Skip to main content

Tutorial: Building an Integration Flow Between Akeneo PIM and Shopify using Flowlyze

1. Introduction

This tutorial covers how to automate the transfer of product data from Akeneo PIM to Shopify using the Flowlyze integration platform. By connecting these systems, we eliminate manual data entry, ensuring that your storefront always displays accurate, correctly formatted product information.

Video tutorial

💡 Tip: Watch the video below to see the flow step by step.

2. Prerequisites

  • An active Akeneo PIM account with API access (Client ID, Secret, Username, Password).
  • A Shopify store with an Admin API Access Token.
  • An active Flowlyze account.
  • Basic familiarity with JSON structures and foundational C# syntax for data formatting actions.

3. Integration Architecture

The data flow follows a linear pipeline architecture:

  • Trigger: Flowlyze connects to Akeneo and retrieves raw product data.
  • Transformation: The Mapping Action aligns Akeneo attributes to Shopify's schema. Following this, the Data Formatting Action uses lightweight C# scripts to clean and structure the data.
  • Shopify destination: The processed payload is sent through the native Shopify adapter. For the product master-data payload, see the Shopify product documentation.

4. Step-by-Step Implementation

Step 4.1: Configuring the Trigger in Akeneo

First, establish a secure connection to your data source:

  1. In the Flowlyze workspace, add a new Source node and select Akeneo.
  2. Complete the authentication process by inputting your Akeneo API credentials (Client ID, Secret, Username, and Password).
  3. Configure the trigger event to fetch product catalogs on a defined schedule or via manual execution.

Step 4.2: Data Transformation and Mapping (Flowlyze)

This is where the core logic resides:

  1. Mapping Action: Add a Mapping node. Connect incoming Akeneo fields to their destination counterparts. For example, map Akeneo's identifier to Shopify's SKU.
  2. Data Formatting Action: Add a Formatting node immediately after the mapping node. Utilize Flowlyze's environment to write short C# formatting scripts. For instance, you can parse text to ensure titles are correctly formatted or strip unwanted currency symbols from numeric price fields before they reach Shopify.
using System;
using System.Collections.Generic;

var finalOutput = new Dictionary<string, object>();
// ==========================================
// --- 1. SKU & VARIANTS FORMATTING ---
// ==========================================
var skuValue = Data.GetString("sku");
string formattedSku = string.IsNullOrEmpty(skuValue) ? string.Empty : skuValue.Replace(" ", "-").ToUpperInvariant();

// MISSING PART TO ADD
finalOutput["sku"] = formattedSku;
finalOutput["options"] = new List<string> { "Title" };

finalOutput["variants"] = new List<Dictionary<string, object>>
{
new Dictionary<string, object>
{
{ "sku", formattedSku },
{
"optionValues", new Dictionary<string, string>
{
{ "Title", "Default Title" }
}
}
}
};

// ==========================================
// --- 2. CATEGORY MATCHING ---
// ==========================================
var categoryValue = Data.GetString("category");

if (!string.IsNullOrEmpty(categoryValue))
{
var categoryMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "drones", "gid://shopify/TaxonomyCategory/tg-5-12-2" },
{ "industrial_tools", "gid://shopify/TaxonomyCategory/ha-14-9" },
{ "three_d_printers", "gid://shopify/TaxonomyCategory/el-13-2" },
{ "robotics", "gid://shopify/TaxonomyCategory/el" },
{ "sensors", "gid://shopify/TaxonomyCategory/el-5-7" }
};

if (categoryMap.TryGetValue(categoryValue, out string shopifyGid))
{
finalOutput["category"] = shopifyGid;
}
else
{
finalOutput["category"] = categoryValue;
}
}

finalOutput["title"] = Data.GetString("title");
finalOutput["description"] = Data.GetString("description");
finalOutput["vendor"] = Data.GetString("vendor");
finalOutput["status"] = Data.GetString("status");

