Quickstart: Next.js

Install the OakData SDK in a Next.js App Router project using the instrumentation-client.ts pattern.

OakData ships as oakdata-js, a zero-config browser tracker. On Next.js (App Router, 15.1+) the cleanest install point is instrumentation-client.ts - Next.js runs it once on the client before your app hydrates, so tracking starts immediately.

In a hurry? Paste this prompt into Claude Code, Cursor, or any agent working in your repo, and give it your public key when asked:

Set up with your AI agent
Paste into Claude Code, Cursor, or any agent in your repo

Set up OakData product analytics in this Next.js App Router project using the oakdata-js SDK.

  1. 1

    Install the package: run "npm install oakdata-js".

  2. 2

    Create or edit .env.local at the project root and add:

    NEXT_PUBLIC_OAK_KEY=<my public key, starts with oak_pub_>
    NEXT_PUBLIC_OAK_HOST=https://oakdata.co

    Ask me for the key value if you don't already have it.

  3. 3

    Create instrumentation-client.ts at the project root (next to app/, not inside it). Import oakdata-js and call oak.init(process.env.NEXT_PUBLIC_OAK_KEY!, { api_host: process.env.NEXT_PUBLIC_OAK_HOST }).

  4. 4

    In my sign-in handler, right after auth returns the user, call oak.identify(user.id, { email: user.email }). In my sign-out handler, call oak.reset().

  5. 5

    If I sign in with OAuth/SSO (e.g. Google), also identify on first load from instrumentation-client.ts: read the current session and, if there is a signed-in user whose id is not already oak.getDistinctId(), call oak.identify(user.id, { email }).

Use my existing auth library. Don't add any other analytics providers or wrapper components. Show me the changes before applying them.

Your agent will ask for your key.

Prefer to wire it up yourself? The steps below are exactly what that prompt does.

1. Install the package

npm install oakdata-js

2. Add your keys

Create (or edit) .env.local at your project root. The NEXT_PUBLIC_ prefix is required - these values run in the browser. Use your public key (oak_pub_…); never put a secret key here.

.env.local
bash
NEXT_PUBLIC_OAK_KEY=oak_pub_xxxxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_OAK_HOST=https://oakdata.co

3. Initialize the tracker

Create instrumentation-client.ts at your project root (next to app/, not inside it):

instrumentation-client.ts
ts
import oak from 'oakdata-js'

oak.init(process.env.NEXT_PUBLIC_OAK_KEY!, {
  api_host: process.env.NEXT_PUBLIC_OAK_HOST,
})

That's it. Pageviews fire on load and on every client-side route change, and clicks, form submits, and other interactions are autocaptured.

Older Next.js?

On versions without instrumentation-client.ts support, call oak.init() from a small "use client" component in your root layout, inside a useEffect with an empty dependency array. Calling initmore than once is a no-op, so it's safe.

4. Identify signed-in users

Add one line to your sign-in handler, right where auth returns the user. oak.identify links everything they did before signing in to the identified profile. Pass their id plus any traits (email, name, plan…) you want in the dashboard.

sign-in-handler.ts
ts
import oak from 'oakdata-js'

async function onSignIn(email, password) {
  const { user } = await auth.signIn(email, password)

  // 👇 the only line you add
  oak.identify(user.id, { email: user.email, name: user.name })
}

And add oak.reset() to your sign-out handler so the next person on that browser starts fresh:

sign-out-handler.ts
ts
async function onSignOut() {
  await auth.signOut()
  oak.reset()
}

That's the whole setup - no extra components or providers. Calls made before init() are queued and replayed, so ordering never matters. See identity resolution for how anonymous and identified activity are stitched together.

Using OAuth / SSO?

With social or SSO login the user returns through a server redirect, so there's no client handler for oak.identify. Instead, identify from instrumentation-client.ts - right after oak.init(), read the session and identify the user if they aren't already. The distinct-id guard makes it a no-op for anyone the sign-in handler already covered.

instrumentation-client.ts
ts
import oak from 'oakdata-js'
// your auth client - e.g. Supabase, Auth.js, Clerk
import { getSession } from '@/lib/auth'

oak.init(process.env.NEXT_PUBLIC_OAK_KEY!, {
  api_host: process.env.NEXT_PUBLIC_OAK_HOST,
})

// OAuth/SSO users land here after the redirect - identify them once.
getSession().then((session) => {
  const user = session?.user
  if (!user || oak.getDistinctId() === user.id) return
  oak.identify(user.id, { email: user.email })
})

5. Track custom events

Beyond autocapture, send your own events with capture:

checkout.ts
ts
import oak from 'oakdata-js'

oak.capture('signup_completed', { plan: 'pro' })

6. See it working

Load a page, then open Live in your dashboard. Your visit shows up within a second or two, with its page, location, and device. Known people appear by name; anonymous humans get a friendly alias; bots are labelled as crawlers - never disguised as people.

Live · now

AP

Amber Panda

/pricing · United States

2s

Googlebot

/blog · crawler

9s
Bots shown as crawlers
The Live feed as visits arrive. A human alias sits alongside a crawler shown honestly as Googlebot.

The SDK reference covers every method and init option.