Shopify
Web Pixel extension plus an order webhook.
Shopify does not allow arbitrary scripts on checkout, so a storefront script tag cannot see the step that matters most. This integration has two halves that cover the gap between them.
1. Web Pixel extension
Runs in Shopify's sandboxed worker and receives the curated analytics stream,
including checkout_completed.
shopify app generate extension --template web_pixelPoint the generated extension at src/pixel.ts from
the package, then set its settings:
| Setting | Value |
|---|---|
apiKey | Your site key (sig_live_…) |
host | https://api.pixelfox.app |
mode | online or offline |
collectorUrl | Required for offline - see below |
2. Order webhook
The authoritative record. It fires for phone orders, draft orders and delayed captures that no browser event ever sees, and survives a shopper closing the tab at checkout.
import { handleShopifyWebhook } from "@pixelfox/shopify";
export async function POST(req: Request) {
// Raw body - re-serialising the parsed JSON breaks the HMAC.
const rawBody = await req.text();
const { status, body } = await handleShopifyWebhook(
{
shopifySecret: process.env.SHOPIFY_API_SECRET!,
apiKey: process.env.SIGNALS_API_KEY!,
host: process.env.SIGNALS_HOST!,
mode: "online",
},
{ rawBody, headers: Object.fromEntries(req.headers) },
);
return Response.json(body, { status });
}Subscribe to orders/paid in your app config.
The event id is derived from the Shopify order id, so a retried delivery cannot count one sale twice.
Offline mode on Shopify
Offline means "send to an endpoint you control, not to PixelFox". Unlike WordPress, Shopify gives you no server the pixel can write to - the storefront runs on Shopify's infrastructure and the pixel is a sandboxed worker whose only outlet is an HTTP request.
So offline requires a collectorUrl pointing at your own endpoint. Without
one the pixel refuses to send rather than quietly falling back to PixelFox,
which would make the offline promise false.