Single Page App Tracking
Set up AnyTrack conversion tracking in single page applications built with React, Next.js, Vite, or AI coding tools like Lovable and Bolt. Covers Tracking Tag installation, automatic PageView tracking on route changes, and form Click ID setup.
Overview
Section titled “Overview”A single page application (SPA) loads once and updates content through client-side routing instead of full page reloads. Frameworks like React, Next.js, Vue, and Svelte work this way, and so do apps built with AI coding tools such as Lovable, Bolt, and v0.
On a traditional website, the Tracking Tag reloads with every page. In an SPA, the Tracking Tag loads once and stays on the page while the visitor navigates. The Tracking Tag detects each route change and sends a PageView, so you do not need router code for page views. The one exception is a hash router (see the warning below).
This guide covers what the Tracking Tag handles automatically in an SPA, where to install it in popular frameworks, and how to keep the Click ID in forms.
What Works Automatically
Section titled “What Works Automatically”The Tracking Tag handles most SPA behavior out of the box:
PageViewon load and on route changes: the Tracking Tag sends aPageViewwhen the app loads. Then it checks the URL about once per second and sends aPageViewwhen the path or the query string changes. A change after the#sign does not count.- Dynamically added content: AutoTrack watches the page for changes, so links and forms your app renders after load are picked up automatically.
- Click ID substitution: AutoTag replaces the
--CLICK-ID--placeholder in hidden form fields and form action URLs with the real Click ID at runtime. - Form submissions: AutoTrack detects standard HTML form submissions and fires a
FormSubmitevent.
Install the Tracking Tag
Section titled “Install the Tracking Tag”The tag itself is the same as on any website: paste the snippet from your AnyTrack dashboard into the <head> of the HTML document that hosts your app, before other scripts. Follow the standard installation guide to get your snippet. What varies by framework is where that document lives:
| Framework | Where to paste the tag |
|---|---|
| React (Vite, Create React App, Lovable, Bolt) | index.html at the project root, inside <head> |
| Next.js App Router (v13+) | app/layout.tsx, using the Next.js Script component with the beforeInteractive strategy |
| Next.js Pages Router | pages/_document.tsx |
| Astro | The base layout, usually src/layouts/Layout.astro |
| SvelteKit | src/app.html |
Track Forms in an SPA
Section titled “Track Forms in an SPA”Form tracking in an SPA uses the same hidden field pattern as any other site. Add a hidden input with the --CLICK-ID-- placeholder inside the <form> element. AutoTag fills it with the real Click ID.
<form> <input type="hidden" name="click_id" value="--CLICK-ID--" /> <!-- your visible fields --></form>In React, keep the hidden input uncontrolled (defaultValue="--CLICK-ID--"). A controlled input (value={state}) lets React overwrite the Click ID on the next render.
When the form submits, read the hidden field value in your submit handler and include it in the payload you send to your backend or CRM. AutoTrack fires the FormSubmit event in the browser automatically.
See Form Tracking for the full hidden field setup. Embedded Typeform and Calendly forms need no hidden field: the Tracking Tag passes the Click ID to them automatically. If your form is another third-party widget that cannot hold hidden fields, use the Append Click ID to URL method.
Fire Conversion Events from Components
Section titled “Fire Conversion Events from Components”For events that do not come from a form, such as a purchase after payment, trigger them from your component code:
AnyTrack(function() { AnyTrack('trigger', 'Purchase', { value: 49.90, // number, not a string currency: 'USD', transactionId: 'order-12345' // unique ID prevents duplicates });});See Standard Events for the full list of event names and Event Attributes for the data you can attach.
Next.js and SSR Pitfalls
Section titled “Next.js and SSR Pitfalls”Server-side rendering adds a few constraints, because AnyTrack only runs in the browser:
- Server components: Next.js App Router components are server components by default. Add the
'use client'directive to any component that calls AnyTrack. - Call inside
useEffect: Never call AnyTrack during component rendering. It runs on the server there and crashes. Wrap calls inuseEffect, which only runs in the browser after mount. - TypeScript errors: Without a type declaration, the IDE flags
AnyTrack is not defined, and AI coding tools may remove the calls. Createsrc/types/anytrack.d.ts:
// Type declarations for the AnyTrack global JavaScript SDKdeclare function AnyTrack(command: 'PageView'): void;declare function AnyTrack(command: 'trigger', eventName: string, attributes?: Record<string, any>): string;declare function AnyTrack(command: 'atclid'): string;declare function AnyTrack(callback: () => void): void;
interface Window { AnyTrack: typeof AnyTrack;}Related Resources
Section titled “Related Resources”FAQ & Troubleshooting
FAQ was last reviewed on 2026-10-26
Does AnyTrack work with React, Next.js, and other SPA frameworks?
Do I need to fire PageView manually in a single page app?
AnyTrack('PageView') on each route change.Does AutoTrack detect links and forms my app renders after the page loads?
AnyTrack('trigger', 'ViewForm') right after the form appears. See the AutoTrack article for details.