Frameworks
TanStack Start
TanStack Start 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.
For plain Vite, put the tag in index.html as in the React guide.
Add the script
Put your site ID in an environment variable
Set
VITE_STICKYBEAK_SITE_IDin.env.productionor production host settings.VITE_STICKYBEAK_SITE_ID=YOUR_SITE_IDRender the tag in the root document
Add it after
<HeadContent />in the component that renders<html>:import { HeadContent, Outlet, Scripts, createRootRoute } from "@tanstack/react-router"; import type { ReactNode } from "react"; const siteId = import.meta.env.VITE_STICKYBEAK_SITE_ID; export const Route = createRootRoute({ head: () => ({ meta: [ { charSet: "utf-8" }, { name: "viewport", content: "width=device-width, initial-scale=1" }, ], }), component: RootComponent, }); function RootComponent() { return ( <RootDocument> <Outlet /> </RootDocument> ); } function RootDocument({ children }: { children: ReactNode }) { return ( <html lang="en"> <head> <HeadContent /> {siteId && ( <script defer data-site={siteId} data-domain="example.com" src="https://app.usestickybeak.com/_cfw/s.js" /> )} </head> <body> {children} <Scripts /> </body> </html> ); }If your starter already has a
RootDocument, add only the conditional script tag inside its<head>.Build and deploy
In development the variable isn't set, so nothing loads. The script also switches itself off on
localhost.
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.
<Link to="/signup" data-goal="start_signup" data-goal-plan="pro">Start free trial</Link>
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 { createProject } from "../server/projects";
import { track } from "../lib/stickybeak";
export function CreateProject() {
return (
<button
type="button"
onClick={async () => {
await createProject({ data: { name: "Untitled" } });
track("project_created");
}}
>
New project
</button>
);
}
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
TanStack Router counts new paths. Replace, search-only and hash-history changes do not. See Single-page apps.
If it isn't working
Check the production site ID and domain, then see Troubleshooting.