Case Study

The Connected Storefront: Shopify and Salesforce in sync, both ways

A real-time, two-way integration between a Shopify store and Salesforce. Orders flow into the CRM the moment they are placed, loyalty changes flow back out to the store, and a reconciliation job catches anything that slips through. Built for reliability, with every event logged on both sides.

Client
Coastline Apparel (demonstration build)
Industry
Retail & e-commerce
Services
Integration architecture, Apex & Platform Events, Change Data Capture & Pub/Sub, Off-platform middleware (Node/TypeScript)

Coastline Apparel is a fictional retail brand. We built this engagement against a real Shopify store and a real Salesforce org to show the integration side of our work: two systems kept in sync in real time, built so a dropped message never means a lost order. Only the brand is invented.

The brief was the one every growing store hits. Sales happen in Shopify. The customer relationship lives in Salesforce. Keeping the two in step by hand does not scale, and a nightly export is too slow and too brittle to trust.

The challenge

A storefront and a CRM disagree the moment they stop talking. An order placed at checkout needs to be a record in Salesforce within seconds, not the next morning. A loyalty tier the team sets in the CRM needs to show up on the customer in Shopify without anyone re-keying it.

The hard part is not the happy path. It is what happens when a webhook is delivered twice, or arrives out of order, or the network drops mid-send. Get that wrong and you get duplicate orders, stale data, and a team that stops believing the numbers. So the real requirement was reliability: every event accounted for, nothing silently lost, and a way to see exactly what crossed between the systems.

The approach

We treated the seam between the two systems as the thing to design first, before any code. We wrote a contract: which system owns which data, what each message looks like, and how every failure is handled. Salesforce owns the customer relationship. Shopify owns the order. Each direction has one clear job.

Inbound, an order placed in Shopify is sent to Salesforce as a signed webhook. We verify that signature before trusting a single byte, so only genuine Shopify traffic is ever processed. The order becomes an opportunity with its line items, and the write is idempotent: if the same order arrives twice, it updates in place instead of creating a duplicate.

Outbound, a change to a customer in Salesforce is picked up through Change Data Capture and streamed out over the Pub/Sub API. A piece of middleware maps it to the Shopify customer and pushes it. The loyalty tier a rep sets in the CRM lands on the customer in Shopify on its own.

The middleware itself runs off-platform, in Node and TypeScript. Some integration work does not belong inside Salesforce, and forcing it there just to keep everything in one place is a mistake. Keeping it outside let us build it properly, with its own tests and its own failure handling, and keep the Salesforce org clean.

What we built

A verified inbound path. Shopify orders arrive as signed webhooks, get checked, and become opportunities with their line items. The order total always matches the sum of its lines, because that invariant is enforced on every write.

A paid Shopify order #1002 for $48.00 with a Coastline Linen Shirt line item, placed by customer Avery Coast
A real paid order in Shopify: #1002, a Coastline Linen Shirt for $48.00.
A Salesforce opportunity named Coastline Order #1002 for $48.00, reconciled from the Shopify order
The same order in Salesforce: opportunity Coastline Order #1002 at $48.00. The total always equals the sum of its line items, and the same order arriving twice updates in place instead of duplicating.

A real-time outbound path. CRM changes flow out through Change Data Capture and the Pub/Sub API to the store, so the loyalty tier set in Salesforce shows up on the Shopify customer without a manual step.

A Salesforce account list view showing each account's loyalty tier and the Shopify customer id it links to
Salesforce owns the loyalty tier. Each linked account carries its tier and the Shopify customer it maps to.
A Shopify customer record showing a loyalty:Gold tag and a timeline entry that the Coastline middleware created the customer
The same tier in Shopify, written by the integration as a loyalty tag (loyalty:Gold). The timeline shows the middleware created and maintains the customer.

A reconciliation backstop. Real integrations drop messages eventually. A job runs every few hours, pulls recent orders straight from Shopify, and re-ingests anything Salesforce missed. Each order is handled in its own savepoint, so one bad record can never poison the rest of the batch.

A single source of truth for what happened. Every event in either direction writes an Integration Log record: direction, status, latency, and a reference back to the record it touched. No personal data is ever logged. When failures cross a threshold, the team gets an alert instead of finding out from a customer.

The Integration Log list in Salesforce: inbound order webhooks, an outbound customer sync, a failure, and a reconciliation pass, each with direction, status, and latency
The integration log: every event, both directions, with status and latency. Inbound order webhooks, an outbound customer sync, a deliberate failure, and the reconciliation pass, all in one place.
The Integration Health dashboard in Salesforce: charts of integration events by status (success, failure, retry), by direction (inbound and outbound), and by type, plus processing latency
The health dashboard, built on the integration log: events by status (success, failure, retry), by direction (inbound vs outbound), and by type. One place to answer "did this go through?"

How it runs

A customer checks out on the store. Within seconds the order is a verified opportunity in Salesforce, line items and all. Nobody re-keys anything.

A rep updates a customer’s loyalty tier in the CRM. The change flows out to Shopify on its own, so the storefront reflects it without a second system to update.

Every few hours, the reconciliation job sweeps recent orders and fills any gap before it matters. And the whole time, both directions are writing to the integration log, so there is always one place to answer the question “did this go through?”

The result

A storefront and a CRM that stay in sync in real time, built so the failure cases are handled rather than hoped against. Orders are verified and idempotent. Loyalty syncs itself back. A reconciliation job catches the rest, and every event is visible on both sides.

To prove it, we ran a signed order end to end and watched it become the right opportunity in Salesforce, then changed a customer in the CRM and watched the loyalty tag appear in Shopify. We seeded the log with traffic in both directions, including deliberate failures, so the dashboard and the alerting run on real movement.

This is the integration work we bring when two systems have to behave like one: a designed contract, real-time sync both ways, and the reliability engineering that keeps it honest under load. If your storefront and your CRM are drifting apart, let’s talk.

← Back to all work