Integrating Shopify inventory with custom sales channels like Temu, Allegro, or Onbuy is best handled directly in the admin dashboard. Here is how we decoupled our core marketplace synchronization engine.
By Rehan Idrisi · · Updated · 5 min read
Part of: Shopify
Merchants prefer to run their business from a single dashboard. Forcing them to log in to external platforms to configure inventory mapping, product listings or shipping tracking is a major UX friction point.
To solve that for our clients, we extracted the key synchronization processes out of our core synchronization engine and built modular, embedded Shopify apps for Onbuy, Temu and Allegro using Shopify's Remix framework. Here is how the integration is architected.
Mapping is the foundation of multi-channel synchronization. We built an intuitive SKU mapper directly inside the Shopify admin panel, using Polaris components.
Once a merchant maps a Shopify SKU to its marketplace counterpart, the app saves that pair to our central database, and bidirectional updates start flowing automatically.
A customer buys on Temu, Onbuy or Allegro. Our webhook receiver intercepts the transaction and creates a corresponding order in the merchant's Shopify admin automatically.
The merchant fulfils that order and generates shipping labels through their existing Shopify app flow, and our background queue immediately relays the tracking details back to the source marketplace.
Remix loaders and actions let us fetch mapped products in the backend and render them instantly on the frontend, inside the Shopify iframe. Merchants never feel like they left Shopify.
import { json } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
export const loader = async ({ request }) => {
const { admin } = await authenticate.admin(request);
// Fetch mapped products from internal sync database
const mappings = await db.getMappings(admin.shop);
return json({ mappings });
};
export default function Dashboard() {
const { mappings } = useLoaderData();
return (
<Page title="Marketplace Mapping">
<Layout>
<Card sectioned>
<p>You have {mappings.length} active product mappings.</p>
</Card>
</Layout>
</Page>
);
}Shopify's API limits work on a leaky bucket algorithm. Push millions of SKU updates at once during a peak sale and you trigger HTTP 429 rate limit exceptions, which blocks sync entirely.
Every update is queued in BullMQ instead. The queue processors calculate the remaining API budget from Shopify's headers and wait before firing new requests, which keeps transfers smooth and uninterrupted.
Every webhook Shopify sends includes an X-Shopify-Hmac-SHA256 header, a signature computed from the request body and the app's shared secret. We recompute that signature ourselves before touching the payload, and reject anything that doesn't match. Skip this step and the order-creation endpoint is a public URL that will accept and act on whatever gets POSTed to it. It is a small piece of middleware. It sits in front of every webhook route, not just the marketplace-order one.
Shopify expects a webhook endpoint to respond quickly, and will retry delivery if it doesn't hear back in time or gets a non-2xx response. The same webhook can therefore arrive more than once for the same event. We key incoming order webhooks by Shopify's own order ID and check for an existing sync record before creating anything, so a retried delivery updates the existing record instead of creating a duplicate order on the marketplace side. Acknowledging the webhook immediately and doing the actual work in the BullMQ queue afterwards keeps the response fast enough that retries stay rare in the first place.
Many merchants install the app independently, so nothing about the data model can assume there is only one shop. Every mapping, queue job and webhook handler carries the shop's domain as a first-class key, and offline access tokens are stored per shop instead of in a single shared credential. A bug that leaks one merchant's product mappings into another's dashboard is obvious in hindsight and very easy to introduce by accident. Shop scoping has to be enforced at the data layer from the start. Bolting it on later never covers everything.
Waiting for a real order on Temu, Onbuy or Allegro isn't a workflow for testing a code change. We replay captured webhook payloads, anonymised and taken from real historical events, against a local instance to exercise the order-creation and inventory-update paths. Outbound calls go to each marketplace's sandbox or test-store mode, so a bad deploy can't create a real listing or charge a real customer. The Remix loader and action logic is plain server-side code, and tests the same way as any other backend function, independent of the Shopify iframe it eventually renders inside.
Rate limiting is the routine case. An outright outage on the marketplace side is the one that needs a different response. BullMQ's retry-with-backoff handles transient failures automatically, but a sustained outage just means the queue backs up while retries keep failing. We surface sync status per product and per channel directly in the merchant's Shopify admin, so a merchant sees a pending-sync state instead of a silent failure, and we cap the retry backoff so a recovered marketplace drains the backlog in a bounded window instead of retrying at an ever-lengthening interval.
Embed the synchronization features directly into the tools your merchants already use everyday. Good integrations should be invisible.
Queue every API update through Redis and BullMQ instead of firing calls directly, and calculate the remaining request budget from Shopify's rate-limit response headers before each batch. Paired with a webhook receiver for inbound marketplace orders, that keeps bidirectional sync inside Shopify's leaky-bucket limits even during peak sales.
Turn a CSV or TSV table into JSON records, or flatten JSON back into a spreadsheet-ready table.
Check a product CSV for missing columns, broken variant handles, duplicate SKUs, invalid barcodes and bad prices before you import it.
Generate consistent SKU codes in bulk from a custom pattern, with variant permutations, sequential numbering and collision checking. Free, no sign-up.
Convert product codes between GTIN-8, GTIN-12 (UPC-A), GTIN-13 (EAN-13) and GTIN-14, validate check digits, and normalise a whole catalog in bulk.