Frameworks
React
React 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. It is a lighter alternative to Google Analytics for React, with live visitors, goals and revenue attribution in one script.
Add the script
Add the script
Copy your snippet
Open Settings → React / Vite.
Paste it into index.html
In root
index.html, paste before</head>.<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My app</title> <script defer data-site="YOUR_SITE_ID" data-domain="example.com" src="https://app.usestickybeak.com/_cfw/s.js" ></script> </head> <body> <div id="root"></div> <script type="module" src="/src/main.tsx"></script> </body> </html>Keep it a plain script;
type="module"stops it working.Build and deploy
Create React App
For Create React App, use public/index.html.
Keep the site ID in an environment variable
For production-only loading, use a VITE_ variable in index.html:
VITE_STICKYBEAK_SITE_ID=YOUR_SITE_ID
Change the installed tag to data-site="%VITE_STICKYBEAK_SITE_ID%".
For Create React App, use %REACT_APP_STICKYBEAK_SITE_ID%.
localhost is already excluded; the variable also excludes staging.
Check it's working
Test the deployed site, then verify your install.
Track goals
Add data-goal to rendered links or buttons. For other events, use the typed queued helper below. See Custom goals.
<button data-goal="initiate_checkout" data-goal-plan="pro" onClick={openCheckout}>
Upgrade
</button>
type GoalProps = Record<string, string | number | boolean>;
type Stickybeak = ((goal: string, props?: GoalProps) => void) & { q?: unknown[][] };
declare global {
interface Window {
stickybeak?: Stickybeak;
}
}
export function track(goal: string, props?: GoalProps): void {
if (typeof window === "undefined") return; // on the server: nothing to do
if (!window.stickybeak) {
// Hold calls made before the script loads; it sends them when it arrives.
const queue: Stickybeak = (...args) => {
(queue.q ??= []).push(args);
};
window.stickybeak = queue;
}
window.stickybeak(goal, props);
}
import { track } from "../lib/stickybeak";
export function InviteForm() {
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
const form = new FormData(event.currentTarget);
const res = await fetch("/api/invites", { method: "POST", body: form });
if (res.ok) track("invite_sent", { role: String(form.get("role")) });
}
return (
<form onSubmit={onSubmit}>
<input name="email" type="email" required />
<select name="role">
<option value="member">Member</option>
<option value="admin">Admin</option>
</select>
<button>Send invite</button>
</form>
);
}
export function track(goal, props) {
if (typeof window === "undefined") return; // on the server: nothing to do
// Hold calls made before the script loads; it sends them when it arrives.
window.stickybeak = window.stickybeak || function () {
(window.stickybeak.q = window.stickybeak.q || []).push(arguments);
};
window.stickybeak(goal, props);
}
Track purchases
After confirming an order in the browser, send:
window.stickybeak?.("purchase", { revenue: 49, currency: "USD", order_id: "ORDER_ID" });
Use real values; see Revenue.
Page changes
History routers count new paths. Replace, query-only, hash-only and HashRouter changes do not. See Single-page apps.
If it isn't working
Check the production site ID and domain, then see Troubleshooting.