If you run an e-commerce shop with 2 to 20 staff, you have to decide this week whether your onsite popups write email and SMS consent directly to your email service provider, directly to Shopify, or to both simultaneously.
Most teams toggle every sync button in the Privy dashboard, verify that a test email lands in a list, and move on. That is a mistake.
When you capture an email address through an onsite modal, you are not merely collecting a string of characters. You are asserting a legal state transition across at least 3 distinct databases: Privy’s campaign store, Shopify’s core customer table, and your downstream marketing platform (such as Klaviyo, Omnisend, or Mailchimp).
If those platforms disagree on whether a user gave affirmative consent, you will eventually send marketing mail to someone who opted out at checkout, or suppress someone who specifically asked for a discount code. We have audited migrations where this exact mismatch silently corrupted 4 to 7 percent of a merchant’s active subscriber base within weeks.
What does the Three Disconnected Consent Records in Your Stack actually mean?
Every store in your size bracket operates with distributed customer records. You do not have one system of record for marketing permissions; you have three separate platforms running three distinct state machines, connected by asynchronous webhooks and batch polling.
[ Visitor Browser ]
│
▼
[ Privy Form ] ──(Sync)──► [ Shopify Customer API ]
│ ▲
│ │ (Sync/Reconciliation)
└────────(Direct Sync)────────►▼
[ Marketing ESP ]
The browser payload versus the server record
When a shopper fills out a Privy modal offering a 10% welcome discount, Privy creates a contact record inside its own infrastructure. Privy then dispatches API calls outward based on your integration settings.
Shopify exposes customer consent through its Shopify Customer Privacy API and Admin REST/GraphQL endpoints. In Shopify, a customer record carries distinct objects for email_marketing_consent and sms_marketing_consent. These are not simple binary flags. They track states like subscribed, unsubscribed, not_subscribed, and pending, alongside a timestamp and an assessment of consent collection method.
Your email platform maintains its own suppression tables, bounce logs, and list membership states. When Privy attempts to update both platforms simultaneously, it does so without distributed transaction guarantees. There is no two-phase commit. If the HTTP call to your email provider succeeds in 300 to 800 milliseconds, but the call to Shopify fails due to API rate limits (typically 2 to 4 requests per second on standard REST buckets), your stack is immediately out of sync.
API write behaviors and silent overwrites
Different endpoints handle existing records with conflicting rules. If an email address already exists in Shopify as an unsubscribed customer—perhaps they bought something six months ago and explicitly unchecked the marketing box at checkout—a raw Privy integration will frequently push an update that flips that customer back to subscribed.
The table below outlines how common sync configurations handle incoming lead data against existing records:
| Integration Topology | Update Latency | Handling of Prior Checkout Unsubscribe | Double Opt-In Handling |
|---|---|---|---|
| Privy to Shopify Only (ESP reads Shopify) | 2 to 5 minutes | Overwrites Shopify state to subscribed unless explicitly restricted | Inherits Shopify global double opt-in rules |
| Privy to ESP Only (ESP syncs to Shopify) | Sub-second to ESP; minutes to Shopify | ESP marks subscribed; downstream Shopify sync often drops consent timestamp | Bypasses Shopify opt-in; ESP triggers confirmation |
| Privy Dual-Sync (Direct to both simultaneously) | Variable (race hazard) | Non-deterministic; the slower API response wins the final state | Causes duplicate or conflicting confirmation emails |
If your system design allows a generic popup submission to silently override a legal checkout opt-out without collecting a fresh, audited opt-in event, you are violating basic compliance principles.
“Merchants are responsible for ensuring that they have obtained the necessary consent from their customers before sending marketing communications.” — Shopify Customer Privacy API Documentation
Where the State Machine Breaks Under Real Traffic
The edge cases do not show up during basic staging tests with your own corporate email address. They appear under the strain of high-volume catalog traffic, multi-tab browsing sessions, and repeat customers.
Double opt-in collisions and the pending state
If you enable double opt-in inside Shopify, any customer created with a marketing consent state will not receive marketing broadcasts until they click an email verification link. Shopify stores their state as pending.
If Privy simultaneously writes that same lead directly to your email provider, the email provider often defaults to marking the profile as fully subscribed. Your marketing automation system immediately fires the welcome flow, delivering the coupon code within 90 seconds.
Forty-eight hours later, the shopper has never clicked the verification link sent by Shopify because they already received the discount code from your ESP. Shopify now permanently marks that user as not_subscribed or leaves them in pending.
During the next store-wide broadcast, if you segment based on Shopify’s customer database, that user is excluded. If you segment based on your ESP’s native lists, they are included. Your reporting metrics diverge immediately.
Checkout unsubscriptions and webhook race conditions
Consider this sequence, which we see regularly on stores doing between 50 and 500 orders a day:
- A customer browses your catalog, enters their email into a Privy popup to get a discount, and is synced to the marketing platform.
- The customer adds items to their cart, proceeds to Shopify checkout, and deliberately unchecks the “Keep me updated on news and exclusive offers” checkbox.
- The checkout completes. Shopify fires an
orders/createorcustomers/updatewebhook to your marketing platform, instructing it to mark the user as opted-out. - Meanwhile, a delayed retry of Privy’s original form submission sync lands at the marketing platform 15 to 30 percent slower due to network queuing, re-flagging the profile as active.
Your customer explicitly asked not to be emailed while handing you payment details, yet your marketing software re-subscribed them seconds later based on a cached popup session.
The format of email headers and message exchange semantics defined in RFC 5322 assumes clear message routing, but software stacks like this break the higher-level operational contract between the user and the sender before an email even leaves your outbound mail server.
What Breaks in Month Two After Migration
During the first 30 days after installing Privy alongside an existing Shopify and ESP stack, everything appears functional. The subscriber counter climbs, conversion tracking credits sales to the welcome series, and no critical alerts fire.
The failure modes emerge around day 45 to 60.
The first issue is suppression list drift. By month two, customers who hit “Unsubscribe” in the footer of your marketing campaigns are marked as suppressed in your ESP.
However, many basic integrations do not pass unsubscribes back upstream to Privy or Shopify. If that same customer returns to your store weeks later to track a package, an exit-intent popup may trigger. If the customer enters their email address again—perhaps thinking it is required to look up an order—Privy processes it as a fresh opt-in.
Privy sends a sync event to your ESP. Depending on how your ESP handles re-subscriptions, it will either silently reject the contact, or worse, unsuppress the user without their conscious consent. If unsuppressed, they receive promotional emails they opted out of a month prior, leading directly to spam complaints.
The second issue is attribution reconciliation. In month two, your finance or marketing lead will compare Privy’s reported revenue against Shopify’s analytics and your ESP’s dashboard.
Because consent states diverged in month one, the platforms are now tracking different cohorts. Customers who are subscribed in your ESP but unsubscribed in Shopify will generate revenue that Shopify classifies as direct or organic, while your ESP claims it as attributed email revenue.
You end up paying software bills for multiple systems that cannot agree on how many marketable contacts you actually own.
Engineering a Reliable Synchronization Path
To eliminate the consent gap, you must establish a strict hierarchy among your systems. Two platforms cannot share equal authority over a customer’s marketing permission.
[ Privy Form ]
│
▼ (Payload with Source Metadata)
[ Shopify Admin API ] ──(Single Source of Truth)──► [ Webhook Pipeline ]
│
▼
[ Marketing ESP ]
Establish Shopify as the single source of truth
Do not permit Privy to sync directly to your email service provider if that provider also maintains a bidirectional sync with Shopify. Dual writes create unresolvable race conditions.
Configure Privy to write exclusively to Shopify’s Customer API. Let Shopify evaluate the state transition, apply your store’s canonical double opt-in settings, and record the consent_updated_at timestamp.
Configure your marketing platform to ingest customer data solely from Shopify’s downstream webhooks (customers/create and customers/update). This adds roughly 2 to 5 seconds of latency between a popup submission and the arrival of the welcome email, but it guarantees that your email platform never holds a consent record that Shopify contradicts.
Why does implement a weekly state reconciliation audit break first?
If you cannot avoid dual writes due to tooling limitations, you must run a script or export audit every 30 days.
Extract all customer records updated in the last 30 days from Shopify where email_marketing_consent.state is not equal to subscribed. Extract the active subscriber list from your ESP for the same timeframe.
Perform a simple diff on the email fields. Our experience suggests that in a stack with 10,000 active contacts, you will routinely find between 50 and 200 addresses that your ESP considers marketable while Shopify considers them opted-out. Force the status of those mismatched records to unsubscribed in your ESP.
We would route all Privy popups exclusively through Shopify’s Customer API, accept the slight delivery delay on the initial coupon code, and strictly disable any direct sync from Privy to our downstream email platform.
Terms used on this page
A connector is a service that moves records between two systems on a schedule or on an event. A webhook is an HTTP callback that a system sends when something changes, rather than waiting to be polled. An item fulfilment is the record that says a physical shipment left the warehouse, and it is a different object from the sales order it belongs to.
- Sales order — the record of what a customer bought
- Item fulfilment — the record of what actually shipped
- Inventory level — available quantity at a specific location
- Location — a warehouse, a store, or a virtual bucket
- Matrix item — a product with variants inherited from an option schema
- Upsert — create if absent, update if present
- Idempotency key — a value that stops a retry from creating a duplicate
- Reconciliation — the manual or scripted comparison of two ledgers
- Backfill — replaying historical records into a new system
- Cutover — the moment the new system becomes authoritative
- Drift — the state where two systems disagree without either raising an error
- Circuit breaker — a mechanism that stops retrying a failing integration