Appearance
Next.js integration
Next.js requires special handling because it renders components on the server where browser APIs (window, document) don't exist. The vantmetry/next export provides components designed for this environment.
Why a separate integration?
The core tracker calls window.addEventListener and accesses navigator during initialization. In Next.js, components run on the server first, and these APIs would throw. The Next.js integration solves this in two ways:
VantmetryScriptuses Next.js'sScriptcomponent to load the CDN tracker after the page becomes interactive, avoiding SSR entirelyinitVantmetryis an SSR-safe wrapper that skips initialization whenwindowis undefined
Option A: Script component (recommended)
The simplest approach. Add VantmetryScript to your root layout:
tsx
import { VantmetryScript } from 'vantmetry/next';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<VantmetryScript publicKey="YOUR_PUBLIC_KEY" />
</body>
</html>
);
}tsx
import { VantmetryScript } from 'vantmetry/next';
export default function App({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<VantmetryScript publicKey="YOUR_PUBLIC_KEY" />
</>
);
}VantmetryScript loads the tracker from the CDN with strategy="afterInteractive", so it never blocks page rendering. Errors are captured automatically after the script loads.
Option B: npm import with initVantmetry
If you prefer bundling the tracker with your app instead of loading it from the CDN, use initVantmetry in a client component:
tsx
'use client';
import { useEffect } from 'react';
import { initVantmetry } from 'vantmetry/next';
export function VantmetryInit() {
useEffect(() => {
initVantmetry({ publicKey: 'YOUR_PUBLIC_KEY' });
}, []);
return null;
}Then add this component to your layout:
tsx
import { VantmetryInit } from './VantmetryInit';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<VantmetryInit />
</body>
</html>
);
}Using the logger in client components
After initialization (either method), use the logger from client components:
tsx
'use client';
import { logger } from 'vantmetry';
export function SubmitButton() {
async function handleSubmit() {
try {
await submitForm();
} catch (err) {
logger.error('Form submission failed', { form: 'contact' });
}
}
return <button onClick={handleSubmit}>Submit</button>;
}Using the React provider with Next.js
You can combine the Next.js initialization with the React provider and error boundary. Create a client wrapper:
tsx
'use client';
import { VantmetryProvider, VantmetryErrorBoundary } from 'vantmetry/react';
export function Providers({ children }) {
return (
<VantmetryProvider publicKey="YOUR_PUBLIC_KEY">
<VantmetryErrorBoundary fallback={<p>Something went wrong.</p>}>
{children}
</VantmetryErrorBoundary>
</VantmetryProvider>
);
}Then use it in your layout:
tsx
import { Providers } from './Providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}This gives you the useLogger hook, automatic error boundary logging, and SSR-safe initialization in one setup.
Core Features
For details on batching, deduplication, circuit breaker, PII masking, and other core tracker features, see the main Tracker page.