Someone on the marketing team says a creator's sale is "in Shopify but not in the affiliate dashboard", and the ticket lands with you. To answer it properly you need to know what happens between a link click and a commission line, which system decides at each step, and where the chain can legitimately break.
Most explanations of affiliate tracking stop at "the pixel fires". That was roughly true when tracking lived in theme JavaScript and a cookie. It has not been true on Shopify for a while, and after the checkout upgrade on August 26, 2026, theme-injected scripts on the thank-you page are gone for every plan. Attribution now has to be assembled from a sandboxed pixel event, server-side webhooks and the Admin API.
This post lays out that chain in order, explains why the decisions are made server-side, covers idempotency and conflict rules, and ends with a checklist for the ticket you were just handed.
Run your affiliate program on Shopify
Install Reveshare from the Shopify App Store and start turning customers into ambassadors.
Get the app →1. The event chain, in order
Here is the full path from click to payout on a Reveshare-tracked store. Each row names the event, where it is observed, and what is decided at that point.
| Step | Event | Observed by | What is decided |
|---|---|---|---|
| 1 | Shopper clicks the affiliate's Sneakylink | Reveshare redirect | Click recorded against the affiliate; a short-lived discount code is minted for this shopper via Admin GraphQL; shopper is associated with the affiliate for the cookie window |
| 2 | Shopper reaches the storefront | Storefront | Minted code is applied to the cart so the discount shows without typing |
| 3 | checkout_completed | Sandboxed Web Pixel with Protected Customer Data Access scopes | Order id, discount codes and customer identifiers captured in real time and sent server-side |
| 4 | orders/create webhook | Reveshare backend | Order confirmed as real, line items and discount codes read from the source of truth; the order is matched to an affiliate |
| 5 | Commission calculation | Reveshare backend | Program rules applied: rate, current tier, excluded products, self-referral check; commission recorded as pending |
| 6 | orders/updated, refunds/create, fulfilment events | Reveshare backend | Commission adjusted for partial refunds, reversed for full refunds, released once the order clears |
| 7 | Payout run | Reveshare backend and payment provider | Released commission across all programs paid to the affiliate's method; reversals netted against the balance |
Two things stand out. The pixel at step 3 is fast but not authoritative. The webhook at step 4 is authoritative but arrives on Shopify's schedule. Attribution uses the pixel for speed and the webhook for truth, and nothing is paid until the webhook has confirmed the order.
2. Why attribution is decided server-side
There are three reasons the decision cannot live in the storefront any more, and each one on its own would be enough.
Ad blockers and privacy tooling. A meaningful share of shoppers run extensions that block third-party scripts and strip tracking cookies. A theme script that records the click in a first-party cookie and reads it back on the thank-you page silently loses those orders. A webhook from Shopify to your backend cannot be blocked by anything in the shopper's browser.
The Checkout Extensibility sandbox. Checkout and the thank-you page run app code inside isolated frames. A Web Pixel cannot read arbitrary cookies, cannot touch the page DOM, and only receives customer fields its app has been granted through Protected Customer Data Access. This is the correct design, but it means the "read the cookie, fire a request" pattern is not available.
The August 26, 2026 upgrade. Additional Scripts on the order status page were removed for Basic, Shopify and Advanced plans when legacy checkouts were upgraded. Any attribution logic that still lived there stopped running that day. Reveshare was built on Web Pixels, webhooks and Admin GraphQL from the start, so it did not need migrating, but plenty of home-grown tracking did.
3. Code on order beats click
Sometimes the two signals disagree. The shopper clicked creator A's link, which minted a code for them, then typed creator B's static code at checkout. Who gets paid?
The rule in Reveshare is that the discount code on the order wins. It is the only signal that is on the order itself, it is visible in Shopify Admin, and it is explainable to both creators. Click-based attribution fills in the cases where no affiliate code is present, which is exactly the "they clicked and forgot the code" scenario Sneakylinks exist for.
This has an implementation consequence. When the orders/create payload arrives, the handler reads discount_codes first and resolves any affiliate code before consulting click history. Only if the order carries no affiliate code does the cookie-window association apply. Do not do this in the other order, or you will pay creator A for creator B's sale and then spend a week on the dispute.
Talk to our team
Book a short call to see how Reveshare fits your store and ambassador goals.
Book a demo →4. Idempotency, retries and signatures
Shopify delivers webhooks at least once, not exactly once. If your endpoint is slow, returns a non-2xx status, or is briefly down, Shopify retries the same event with the same payload over a period of hours. A handler that is not idempotent will create two commissions for one order.
The safe pattern is to key every write on the Shopify order id and the event type, and make the write a no-op if it has already been applied. A minimal shape looks like this:
{
"topic": "orders/create",
"order_id": 5678901234,
"discount_codes": ["SARAH15"],
"financial_status": "paid",
"processed_at": "2026-09-14T10:22:31Z"
}Before doing anything with that, verify the X-Shopify-Hmac-SHA256 header against the raw request body using your app's secret. A payload that fails verification is dropped, not processed. Then check whether a commission already exists for order_id; if it does, acknowledge with a 200 and return.
Webhook handler rules
- Verify the HMAC on the raw body before parsing anything
- Respond 200 quickly and do the work asynchronously; Shopify times out slow endpoints and retries
- Key writes on order id plus topic so redeliveries are no-ops
- Treat `orders/updated` as a diff, not a fresh order; recompute commission from the current line items
- Handle `refunds/create` separately from cancellation, because partial refunds adjust rather than reverse
- Log the webhook id and processed_at so a support ticket can be traced to a specific delivery
Reveshare runs its own handlers on these rules. If you are building anything alongside it, for example a data warehouse sync, the same rules apply to you.
5. Code lifetime versus cookie window
Two settings govern link-based programs and they are often confused.
Code lifetime is how long the discount code minted at click time stays valid. The default is 24 hours. Its purpose is leak prevention: a code that expires tomorrow is worthless on a coupon site, so there is nothing durable to scrape. Creating and expiring these codes is done through Admin GraphQL against a price rule that belongs to the program.
Cookie window is how long the shopper stays associated with the affiliate after the click. The default is 30 days. Its purpose is fair credit: a shopper who clicks, thinks about it, and buys next week without a code is still the creator's.
The two are independent. A shopper on day 10 has an expired minted code and a live association. If they buy, they will not get the discount automatically, but the order is still attributed through the click. If they want the discount, a fresh click mints a fresh code.
Static-code programs have neither setting. The code is permanent and attribution is purely "was it on the order". That is simpler, and it is also why static codes leak.
6. How Admin GraphQL is used
The storefront never talks to Reveshare's database directly. Everything that changes state in Shopify goes through the Admin GraphQL API with the app's granted scopes, and the operations are narrow.
- Discount codes and price rules. A program's customer discount is backed by a Shopify price rule. Minting a per-click code creates a code under that rule; expiring it deletes or deactivates the code. Campaign codes with start and end dates, usage caps, minimum subtotal and combination rules are created the same way, so Shopify enforces the limits at checkout rather than an app trying to police them afterwards.
- Order reads. When a webhook payload is ambiguous, or a support ticket needs the current state of an order, the backend reads the order by id rather than trusting a cached copy.
- Webhook subscriptions. Registered per shop at install, and re-registered if the app's URL or topics change.
Nothing in this list modifies the theme. That is deliberate. Theme edits break on theme updates, are invisible to the merchant's next developer, and are exactly the surface the checkout sandbox was designed to remove.
7. What you can and cannot see
A brand-side developer asking "show me the raw attribution" needs to know where each piece lives.
In Shopify Admin. The order, its discount codes, its financial and fulfilment status, refunds, and the customer. This is the source of truth for whether an order exists and what was on it.
In Reveshare. The click record, which affiliate it belongs to, the program's window and lifetime settings, the commission calculation with the rate and tier that applied, the pending or paid state, and any reversal. Dashboards show this per affiliate and per program, and exports let you pull it into your own tooling.
Not directly exposed. Internal delivery logs and the raw pixel event stream. If a ticket needs those, the Reveshare team can trace a specific order id through them.
The join between the two systems is always the Shopify order id. Every export carries it, so reconciling the affiliate ledger against Shopify's order list is a straightforward left join, and the unmatched rows are your investigation list.
8. Debugging "the sale is in Shopify but not in the dashboard"
Work top-down. Each step either explains the gap or rules something out.
Confirm the order exists and is paid
Find it in Shopify Admin by order number. Check financial status. A pending, voided or fraud-held order will not carry commission until it is paid. If it was cancelled, that is the answer.
Look at the discount codes on the order
If an affiliate code is present, attribution should be to that affiliate. If it is a different affiliate's code, the code-on-order rule explains it. If there is no affiliate code at all, attribution depends on the click record.
Check the click record and the window
Find the affiliate's clicks in Reveshare around the purchase date. No click from that shopper means no association; a click outside the cookie window means the association had expired. A click on a different device than the purchase will not link.
Check exclusions
Was the buyer the affiliate? Self-referral cleaning on plans that have it will have excluded the order. Was the product outside the program's scope? Was the order later refunded, so the commission was reversed?
Check webhook delivery
In the Shopify app's webhook delivery view, confirm
orders/createfor that order id was delivered and acknowledged. A failed delivery that exhausted retries is rare but real, and the fix is a manual re-sync of the order rather than a code change.Escalate with the order id
If everything above checks out and the order is still missing, send the Shopify order id, the affiliate, and the purchase timestamp. That is enough to trace the delivery end to end.
In practice the ticket is resolved at step two or three most of the time. The order carried someone else's code, or the click was outside the window, or there was no click at all because the shopper came back through search.
Conclusion
Affiliate attribution on Shopify is no longer a script on the thank-you page. It is a chain: a click that mints a short-lived code and starts a 30-day association, a sandboxed pixel that reports the checkout quickly, an orders/create webhook that confirms it authoritatively, a commission calculated against program rules, and refund and fulfilment events that adjust it before a monthly payout. The decisions are made server-side because ad blockers, the checkout sandbox and the August 2026 upgrade all make the browser unreliable. The code on the order beats the click, handlers are idempotent on order id, and the Shopify order id is the key that joins the two systems when something needs tracing.
Have a question about your program?
Payouts, removals, tier setup, migrations. Write to the team and a real person replies, usually the same day.
Email the team →Frequently Asked Questions
Read more
The 2026 Shopify Checkout Revolution: How to Protect Your Tracking, Attribution, and Affiliate Revenue
Discover how Shopify’s mandatory shift to Checkout Extensibility affects your store's conversion tracking and how Reveshare ensures zero data gaps in 2026.
Under the Hood: Scaling E-Commerce ROI via Secure Shopify API Integrations in 2026
A high-level architectural guide for modern brands. Master secure App Proxies, PCDA compliance, and GraphQL to scale your operations without performance bottlenecks.
BFCM 2026 for Affiliate Programs: A Six-Week Countdown From Recruiting to Payout
Black Friday is 27 November 2026 and the affiliate program that performs is the one that was ready in October. Here is a week-by-week plan: recruiting, briefs, scheduled campaign codes, fraud settings, a tracking test, Meta whitelisting, the go-live checklist, and what to do in the week after.