Next.js SDK
Drop-in analytics for App Router and Pages Router — one component, React hooks, and an optional API proxy.
The Next.js SDK wraps the Web SDK and adds a FlashAnalyticsComponent for layout setup, a useFlashAnalytics() hook for client components, and an optional route-handler proxy so events stay on your domain.
Installation
Install the package
npm install @flash-analytics/nextjs@2.2.3pnpm add @flash-analytics/nextjs@2.2.3Add environment variables
NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID=00000000-0000-4000-8000-000000000000
NEXT_PUBLIC_FLASH_ANALYTICS_ENDPOINT=https://api.flashanalytics.appKeep secrets server-side
NEXT_PUBLIC_* variables in the browser. Never set FLASH_ANALYTICS_SECRET_KEY as a public env var.Add the component to your root layout
Place FlashAnalyticsComponent inside <body> so it loads on every page.
import { FlashAnalyticsComponent } from '@flash-analytics/nextjs';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<FlashAnalyticsComponent
appId={process.env.NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID!}
capturePageViews
captureErrors
captureVariants
/>
{children}
</body>
</html>
);
}Track events in client components
'use client';
import { useFlashAnalytics } from '@flash-analytics/nextjs';
export function UpgradeButton() {
const analytics = useFlashAnalytics();
return (
<button
onClick={() => analytics.track('upgrade_clicked', { placement: 'settings' })}
>
Upgrade
</button>
);
}Pages Router setup
For Pages Router, add the component in _app.tsx.
import type { AppProps } from 'next/app';
import { FlashAnalyticsComponent } from '@flash-analytics/nextjs';
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<FlashAnalyticsComponent
appId={process.env.NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID!}
capturePageViews
/>
<Component {...pageProps} />
</>
);
}Identify users
Call identify after login. Pass userId directly to the component to identify immediately at bootstrap.
// Via hook (client component)
const analytics = useFlashAnalytics();
await analytics.identify({ profileId: session.user.id, email: session.user.email });
// Via component prop (identifies at script boot)
<FlashAnalyticsComponent
appId={process.env.NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID!}
userId={session?.user?.id}
defaultProperties={{ plan: session?.user?.plan }}
/>Experiments
Enable captureVariants to keep a local cache in sync automatically. New session → all experiments fetched. After identify() → profile-mode assignments refreshed.
'use client';
import { useFlashAnalytics } from '@flash-analytics/nextjs';
export function PricingBanner() {
const analytics = useFlashAnalytics();
// No API call — reads from cache
const all = analytics.getAllExperiments();
// Cache first, API fallback
const assignment = await analytics.getExperimentById('checkout-cta');
console.log(assignment?.variantName); // 'control' | 'variant_a'
}Error boundaries
import { FlashAnalyticsComponent, FlashErrorBoundary } from '@flash-analytics/nextjs';
export default function RootLayout({ children }: { children: React.ReactNode }) {
const appId = process.env.NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID!;
const endpoint = process.env.NEXT_PUBLIC_FLASH_ANALYTICS_ENDPOINT
?? 'https://api.flashanalytics.app';
return (
<html lang="en">
<body>
<FlashAnalyticsComponent appId={appId} endpoint={endpoint} captureErrors />
<FlashErrorBoundary
clientId={appId}
apiUrl={`${endpoint}/track`}
fallback={<h1>Something went wrong.</h1>}
>
{children}
</FlashErrorBoundary>
</body>
</html>
);
}API proxy (optional)
Route events through your own domain to avoid ad-blockers. Create a route handler and point the component at it with endpoint.
import { createRouteHandler } from '@flash-analytics/nextjs/server';
export const { GET, POST } = createRouteHandler({
endpoint: 'https://api.flashanalytics.app',
});<FlashAnalyticsComponent
appId={process.env.NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID!}
endpoint="/api/flash-analytics"
/>Available hook methods
useFlashAnalytics() returns all core SDK methods:
track()identify()setGlobalProperties()revenue()increment()decrement()getSession()fetchRemoteConfig()assignExperiment()autoAssignExperiments()getAllExperiments()getExperimentById()