Skip to main content

Next.js Integration

MentiQ Analytics provides seamless integration with Next.js applications, supporting both the App Router (app/) and Pages Router (pages/) patterns with automatic page tracking and server-side analytics.

App Router Integration

The App Router (Next.js 13+) uses React Server Components. Here’s how to integrate MentiQ Analytics:
1

Install MentiQ SDK

npm install mentiq-sdk
# or
yarn add mentiq-sdk
2

Create Analytics Provider

Wrap your application with the AnalyticsProvider in your root layout:
app/layout.tsx
import { AnalyticsProvider } from "mentiq-sdk";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <AnalyticsProvider
          config={{
            apiKey: process.env.NEXT_PUBLIC_MENTIQ_API_KEY!,
            projectId: process.env.NEXT_PUBLIC_MENTIQ_PROJECT_ID!,
            enableAutoPageTracking: true,
            enablePerformanceTracking: true,
            enableErrorTracking: true,
            batchSize: 20,
            flushInterval: 10000,
          }}
        >
          {children}
        </AnalyticsProvider>
      </body>
    </html>
  );
}
3

Use Analytics in Client Components

Mark your component with 'use client' and use the analytics hooks:
app/components/TrackingButton.tsx
'use client';

import { useAnalytics } from "mentiq-sdk";

export function TrackingButton() {
  const { track } = useAnalytics();

  const handleClick = () => {
    track("button_clicked", {
      button_id: "hero-cta",
      location: "homepage",
    });
  };

  return <button onClick={handleClick}>Get Started</button>;
}

Alternative: Using withAnalytics Wrapper

For more control over page tracking, use the withAnalytics wrapper:
app/layout.tsx
import { withAnalytics } from "mentiq-sdk/nextjs";

const AnalyticsWrapper = withAnalytics({
  apiKey: process.env.NEXT_PUBLIC_MENTIQ_API_KEY!,
  projectId: process.env.NEXT_PUBLIC_MENTIQ_PROJECT_ID!,
  enableAutoPageTracking: true,
});

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <AnalyticsWrapper>{children}</AnalyticsWrapper>
      </body>
    </html>
  );
}
The withAnalytics wrapper automatically tracks route changes by intercepting window.history.pushState and window.history.replaceState.

Pages Router Integration

For applications using the traditional Pages Router:
1

Wrap Application in _app.tsx

pages/_app.tsx
import type { AppProps } from "next/app";
import { AnalyticsProvider } from "mentiq-sdk";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { useAnalytics } from "mentiq-sdk";

function AnalyticsPageTracker() {
  const router = useRouter();
  const { page } = useAnalytics();

  useEffect(() => {
    // Track initial page load
    page({
      url: window.location.href,
      path: router.pathname,
      title: document.title,
    });

    // Track route changes
    const handleRouteChange = (url: string) => {
      page({
        url,
        path: new URL(url, window.location.origin).pathname,
        title: document.title,
      });
    };

    router.events.on("routeChangeComplete", handleRouteChange);
    return () => {
      router.events.off("routeChangeComplete", handleRouteChange);
    };
  }, [router, page]);

  return null;
}

export default function App({ Component, pageProps }: AppProps) {
  return (
    <AnalyticsProvider
      config={{
        apiKey: process.env.NEXT_PUBLIC_MENTIQ_API_KEY!,
        projectId: process.env.NEXT_PUBLIC_MENTIQ_PROJECT_ID!,
        enableAutoPageTracking: false, // We handle manually
      }}
    >
      <AnalyticsPageTracker />
      <Component {...pageProps} />
    </AnalyticsProvider>
  );
}
2

Track Events in Pages

pages/index.tsx
import { useAnalytics } from "mentiq-sdk";

export default function HomePage() {
  const { track, identify } = useAnalytics();

  const handleSignup = async (email: string) => {
    // Your signup logic...
    
    identify(userId, { email });
    track("signup_completed", {
      method: "email",
      source: "homepage",
    });
  };

  return (
    <div>
      {/* Your page content */}
    </div>
  );
}

Alternative: Using trackPageView Helper

For simpler integration with Pages Router:
pages/_app.tsx
import { useRouter } from "next/router";
import { useEffect } from "react";
import { Analytics } from "mentiq-sdk";
import { trackPageView } from "mentiq-sdk/nextjs";

const analytics = new Analytics({
  apiKey: process.env.NEXT_PUBLIC_MENTIQ_API_KEY!,
  projectId: process.env.NEXT_PUBLIC_MENTIQ_PROJECT_ID!,
});

export default function App({ Component, pageProps }) {
  const router = useRouter();

  useEffect(() => {
    const handleRouteChange = (url: string) => {
      trackPageView(analytics, url);
    };

    router.events.on("routeChangeComplete", handleRouteChange);
    return () => router.events.off("routeChangeComplete", handleRouteChange);
  }, [router.events]);

  return <Component {...pageProps} />;
}

Server-Side Analytics

Track events from API routes and server components:
app/api/signup/route.ts
import { NextRequest, NextResponse } from "next/server";
import { trackServerEvent } from "mentiq-sdk/nextjs";

