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
}