Skip to main content

Next.js App Router wiring

Install (substitute the target repo's own package manager — see invariant 3):

npm install @idhub/identity-core @idhub/identity-adapter-nextjs \
@idhub/identity-provider-segment @idhub/identity-provider-launchdarkly @idhub/identity-provider-fullstory

Drop any provider line the user did not select in step 2. If none were selected, install @idhub/identity-core @idhub/identity-adapter-nextjs only — <IdentityProvider providers={[]}> is valid and simply resolves the anonymous id with no vendor fan-out yet.

middleware.ts — guarantee the anonymous id before first render

Write-if-absent. If middleware.ts already exists with unrelated logic (auth redirects, rewrites), report the conflict and show this instead of the no-existing-logic form:

// middleware.ts — no existing middleware logic
import { identityMiddleware } from '@idhub/identity-adapter-nextjs/middleware'

export const middleware = identityMiddleware()
export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] }
// middleware.ts — composing with existing logic
import { withIdentity } from '@idhub/identity-adapter-nextjs/middleware'
import { NextResponse, type NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
const { response, anonymousId } = withIdentity(request)
// ...the target's existing middleware logic goes here, using `response`...
return response
}

export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] }

app/layout.tsx + app/providers.tsx — mount the client providers

// app/layout.tsx — Server Component
import { getAnonymousIdFromCookies } from '@idhub/identity-adapter-nextjs/server'
import { cookies } from 'next/headers'
import { Providers } from './providers'

export default async function RootLayout({ children }: { children: React.ReactNode }) {
const anonymousId = getAnonymousIdFromCookies(await cookies())
return (
<html lang="en">
<body>
<Providers initialAnonymousId={anonymousId}>{children}</Providers>
</body>
</html>
)
}
// app/providers.tsx
'use client'
import { IdentityProvider } from '@idhub/identity-adapter-nextjs'
// Import only the providers the user selected in step 2:
import { segmentProvider } from '@idhub/identity-provider-segment'
import { launchDarklyProvider } from '@idhub/identity-provider-launchdarkly'
import { fullStoryProvider } from '@idhub/identity-provider-fullstory'

export function Providers({
initialAnonymousId,
children,
}: {
initialAnonymousId?: string
children: React.ReactNode
}) {
return (
<IdentityProvider
providers={[
// one entry per selected provider only — see references/provider-env-vars.md
segmentProvider({ client: analytics, writeKey: process.env.NEXT_PUBLIC_SEGMENT_WRITE_KEY! }),
launchDarklyProvider({ clientSideId: process.env.NEXT_PUBLIC_LD_CLIENT_ID! }),
fullStoryProvider({ orgId: process.env.NEXT_PUBLIC_FULLSTORY_ORG_ID! }),
]}
initialAnonymousId={initialAnonymousId}
cookie={{ /* domain: <the value chosen in step 3, or omit entirely for host-only> */ }}
>
{children}
</IdentityProvider>
)
}

segmentProvider needs a caller-supplied analytics/analytics-node client instance (client: analytics above) — this skill does not create that instance; the target repo must already have (or add) its own Segment client module and import it here.

Where identify()/reset() go (surface only — do not auto-edit)

'use client'
import { useIdentity } from '@idhub/identity-adapter-nextjs'

function ExampleUsage() {
const { state, identify, reset } = useIdentity()
// identify(userId, traits) belongs at the login handler found in step 4
// reset() belongs at the logout handler found in step 4
}