I’m exploring different ways to automate product data workflows with n8n and a PIM.
For example, a setup like:
PIM → n8n → Shopify/WooCommerce/ERP
could handle product updates, approvals, translations, and syncing selected fields. I came across UnoPIM, an open-source PIM that provides REST APIs and webhooks for integrations.
What’s the best way to structure this workflow in n8n so updates stay reliable without creating duplicate products or unnecessary API calls?
Hey @Karan_Gupta Welcome to the n8n community
What prevents duplicates is a mapping you own, not the workflow shape. Keep a Data Table (or any DB table) with one row per product: the PIM SKU, the Shopify/Woo product ID, and a hash of the fields you sync. On each PIM webhook, look the SKU up. No row means create the product and store the ID it returns, a row means update by that ID. Never create based on a title search.
For the unnecessary calls, hash the selected fields with a Crypto node, compare with the stored hash, and skip the item when it matches. That also absorbs webhook retries and approval saves that didn’t touch a synced field.
Webhooks get missed, so add a Schedule Trigger that pulls products updated since the last run from the PIM API and sends them through the same sub-workflow.
Does UnoPIM send the full product in the webhook, or just the ID?
@Karan_Gupta The two things that keep a PIM sync reliable:
Use SKU as the key and always upsert: Keep a mapping table (an n8n Data Table works) of SKU → Shopify/Woo product ID. On each update, look up the SKU. If it’s found, update. If not, create and save the new ID. Never create a product just because a webhook arrived.
Skip unchanged data: Hash only the fields you actually sync (title, price, stock, etc.), store the hash in the same table, and do nothing if it matches the last sync. This cuts out most of the unnecessary API calls.
A couple of extras:
Have the Webhook respond immediately, and use the HTTP Request node’s batching to stay under Shopify’s rate limits.
Run a nightly reconciliation workflow that compares recent PIM changes against the mapping table, to catch any webhooks that got missed.
Hi @Karan_Gupta, for UnoPIM, the v3.1 webhook includes SKUs and a changes object, not the full product. Fetch it with GET /api/v1/rest/products/{sku}, check your approval status, then compare the hash of the fields you’re sending to that store. Save the new hash only after the write succeeds.
One thing to add to the mapping approach above: two executions can both find no mapping and create the same product. Use an atomic claim in PostgreSQL per product/store, shared by webhook and reconciliation runs, so only one run handles that product at a time.
If a create request times out, check the destination before trying another create. The product may already exist even though n8n never saved its ID.
One piece from your list that hasn’t been covered yet is translations. I’d key the mapping table on SKU + locale rather than SKU alone, and hash per locale, so editing a French description only pushes that locale instead of re-updating the whole product and every other language.
Same idea for approvals: only let an item through when its approval status in the PIM is approved for that locale, and save the new hash only after the destination write succeeds.
It also helps to keep the field mapping (PIM attribute → Shopify/Woo field) in one place, like a single Set node or a small config table, so adding a new synced attribute later doesn’t mean editing the flow in several places.
I’d test one case before expanding the sync: Shopify accepts a product update, but the ERP request times out.
With one ‘last synced’ hash for the whole product, you can either mark everything done too early or resend the Shopify update unnecessarily. In n8n, I’d pass the approved product to separate destination sub-workflows, each recording its own confirmed result. Keep a timed-out operation unconfirmed. Reconcile it, or retry only when that API makes the retry safe; mark it confirmed only after verifying success.
Keep those checkpoints separate from product identity. A translated description can have its own sync status without creating another product. The test should leave Shopify confirmed and the ERP unresolved, then recover the ERP operation without resending the confirmed Shopify update.
I’d also decide field ownership first. If the ERP owns stock or pricing, the PIM workflow shouldn’t overwrite those fields. It might only publish descriptions, images and translations.
Would the PIM own prices and stock in your setup too? That determines which fields this workflow should be allowed to write.
Keep product identity separate from delivery status: one destination can succeed while another times out. Test that case before expanding the flow. Which fields would UnoPIM own, and which would the ERP own?
I developed VinumBridge, a Windows middleware with REST-to-REST profiles, a WooCommerce connector, mapping and run history. Those interfaces need validation; approval and translation logic would remain in your PIM: https://vinumbridge.com/
I’m now offering 30% discount for the first year while launching this.