Shopify webhook integration (recommended for Shopify)
In your Keepface brand-panel Affiliate tab enable Shopify, copy the webhook URL, paste it into Shopify (Order creation + Refund created), copy Shopify's shared secret back into Keepface. No theme code, no signer to write.
Why webhooks (not JS pixel) on Shopify
Shopify is the one platform where our recommendation is skip the pixel entirely. Reasons:
- Refunds work correctly, Shopify fires a native refund webhook we consume. The JS pixel has no signal for refunds; you’d need to build clawback manually.
- Zero theme edits, you don’t have to touch
theme.liquidor a Shopify app. Everything’s admin-side. - HMAC is free, Shopify’s
X-Shopify-Hmac-Sha256header uses their shared secret; we validate it before crediting. No signer to write in your codebase. - Kill-switch is one click, if you ever want to stop crediting, disable the toggle in Keepface or delete the webhook in Shopify. No dead-app cleanup needed.
The 4-step setup
1. Enable the Shopify channel in Keepface
Company → Brands → Edit brand → Affiliate tab → scroll to “Shopify webhooks” → toggle ON.
Paste your myshopify.com URL in Shopify store URL, we use this to verify that the webhooks arrive from the store you claim to own.
Save. The panel reveals a Webhook URL, copy it. It looks like:
https://api.keepface.ai/api/v2/affiliate/shopify/{brand_id}
{brand_id} is your numeric brand id, baked in automatically.
2. Register the 2 webhooks in Shopify
Shopify admin → Settings → Notifications → Webhooks → Create webhook.
Register two webhooks, both pointing at the same URL from step 1, both set to Format = JSON, and pick the latest stable API version (not unstable, which can break without notice):
| Event | Purpose |
|---|---|
| Order creation | Records the conversion + credits commission |
| Refund created | Claws back commission proportionally |
Shopify prompts you to save. Copy the webhook signing secret it displays, you’ll paste it into Keepface in step 3.
If Shopify already gave you a secret earlier and you didn’t save it, click Rotate on either webhook to mint a fresh one, both share it.
App uninstalledis not in the admin dropdown. That topic is app-scoped (Admin GraphQL API only, for registered Shopify apps). For manual webhook setup like this, two webhooks cover attribution + refunds. If you ever need to kill the integration, disable the toggle in Keepface or delete the webhooks in Shopify, no third webhook needed.
3. Paste the shared secret into Keepface
Back in the brand-panel Affiliate tab → Shopify webhook secret → paste. Save.
Keepface stores it write-only, after save the field shows only a status chip (configured), never the secret itself. Rotating in the future: just paste the new value; the old one is invalidated the instant save completes.
4. Send a test order
- Place a real test order using a Keepface discount code (or click a
kpfc.linkfirst and then order). - Within a minute you should see the conversion on /company/affiliate/analytics.
- Verify button in the panel Shopify block will also flip from
PENDINGtoVERIFIEDonce we’ve seen a valid HMAC-signed post from your store.
If the order doesn’t appear:
- Shopify admin → Settings → Notifications → Webhooks → view the “Recent deliveries” log. A green Successful means Shopify sent it and we accepted it, check your discount code / kpfc.link setup, not the plumbing. A 401 in Shopify’s log means our HMAC verify failed → secret mismatch; re-do step 3.
What we record from each event
Order creation
We extract:
order.name→ our idempotency key. Same order can’t be double-counted.order.total_price→ gross amount (major units, e.g. 149.00).order.currency→ 3-letter ISO code.order.customer.email+order.customer.default_address.country_code→ fraud + geo checks.order.discount_codes[]→ matched against your minted Keepface codes to attribute the sale.order.line_items[].sku→ checked against your Excluded SKUs list.
If the order carries neither a Keepface tracking cookie NOR a Keepface discount code, we drop it silently. Non-affiliate sales don’t produce noise in your affiliate stats.
Refund created
We extract refund.order_id and refund.transactions[].amount, sum the amount, and reverse commission proportionally by default (a 50% refund reverses 50% of the commission).
Want full-refund clawback? Set Refund policy: Full clawback in the brand settings, any refund reverses the entire commission for that order.
Stopping the integration
Two ways, either works:
- In Keepface: toggle the Shopify channel off in the brand-panel Affiliate tab. Any webhooks that still arrive from Shopify return
200 ok=false reason=affiliate_disabledso Shopify stops retrying. - In Shopify: delete the two webhooks under Settings → Notifications → Webhooks. Cleanest if you’re leaving Keepface entirely.
Advanced: auto-apply the discount code from a kpfc.link click (Shopify Scripts)
If you want the code to auto-fill at checkout so buyers don’t have to type it, drop this into Shopify Scripts (Plus only):
if Input.cart.attributes["kf_aff_code"]
code = Input.cart.attributes["kf_aff_code"]
Input.cart.discount_code = code
end
Output.cart = Input.cart
Then in your theme’s layout/theme.liquid, read the kf_aff_code query param and stash it on the cart:
<script>
(function () {
var m = location.search.match(/[?&]kf_aff_code=([^&]+)/);
if (!m) return;
fetch('/cart/update.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ attributes: { kf_aff_code: decodeURIComponent(m[1]) } }),
});
})();
</script>
Keepface’s kpfc.link redirect automatically appends ?kf_aff_code=<the code> when the link is tied to a discount-code campaign, so no config on our side.
Rotating the secret without downtime
- Rotate in Shopify first → note the new secret.
- Paste into Keepface within a few minutes → save.
- Any orders Shopify signs with the new secret between the two steps arrive as 401s; Shopify auto-retries them for 48h. You won’t lose data, but you’ll see one or two red rows in Shopify’s delivery log until Keepface catches up.
Best practice: do the rotation during a low-order window (early morning your local time), and refresh /company/affiliate/analytics to confirm the first post-rotation order appears.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Shopify log shows 401 on every delivery | Shared-secret mismatch | Rotate in Shopify → paste into Keepface |
| Verify button stays PENDING | No successful delivery yet | Place a test order, then click Verify again |
| Refunds not clawing back commission | Only Order webhook registered, not Refund | Register the Refund created webhook (step 2) |
| Duplicate commission on the same order | The old JS pixel is still installed | Remove the pixel snippet from theme.liquid |
| Webhook shows warning “unstable API version” | You picked unstable in the API-version dropdown | Edit the webhook, switch to the latest stable version (e.g. 2024-10) |
Related pages
- Server-side postback with HMAC, for custom stacks + WooCommerce
- 10-minute affiliate setup, the general end-to-end flow
- Discount-code attribution, how kpfc.link + coupon codes tie back to influencers
Frequently asked questions
Do I need to edit my theme?
No. Shopify posts orders + refunds to Keepface via native admin webhooks. The old JS pixel is optional; skip it entirely if you're on Shopify.
What if my store already uses another affiliate app?
You can run both in parallel. Keepface only records conversions where the buyer arrived via a kpfc.link click or applied a Keepface discount code, so double-counting is unlikely. Still, we recommend disabling the other app's refund clawback so refunds aren't debited twice.
Does this work with Shopify Plus?
Yes. Same webhook path. Plus stores can additionally use scripted checkout to auto-apply Keepface discount codes from URL params, see the Shopify Scripts section below.
The webhook shows "Successful" in Shopify but my Keepface dashboard is empty. Why?
Successful in Shopify means Shopify sent it, not that we verified it. Almost always the shared secret is wrong. Rotate it in Shopify and paste the new value into Keepface; the next order will land.
Do I need to register the "App uninstalled" webhook too?
No. That topic isn't exposed in Shopify's admin "Notifications, Webhooks" UI, it's app-scoped only (available via the Admin GraphQL API to registered Shopify apps). For manual admin-webhook setup like this, two webhooks are enough. If you ever want to stop crediting, disable the toggle in Keepface or delete the webhooks in Shopify.