Browse docs

Explore by section, then jump directly into a page.

React Framework

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

1

Install the package

Terminal
npm install @flash-analytics/nextjs@2.2.3
Terminal
pnpm add @flash-analytics/nextjs@2.2.3
2

Add environment variables

.env.localTerminal
NEXT_PUBLIC_FLASH_ANALYTICS_APP_ID=00000000-0000-4000-8000-000000000000
NEXT_PUBLIC_FLASH_ANALYTICS_ENDPOINT=https://api.flashanalytics.app

Keep secrets server-side

Only expose NEXT_PUBLIC_* variables in the browser. Never set FLASH_ANALYTICS_SECRET_KEY as a public env var.
3

Add the component to your root layout

Place FlashAnalyticsComponent inside <body> so it loads on every page.

app/layout.tsxTSX
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>
  );
}
4

Track events in client components

TSX
'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.

pages/_app.tsxTSX
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.

TSX
// 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.

TSX
'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

app/layout.tsxTSX
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.

app/api/flash-analytics/[...path]/route.tsTypeScript
import { createRouteHandler } from '@flash-analytics/nextjs/server';

export const { GET, POST } = createRouteHandler({
  endpoint: 'https://api.flashanalytics.app',
});
TSX
<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()