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:
Install MentiQ SDK
npm install mentiq-sdk
# or
yarn add mentiq-sdk
Create Analytics Provider
Wrap your application with the AnalyticsProvider in your root layout: 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 >
);
}
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:
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:
Wrap Application in _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 >
);
}
Track Events in Pages
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:
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 Router API Route
Pages Router API Route
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 });
}
import type { NextApiRequest , NextApiResponse } from "next" ;
import { trackServerEvent } from "mentiq-sdk/nextjs" ;
export default async function handler (
req : NextApiRequest ,
res : NextApiResponse
) {
if ( req . method !== "POST" ) {
return res . status ( 405 ). json ({ error: "Method not allowed" });
}
const { email , name } = req . body ;
// Your signup logic...
const userId = await createUser ( email , name );
// Track server-side event
try {
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: req . headers [ "user-agent" ],
ip: req . headers [ "x-forwarded-for" ] as string || req . socket . remoteAddress ,
}
);
} catch ( error ) {
console . error ( "Analytics error:" , error );
// Don't fail the request if analytics fails
}
return res . status ( 200 ). 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:
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:
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.
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:
# 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:
{
"compilerOptions" : {
"moduleResolution" : "bundler" ,
"resolveJsonModule" : true ,
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
Best Practices
Separate Client and Server Keys
Use different API keys for client-side and server-side tracking to maintain security and enable proper rate limiting.
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
}
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
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