Docs/Shopify

Shopify

What you can track on a Shopify store, what Shopify does not let you touch, and how orders get in anyway.

1. The storefront

In your admin: Online Store → Themes → … → Edit code, open layout/theme.liquid and paste the snippet just before </head>.

layout/theme.liquid
<script defer src="https://kipstats.com/tracker.js" data-site="kp_xxxxxxxx"></script>

That covers every page the theme renders: home, collections, products, cart, blog, search. Route changes in themes that navigate without reloading are picked up automatically.

What Shopify does not let you do: checkout runs on Shopify's own pages, and custom scripts are restricted there. So the funnel you can see stops at the cart — the payment itself is reported by a webhook, below. Kipstats is not a Shopify app, and does not need one.

2. The steps you can see

In your theme, on the cart page
<script>
  function kp(n, d) {
    try { if (window.kipstats && window.kipstats.event) window.kipstats.event(n, d || {}) } catch (e) {}
  }
  document.querySelector('[name="checkout"]')?.addEventListener('click', function () {
    kp('checkout_started', {
      price: {{ cart.total_price }},          // Shopify gives cents already
      currency: '{{ cart.currency.iso_code }}',
      items: {{ cart.item_count }}
    })
  })
</script>

Combined with the rage clicks and dead clicks captured automatically, this is usually enough to find where a cart dies — a shipping table nobody can read, a discount field that swallows codes.

3. Orders, through the webhook

In Settings → Notifications → Webhooks, create an Order payment webhook pointing at a small endpoint of yours; that endpoint forwards the order to Kipstats with your ingest key. The key must never sit in the theme, where anyone can read it — that is the whole reason for the extra hop.

A Cloudflare Worker is enough
export default {
  async fetch(request, env) {
    const order = await request.json()

    await fetch('https://kipstats.com/api/collect/server', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${env.KIPSTATS_INGEST_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        name: 'purchase',
        ref: `shopify_${order.id}`,
        occurredAt: order.processed_at,
        data: {
          amount: Math.round(parseFloat(order.total_price) * 100),
          currency: order.currency,
          items: order.line_items?.length ?? 0,
        },
      }),
    })

    return new Response('ok')
  },
}
  • ref is the Shopify order ID: a webhook Shopify retries records the sale once.
  • Amounts are converted to the smallest unit; Shopify sends a decimal string.
  • Verify Shopify's HMAC header in production — the snippet above is deliberately minimal.

4. Check it

  1. Open your shop in a normal browser: the visit appears in Live activity.
  2. Place one real order: a purchase event shows up in Events with the right amount.
  3. Read tracking revenue for currencies, subscriptions and the refund limitation.