Drop-in tracking for your React app — covers Next.js App Router, Pages Router, Vite, and Create React App. With a one-liner for SPA route changes.
YOURCODE in the snippets below.next/script with strategy="afterInteractive":// app/layout.tsx
import Script from 'next/script';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
<Script
src="https://hitcounters.com/api/tracker.js?code=YOURCODE"
strategy="afterInteractive"
/>
</body>
</html>
);
}_document.tsx:// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html>
<Head>
<script async src="https://hitcounters.com/api/tracker.js?code=YOURCODE" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}index.html:<!-- index.html (Vite or CRA) -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My App</title>
<script async src="https://hitcounters.com/api/tracker.js?code=YOURCODE"></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>hcEvent('pageview') on each navigation. Mount this component once at the root:// SPA route-change tracking (Next.js App Router)
'use client';
import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
export function HitCountersRouteTracker() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
// Tracker auto-records first hit; for SPA navigations, fire a custom event
if (typeof window !== 'undefined' && (window as any).hcEvent) {
(window as any).hcEvent('pageview');
}
}, [pathname, searchParams]);
return null;
}Then add a custom Event goal named pageview to count SPA navigations as conversions, or just use it to verify route tracking is working.// Anonymous user clicked 'Sign up'
window.hcEvent?.('signup');
// User completed a purchase
window.hcEvent?.('purchase', 49.99);
// TypeScript types (optional):
declare global {
interface Window {
hcEvent?: (name: string, value?: number) => void;
}
}Then define matching Event goals on the Goals page.next/script handles SSR correctly. For raw <script> tags, they only execute in the browser anyway.hcEvent('pageview') into a useEffect that depends on useLocation() from React Router.script-src https://hitcounters.com in your Content Security Policy.Free plan, no credit card required. Setup takes 2 minutes.
Sign up free See live demo