React Analytics Without Cookies
Add Fusionaly to a React app built with Vite: one script tag in index.html. It counts React Router page changes and uses no cookies.
In a React app built with Vite, every page loads from index.html. Add the Fusionaly script there once. Fusionaly then counts every page that React Router opens.
Before you start
You need a Fusionaly server, with your site's domain added as a website. Fusionaly takes events only from the domains you added. See Installation.
In the examples, replace analytics.example.com with the domain of your Fusionaly server.
Add the script
-
Open
index.htmlin the root of your project. -
Add the script to
<head>:index.html <!doctype html><html lang="en"><head><meta charset="UTF-8" /><script defer src="https://analytics.example.com/y/api/v1/sdk.js"></script><title>My app</title></head><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>
With Create React App, the file is public/index.html.
Page changes
React Router, with createBrowserRouter or BrowserRouter, changes pages with history.pushState, and Fusionaly counts a page view each time the path changes. A change to only the query string or the hash is not a new page view. Fusionaly counts pages by their path, without the hash. With HashRouter, every page has the path /, so Fusionaly counts all of them as one page. Use a browser router to see each page.
Skip it in development
This is optional. Fusionaly refuses events from localhost, so your own tests never count.
To not load the script at all in development, remove the tag from index.html, and add the script from your entry file:
if (import.meta.env.PROD) { const script = document.createElement("script"); script.src = "https://analytics.example.com/y/api/v1/sdk.js"; script.defer = true; document.head.appendChild(script);}Track events
Fusionaly counts page views and button clicks without any setup. To give an event your own name,
use the data-fusionaly-event-name attribute. See Tracking.
Add the attribute in JSX:
<a href="/pricing" data-fusionaly-event-name="pricing_clicked">Pricing</a>For data that only the browser knows, call the SDK from a handler:
function ExportButton({ format }: { format: string }) { return ( <button onClick={() => window.Fusionaly?.sendCustomEvent("report_exported", { format })}> Export </button> );}With TypeScript, declare the SDK in a .d.ts file that your tsconfig.json includes:
declare global { interface Window { Fusionaly?: { sendCustomEvent(name: string, metadata?: Record<string, unknown>): void; sendPageView(): void; }; }}
export {};Check that it works
- Open your site in a normal browser window. Fusionaly skips automated browsers, such as Playwright, and browsers that send Do Not Track.
-
In the developer tools, open the network tab, and find a
POSTrequest to/x/api/v1/events. A 403 status means that your site's domain is not added as a website. - Open your Fusionaly dashboard. The visit shows up within about a minute.
Notes
- If your app runs on a subdomain, such as
app.example.com, add that subdomain as a website. Or addexample.comand turn on subdomain tracking.
Next steps
- Revenue Tracking: count purchases and their amounts.
- Section Tracking: count the sections that visitors see.
- Exclude your own visits: stop counting your own browser.
- AI Clients (MCP): ask Claude Code, Codex, or Cursor about your traffic.
Guides for other frameworks: Next.js, Astro, Nuxt, SvelteKit, WordPress, Shopify, Webflow, Ghost, Hugo, and the generic guide.