export async function POST(request: NextRequest) {
  const body = await request.json();
  const { email, name } = body;

  // Your signup logic...
  const userId = await createUser(email, name);

  // Track server-side event
  await trackServerEvent(
    {
      apiKey: process.env.MENTIQ_API_KEY!,
      projectId: process.env.MENTIQ_PROJECT_ID!,
    },
    "signup_completed",
    {
      method: "api",
      email_domain: email.split("@")[1],
    },
    {
      userId,
      userAgent: request.headers.get("user-agent") || undefined,
      ip: request.headers.get("x-forwarded-for") || request.ip,
    }
  );

  return NextResponse.json({ success: true, userId });
}

Server Event Context

The trackServerEvent function accepts a context object for server-side enrichment:
interface ServerContext {
  userId?: string;       // User ID to associate with event
  userAgent?: string;    // Browser user agent
  ip?: string;          // Client IP address
}
Server-side events are sent directly to the MentiQ API without queuing or batching. Make sure to handle errors appropriately.

API Route Analytics Helper

For consistent tracking across multiple API routes, use the createAnalyticsApiHandler:
lib/analytics.ts
import { createAnalyticsApiHandler } from "mentiq-sdk/nextjs";

export const apiAnalytics = createAnalyticsApiHandler({
  apiKey: process.env.MENTIQ_API_KEY!,
  projectId: process.env.MENTIQ_PROJECT_ID!,
  debug: process.env.NODE_ENV === "development",
});
Then use it in your API routes:
pages/api/purchase.ts
import { apiAnalytics } from "@/lib/analytics";
import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { userId, productId, amount } = req.body;

  // Process purchase...
  const orderId = await processPurchase(userId, productId, amount);

  // Track with helper
  apiAnalytics.track(
    "purchase_completed",
    {
      product_id: productId,
      amount,
      order_id: orderId,
    },
    userId
  );

  // Optionally flush immediately
  await apiAnalytics.flush();

  return res.status(200).json({ orderId });
}

Middleware for Request Tracking

Track all API requests automatically with the analytics middleware:
This middleware tracks all API requests. Use carefully in production as it may generate high event volumes.
middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { createAnalyticsMiddleware } from "mentiq-sdk/nextjs";

const analyticsMiddleware = createAnalyticsMiddleware({
  apiKey: process.env.MENTIQ_API_KEY!,
  projectId: process.env.MENTIQ_PROJECT_ID!,
});

export async function middleware(request: NextRequest) {
  // Only track API routes
  if (request.nextUrl.pathname.startsWith("/api/")) {
    const response = NextResponse.next();
    
    // Track request (fire and forget)
    analyticsMiddleware(request, response, () => {}).catch(console.error);
    
    return response;
  }

  return NextResponse.next();
}

export const config = {
  matcher: "/api/:path*",
};
The middleware automatically tracks:
  • api_request_start - When request begins
  • api_request_complete - When request completes (with duration and status code)

Environment Variables

Create a .env.local file in your project root:
.env.local
# Public keys (safe for client-side)
NEXT_PUBLIC_MENTIQ_API_KEY=your_public_api_key
NEXT_PUBLIC_MENTIQ_PROJECT_ID=your_project_id

# Private keys (server-side only)
MENTIQ_API_KEY=your_private_api_key
MENTIQ_PROJECT_ID=your_project_id
MENTIQ_ENDPOINT=https://api.mentiq.io
Use NEXT_PUBLIC_* prefixed variables for client-side code and unprefixed variables for server-side code to maintain security.

TypeScript Configuration

Ensure your tsconfig.json includes proper type resolution:
tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Best Practices

1

Separate Client and Server Keys

Use different API keys for client-side and server-side tracking to maintain security and enable proper rate limiting.
2

Handle Errors Gracefully

Always wrap analytics calls in try-catch blocks to prevent analytics failures from breaking your application:
try {
  await trackServerEvent(config, event, properties);
} catch (error) {
  console.error("Analytics error:", error);
  // Continue with application logic
}
3

Optimize Batch Settings

Configure appropriate batch sizes and flush intervals based on your traffic:
// High-traffic apps
batchSize: 50,
flushInterval: 5000, // 5 seconds

// Low-traffic apps
batchSize: 10,
flushInterval: 30000, // 30 seconds
4

Use Debug Mode in Development

Enable debug logging during development:
config={{
  debug: process.env.NODE_ENV === "development",
  // ... other config
}}

Troubleshooting

Page Views Not Tracking

Make sure enableAutoPageTracking: true is set in your config, and that the AnalyticsProvider wraps your entire application in the root layout.
Ensure you’re tracking route changes with router.events.on("routeChangeComplete") or using the trackPageView helper.

Server-Side Events Failing

Verify your server-side API key is correct and has proper permissions
Ensure the endpoint URL is accessible from your server
Check that you’re using the private API key (not the public one)

TypeScript Errors

# Regenerate types
npm run type-check

# Or install type definitions
npm install --save-dev @types/node

Next Steps

TypeScript Types

Learn about TypeScript interfaces and types

Event Batching

Understand batching and queuing system

Privacy Compliance

Implement privacy features and data masking

Build docs developers (and LLMs) love