Stickybeak Docs Dashboard Get early access

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

  1. Put your site ID in an environment variable

    Set VITE_STICKYBEAK_SITE_ID in .env.production or production host settings.

    VITE_STICKYBEAK_SITE_ID=YOUR_SITE_ID
  2. Render 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>.

  3. 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.