Custom Shopify apps and integrations
Most integration projects fail on the second-order problems rather than the API calls. Rate limits under load, webhooks that arrive twice or out of order, a sync that half-completes and leaves two systems each convinced they are right. Getting data from A to B is the easy day. Keeping it correct through a bad one is the job.
Safe to retry, always
Webhooks are delivered at least once, not exactly once. Every handler is written so a duplicate delivery is a no-op rather than a second order, a doubled stock movement or a repeated charge.
Degrades instead of failing
Shopify's GraphQL API meters by query cost. Work is queued against the leaky bucket with backoff, so a catalogue sync slows down under pressure rather than falling over.
Failures you find out about
Structured logs, a dead-letter path for what could not be processed, and alerting on the queue. The failure mode to design out is the silent one.
The integrations that come up most
ERP synchronisation: NetSuite, Business Central, SAP and the long tail of industry-specific systems. Products, inventory, pricing, orders and fulfilments, each with its own direction of travel and its own answer to which system wins a conflict. That last question decides the architecture, so it gets settled before any code is written.
PIM and catalogue feeds, where the hard part is rarely the transfer and almost always the mapping: variant structures that do not correspond, option values that exist in one system and not the other, and images arriving on a different schedule from the products they belong to.
Subscription, loyalty, warehouse and 3PL systems, which usually need order events pushed out and fulfilment state pulled back, reliably, with reconciliation for the times it did not work.
Admin UI extensions, so the people using Shopify every day see the integrated data in the admin instead of switching to another tab to check it.
Bulk operations, and when not to loop
Anything touching the whole catalogue goes through the Bulk Operations API rather than a paginated loop. Bulk queries run asynchronously and hand back a JSONL file; bulk mutations take one in. For a catalogue of any size this is the difference between a job that completes and a job that spends its life being rate-limited.
Small, targeted updates go the normal route. The failure I see most often is the reverse of both: a well-meant loop over 40,000 products, retried on failure, taking a whole day and half the API budget with it.
Custom app or public app
A custom app is installed on one store, needs no review, and can hold credentials specific to that merchant. It is the right answer for almost every integration built for a single business.
A public app goes through Shopify's review, supports many stores, and carries real obligations: billing, GDPR webhooks, uninstall handling, support. Worth it if you are building a product; expensive overhead if you are integrating one store's ERP.
If the goal is a product rather than an integration, that is a different engagement with a different shape, and I will say so rather than quietly building the wrong one.
Is this the right engagement?
A good fit
- Shopify or Plus stores syncing with an ERP, PIM, WMS or 3PL
- Businesses whose stock or pricing accuracy is a real operational cost
- Teams who have outgrown a connector app and hit its limits
- Merchants needing custom data surfaced inside the Shopify admin
Not a fit
- A one-off CSV import, which the admin already does
- Integrations a well-supported existing app handles properly
- Building a public app for the App Store: different scope, ask separately
Common questions
Where does the app run?
Your infrastructure or a host you control: the app is yours at the end of the engagement, source and all. I will recommend a stack that matches what your team can maintain rather than what I most enjoy writing.
How is a conflict between Shopify and the ERP resolved?
By deciding, in writing, which system owns each field before any code exists. Usually the ERP owns inventory and cost, Shopify owns content and customer-facing copy, but that is a default to be confirmed, not assumed.
What happens when the sync breaks at 3am?
It retries with backoff; what still cannot be processed goes to a dead-letter queue and raises an alert, and the reconciliation job reports the drift. You find out from your monitoring, not from a customer.
Start with the diagnosis
Send me your store and I will record a 20-minute walkthrough of what I would change and why. No call required, and nothing to unsubscribe from afterwards.