Integrations · Next.js

@leetlytics/sdk for Next.js apps.

Use the NPM package for page views, product events, and fetch breakage tracking. Day zero is a few lines of client code — not an analytics warehouse project.

SDK surface

Page views, events, and breakages.

  • createLeetLyticsClient with a public workspace key and ingest endpoint
  • Page views and trackEvent for key product moments
  • installSpaPageViewTracking for App Router client navigations
  • installFetchBreakageTracking for 400/500-class request failures
  • Optional server-side POST /api/conversions with a private conversion key

Run pnpm add @leetlytics/sdk, then mount this provider once from your root App Router layout.

// app/leetlytics-provider.tsx
"use client";

import { useEffect, type ReactNode } from "react";
import {
  createLeetLyticsClient,
  installFetchBreakageTracking,
  installSpaPageViewTracking,
  type JourneyStepEventInput,
  type LeetLyticsClient,
} from "@leetlytics/sdk";

declare global {
  interface Window {
    __leetlyticsRuntime?: {
      client?: LeetLyticsClient;
      cleanup?: () => void;
      initialPageViewSent: boolean;
    };
  }
}

export function LeetLyticsProvider({ children }: { children: ReactNode }) {
  useEffect(() => {
    const runtime = window.__leetlyticsRuntime ?? { initialPageViewSent: false };
    window.__leetlyticsRuntime = runtime;

    // Fast Refresh can replace this module before React runs its prior cleanup.
    runtime.cleanup?.();

    const leetlytics = createLeetLyticsClient({
      workspaceKey: process.env.NEXT_PUBLIC_LEETLYTICS_WORKSPACE_KEY!,
      endpoint: "https://leetlytics.com/api/ingest",
    });
    const restoreSpaPageViews = installSpaPageViewTracking(leetlytics);
    const restoreFetchBreakageTracking = installFetchBreakageTracking(leetlytics);
    runtime.client = leetlytics;

    if (!runtime.initialPageViewSent) {
      runtime.initialPageViewSent = true;
      void leetlytics.trackEvent({ name: "page_view" });
    }

    const cleanup = () => {
      // Start delivery before destroy clears the queued event and its flush timer.
      const delivery = leetlytics.flush();
      if (runtime.client === leetlytics) runtime.client = undefined;
      restoreFetchBreakageTracking();
      restoreSpaPageViews();
      void delivery.finally(() => leetlytics.destroy());
    };
    runtime.cleanup = cleanup;

    return () => {
      if (runtime.cleanup === cleanup) {
        cleanup();
        runtime.cleanup = undefined;
      }
    };
  }, []);

  return children;
}

export function trackKeyAction(name: string) {
  return window.__leetlyticsRuntime?.client?.trackEvent({ name }) ?? Promise.resolve();
}

export function trackJourneyStep(event: JourneyStepEventInput) {
  return window.__leetlyticsRuntime?.client?.trackJourneyStep(event) ?? Promise.resolve();
}
Out of scope for day zero

Keep the client surface small.

  • Automatic GTM container wiring
  • Session replay or full APM traces
  • Warehouse export connectors on day zero