A version written into a manifest is written into every manifest that wants it, which is how eslint came to exist in a hundred and four forms across this estate and how a package came to resolve twice at run time. The catalog moves the number out of the manifest: a manifest names the package, the workspace names the version. Four are held below their latest because the newer release cannot be used, and the reason is recorded rather than the version alone: @noble/hashes 2 renamed every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels 3 points its types condition at the bundle.
@insights/next
The official Insights integration for Next.js. Provides analytics, feature flags, and event capture across the App Router (React Server Components), Pages Router, and middleware — with a single unified package.
Features
- App Router support with a server-component
InsightsProviderthat bootstraps feature flags via SSR - Pages Router support via
InsightsProvider,InsightsPageView, andgetServerSideInsights - Middleware for identity cookie seeding and optional API proxying
- Server-side feature flags via
getInsights()in server components and route handlers - Automatic pageview tracking with the
InsightsPageViewcomponent - Consent-aware — all server-side code respects the user's opt-in/opt-out preference
- Static-safe by default — the provider does not call dynamic APIs unless you enable
bootstrapFlags
Install
npm install @insights/next
# or
pnpm add @insights/next
# or
yarn add @insights/next
Peer dependencies: next >= 13.0.0, react >= 18.0.0, react-dom >= 18.0.0
Quick Start (App Router)
1. Set environment variables
NEXT_PUBLIC_INSIGHTS_KEY=phc_your_key_here
NEXT_PUBLIC_INSIGHTS_HOST=https://us.i.insights.com # optional
2. Add middleware
// middleware.ts
import { insightsMiddleware } from '@insights/next'
export default insightsMiddleware({ proxy: true })
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}
3. Wrap your layout
// app/layout.tsx
import { InsightsProvider, InsightsPageView } from '@insights/next'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<InsightsProvider clientOptions={{ api_host: '/ingest' }} bootstrapFlags>
<InsightsPageView />
{children}
</InsightsProvider>
</body>
</html>
)
}
4. Use Insights
// In a client component
'use client'
import { useInsights, useFeatureFlag } from '@insights/next'
export function MyComponent() {
const insights = useInsights()
const showNewUI = useFeatureFlag('new-ui')
return <button onClick={() => insights.capture('clicked')}>Click me</button>
}
// In a server component
import { getInsights } from '@insights/next'
export default async function Page() {
const insights = await getInsights()
const flags = await insights.getAllFlags()
insights.capture({ event: 'page_viewed' })
// ...
}
For detailed usage including Pages Router, consent management, middleware composition, and all API options, see USAGE.md.
Entry Points
| Import path | Environment | Purpose |
|---|---|---|
@insights/next |
Client + Server | InsightsProvider, InsightsPageView, hooks, getInsights(), insightsMiddleware() |
@insights/next/pages |
Client + Server | InsightsProvider, InsightsPageView, getServerSideInsights() for Pages Router |
Environment Variables
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_INSIGHTS_KEY |
Yes (unless passed as prop) | Your Insights project API key (phc_...) |
NEXT_PUBLIC_INSIGHTS_HOST |
No | Custom Insights host (defaults to https://us.i.insights.com) |
How It Works
-
Middleware runs on every request and seeds an identity cookie (
ph_<key>_insights) with a UUIDv7 anonymous ID if none exists. It optionally proxies SDK API calls through your domain. -
InsightsProvider (a React Server Component) reads that cookie. When
bootstrapFlagsis enabled, it evaluates feature flags server-side viainsights-nodeand passes the results to the client as bootstrap data — so hooks return real values immediately without a network round-trip. -
Client components use
insights-jsunder the hood. The SDK is initialized eagerly during render (not in auseEffect) so that child components and hooks can access a fully configured instance immediately. -
Server utilities (
getInsights()) read the same identity cookie and scope theinsights-nodeclient per request viaenterContext(), so events and flag evaluations are attributed to the correct user. -
Consent is checked at every layer. If the user has opted out (via the consent cookie), the middleware skips cookie seeding, the provider skips flag evaluation, and
getInsights()skips context setup.