Skip to content

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.

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.

The Tracking Tag handles most SPA behavior out of the box:

  • PageView on load and on route changes: the Tracking Tag sends a PageView when the app loads. Then it checks the URL about once per second and sends a PageView when 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 FormSubmit event.

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:

FrameworkWhere 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 Routerpages/_document.tsx
AstroThe base layout, usually src/layouts/Layout.astro
SvelteKitsrc/app.html

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.

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.

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 in useEffect, 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. Create src/types/anytrack.d.ts:
// Type declarations for the AnyTrack global JavaScript SDK
declare 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;
}

FAQ & Troubleshooting

FAQ was last reviewed on 2026-10-26

Does AnyTrack work with React, Next.js, and other SPA frameworks?
Yes. The Tracking Tag is plain JavaScript and works with any framework. Install it in the HTML document that hosts your app. The Tracking Tag sends a PageView on each route change automatically, except for routes after a # sign (hash routers).
Do I need to fire PageView manually in a single page app?
No. The Tracking Tag sends a PageView when the app loads and each time the path or the query string changes. The Tracking Tag does not remove duplicates, so router code that calls AnyTrack PageView can record a second PageView for the same page. The one exception is a hash router, with routes after a # sign such as /#/pricing. The Tracking Tag sees no URL change there, so call AnyTrack('PageView') on each route change.
Does AutoTrack detect links and forms my app renders after the page loads?
Yes. AutoTrack watches the page with a DOM mutation observer, so links and forms added dynamically are picked up automatically. If a custom form appears after a step or a popup and its hidden field keeps the --CLICK-ID-- placeholder, trigger a custom event such as AnyTrack('trigger', 'ViewForm') right after the form appears. See the AutoTrack article for details.
Why does my AnyTrack call fail in a Next.js server component?
AnyTrack only runs in the browser. Server components execute on the server, where the AnyTrack global does not exist. Add the use client directive to the component and wrap the call in useEffect so it runs after the page mounts.
Why do I see duplicate events during development?
Hot module replacement in dev servers like Vite can re-inject the tag while you edit code. This only happens in development mode. In production builds the tag loads once and events fire normally.