Backends
Cloudflare Workers
Cloudflare Workers analytics with Stickybeak starts by adding its script to your rendered pages; this guide shows you where it belongs and how to track page views, goals and purchase revenue.
Your domain needs to be on Cloudflare with its DNS records proxied (the orange cloud), so requests pass through the Worker. You'll also need Wrangler.
Add the script
Write the Worker
It passes each request through to your origin, then appends the tag to
<head>on HTML responses only:export default { async fetch(request, env) { const response = await fetch(request); const type = response.headers.get("content-type") || ""; if (!env.STICKYBEAK_SITE_ID || !type.includes("text/html")) return response; const tag = `<script defer data-site="${env.STICKYBEAK_SITE_ID}" data-domain="example.com" src="https://app.usestickybeak.com/_cfw/s.js" ></script>`; return new HTMLRewriter() .on("head", { element(head) { head.append(tag, { html: true }); } }) .transform(response); }, };Route it to your site
Set the site ID as a variable, and run the Worker on your production hostname only. Copy the ID from Settings in the dashboard.
{ "name": "stickybeak-inject", "main": "src/index.js", "compatibility_date": "2026-09-01", "routes": [{ "pattern": "example.com/*", "zone_name": "example.com" }], "vars": { "STICKYBEAK_SITE_ID": "YOUR_SITE_ID" } }Deploy
npx wrangler deploy
Already serving from a Worker?
If your site is a Worker (with static assets, say) or a Pages project, transform your own response the same way instead of calling fetch(request).
export async function onRequest({ next, env }) {
const response = await next();
if (!env.STICKYBEAK_SITE_ID || !(response.headers.get("content-type") || "").includes("text/html")) return response;
return new HTMLRewriter()
.on("head", { element(head) { head.append(`<script defer data-site="${env.STICKYBEAK_SITE_ID}" data-domain="example.com" src="https://app.usestickybeak.com/_cfw/s.js"></script>`, { html: true }); } })
.transform(response);
}
Check it's working
Deploy first, then run curl -s https://example.com/ | grep _cfw.
See Verify your install.
Track goals
Click goals are a data-goal attribute on the element, so the same Worker can add them. Match elements with a CSS selector:
return new HTMLRewriter()
.on("head", { element(head) { head.append(tag, { html: true }); } })
.on('a[href="/pricing"]', { element(a) { a.setAttribute("data-goal", "view_pricing"); } })
.on("form#signup button[type=submit]", { element(b) { b.setAttribute("data-goal", "signup_submit"); } })
.transform(response);
See Custom goals.
Track purchases
Render window.stickybeak("purchase", { revenue, currency, order_id }) on the checkout confirmation page.
See Revenue.
If it isn't working
- The DNS record must be proxied, the route must match the hostname, and only
text/htmlresponses are rewritten.
See Troubleshooting.