Skip to Content
SourcesTracking SDKNext.js

Next.js

Add Vendo tracking to your Next.js app. Both App Router and Pages Router are supported.

App Router

Add the CDN snippet to your root layout using Next.js’s <Script> component:

// app/layout.tsx import Script from 'next/script'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <head> <Script id="vendo-tracking" strategy="afterInteractive"> {` (function(w,d,s,e,l,k){w['VendoObject']=e;w[e]=w[e]||function(){ (w[e].q=w[e].q||[]).push(arguments)};w[e].l=1*new Date(); l=d.createElement(s);k=d.getElementsByTagName(s)[0]; l.async=1;l.src='https://cdn.vendodata.com/sdk/v1/vendo.js';k.parentNode.insertBefore(l,k); })(window,document,'script','vendo'); vendo('init', 'YOUR_WRITE_KEY', { host: 'https://YOUR_TRACKING_ENDPOINT', trackPageViews: true }); `} </Script> </head> <body>{children}</body> </html> ); }

Track Client-Side Navigations

Next.js client-side navigations don’t trigger a full page load, so the SDK’s automatic page view won’t fire. Add a route-change listener component:

// components/track-page-views.tsx 'use client'; import { usePathname, useSearchParams } from 'next/navigation'; import { useEffect } from 'react'; declare global { interface Window { vendo?: (...args: unknown[]) => void; } } export function TrackPageViews() { const pathname = usePathname(); const searchParams = useSearchParams(); useEffect(() => { if (typeof window.vendo === 'function') { window.vendo('page'); } }, [pathname, searchParams]); return null; }

Add <TrackPageViews /> to your root layout inside a <Suspense> boundary (required by useSearchParams):

// app/layout.tsx (body section) import { Suspense } from 'react'; import { TrackPageViews } from '@/components/track-page-views'; <body> <Suspense fallback={null}> <TrackPageViews /> </Suspense> {children} </body>

Pages Router

Add the snippet to _app.tsx and track route changes with the Next.js router:

// pages/_app.tsx import type { AppProps } from 'next/app'; import Script from 'next/script'; import { useRouter } from 'next/router'; import { useEffect } from 'react'; export default function App({ Component, pageProps }: AppProps) { const router = useRouter(); useEffect(() => { const handleRouteChange = () => { if (typeof window.vendo === 'function') { window.vendo('page'); } }; router.events.on('routeChangeComplete', handleRouteChange); return () => router.events.off('routeChangeComplete', handleRouteChange); }, [router.events]); return ( <> <Script id="vendo-tracking" strategy="afterInteractive"> {` (function(w,d,s,e,l,k){w['VendoObject']=e;w[e]=w[e]||function(){ (w[e].q=w[e].q||[]).push(arguments)};w[e].l=1*new Date(); l=d.createElement(s);k=d.getElementsByTagName(s)[0]; l.async=1;l.src='https://cdn.vendodata.com/sdk/v1/vendo.js';k.parentNode.insertBefore(l,k); })(window,document,'script','vendo'); vendo('init', 'YOUR_WRITE_KEY', { host: 'https://YOUR_TRACKING_ENDPOINT', trackPageViews: true }); `} </Script> <Component {...pageProps} /> </> ); }

Identify Users

Call identify once the user is authenticated:

window.vendo('identify', user.id, { email: user.email, name: user.name, plan: user.plan, });

Call reset on logout to clear the identity:

window.vendo('reset');

Last updated on