Stickybeak Docs Dashboard Get early access

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

  1. Copy your snippet

    Open Settings → React / Vite.

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

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