Keepface
Sign up

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.liquid or a Shopify app. Everything’s admin-side.
  • HMAC is free, Shopify’s X-Shopify-Hmac-Sha256 header 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):

EventPurpose
Order creationRecords the conversion + credits commission
Refund createdClaws 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 uninstalled is 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.link first 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 PENDING to VERIFIED once 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_disabled so Shopify stops retrying.
  • In Shopify: delete the two webhooks under Settings → Notifications → Webhooks. Cleanest if you’re leaving Keepface entirely.

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

SymptomLikely causeFix
Shopify log shows 401 on every deliveryShared-secret mismatchRotate in Shopify → paste into Keepface
Verify button stays PENDINGNo successful delivery yetPlace a test order, then click Verify again
Refunds not clawing back commissionOnly Order webhook registered, not RefundRegister the Refund created webhook (step 2)
Duplicate commission on the same orderThe old JS pixel is still installedRemove the pixel snippet from theme.liquid
Webhook shows warning “unstable API version”You picked unstable in the API-version dropdownEdit the webhook, switch to the latest stable version (e.g. 2024-10)

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.

Was this article helpful?