Better I18NBetter I18N

Next.js

Content analytics for Next.js App Router and Pages Router

The Next.js adapter wraps your app in a ContentProvider and exposes a useTrackView hook that's SSR-safe. It detects build-time and skips emission automatically.

Install

npm install @better-i18n/content
bun add @better-i18n/content
pnpm add @better-i18n/content
yarn add @better-i18n/content

Configure

Add your Project ID and API key to .env.local. Find both in the dashboard under Settings → General and Settings → API Keys.

.env.local
NEXT_PUBLIC_BETTER_I18N_PROJECT_ID=your-org/your-project
NEXT_PUBLIC_BETTER_I18N_KEY=bi_pub_xxxxx

Setup

Wrap your app with ContentProvider in a client component:

app/providers.tsx
'use client'
import { ContentProvider } from '@better-i18n/content/adapters/nextjs'

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ContentProvider
      config={{
        projectId: process.env.NEXT_PUBLIC_BETTER_I18N_PROJECT_ID!,
        apiKey: process.env.NEXT_PUBLIC_BETTER_I18N_KEY!,
      }}
    >
      {children}
    </ContentProvider>
  )
}

Mount it in your root layout:

app/layout.tsx
import { Providers } from './providers'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}

Track a view

app/blog/[slug]/page.tsx
'use client'
import { useTrackView } from '@better-i18n/content/adapters/nextjs'

export default function BlogPost({ post }: { post: Post }) {
  useTrackView('content.view', {
    entryId: post.id,
    contentModel: 'blog',
    entrySlug: post.slug,
    language: post.locale,
  })

  return <article>{post.body}</article>
}

SSR safety

ContentProvider creates the tracker synchronously, but track() is inherently SSR-safe — it checks isBrowser() internally and becomes a no-op on the server. useTrackView is also a no-op during SSR and during the Next.js build phase (NEXT_PHASE=phase-production-build).

If useTrackView or useContent is used outside of a ContentProvider, the SDK logs a one-time warning and disables tracking — it never throws or crashes your app.

Next steps

On this page