// ==========================================
// --- 3. FETCHING MEDIA FROM AKENEO (WITH A SINGLE TOKEN) ---
// ==========================================
var shopifyMediaList = new List<Dictionary<string, string>>();
var assetCodesRaw = Data.GetListString("akeneo_asset_codes");

if (!string.IsNullOrEmpty(skuValue) && assetCodesRaw != null && assetCodesRaw.Count > 0)
{
string akeneoDomain = "{{Your_akeneoDomain}}";
string validToken = "";

string clientId = "{{Your_clientId}}";
string clientSecret = "{{Your_clientSecret}}";
string myUsername = "{{Your_username}}";
string myPassword = "{{Your_password}}";

// For performance, the token is requested only once
var tokenRequest = new CustomHttpRequest
{
Url = $"{akeneoDomain}/api/oauth/v1/token",
Method = "POST",
Post = new Dictionary<string, string>
{
{ "grant_type", "password" },
{ "username", myUsername },
{ "password", myPassword },
{ "client_id", clientId },
{ "client_secret", clientSecret }
}
};

try
{
var tokenResponse = Http.ExecuteRest(tokenRequest);
validToken = tokenResponse.GetString("access_token");
}
catch (Exception ex)
{
Logger.Log("Token error: " + ex.Message);
}

if (!string.IsNullOrEmpty(validToken))
{
string assetFamily = "imported_assets";
int index = 1;

foreach (var assetCode in assetCodesRaw)
{
if (string.IsNullOrWhiteSpace(assetCode)) continue;

var assetInfoRequest = new CustomHttpRequest
{
Url = $"{akeneoDomain}/api/rest/v1/asset-families/{assetFamily}/assets/{assetCode}",
Method = "GET",
Headers = new Dictionary<string, string>
{
{ "Authorization", $"Bearer {validToken}" },
{ "Accept", "application/json" }
}
};

try
{
var assetResponse = Http.ExecuteRest(assetInfoRequest);
string publicUrl = assetResponse.GetString("values.media_link[0].data");

if (!string.IsNullOrEmpty(publicUrl))
{
shopifyMediaList.Add(new Dictionary<string, string>
{
{ "url", publicUrl },
{ "alternativeText", $"{formattedSku} image {index}" }
});
}
}
catch (Exception ex)
{
Logger.Log("Exception while fetching the asset ({0}): {1}", assetCode, ex.Message);
}
index++;
}
}
}

if (shopifyMediaList.Count > 0)
{
finalOutput["media"] = shopifyMediaList;
}

return finalOutput;

Step 4.3: Configuring the Action in Shopify

Now, route the prepared data to your storefront:

  1. Add a Destination node at the end of the pipeline and select Shopify.
  2. Authenticate the connection using your Shopify Admin API Access Token.
  3. Set the Operation to Product sync. Check the Active product and Publish product boxes to ensure the product is marked as active and appears on storefront channels, then map the finalized payload.

5. Testing and Deployment

To verify your pipeline works as expected:

  1. Run a test execution in Flowlyze for a single product payload from Akeneo.
  2. Check the Flowlyze Execution History logs to ensure both the Mapping and Formatting actions processed the data successfully.
  3. Once the logs show a successful execution, enable the flow for automated syncing.
  4. After the flow is active, log into your Shopify Admin panel and verify that the products appear with the correct SKU and precise pricing.

6. Error Handling and Troubleshooting

  • Authentication Errors: Double-check your API Access Tokens. Tokens might expire or lack the specific read/write permissions needed.
  • Mapping Failures: If a required Shopify field is missing in the Akeneo payload, the API will reject the request. Ensure fallback values are assigned in your C# formatting step.
  • Type Mismatches: Ensure price fields are sent as numbers or correctly formatted strings as required by Shopify. Use your C# action to convert data types if necessary.

7. Conclusion and Next Steps

You have successfully built an automated, end-to-end integration between Akeneo and Shopify. As a next step, consider expanding your C# formatting logic to handle product variants efficiently.