JustAnalytics for Next.js

Step-by-step guide to add analytics, error tracking, and APM to your Next.js app

JustAnalytics for Next.js

Add full-stack observability to your Next.js application — distributed tracing, error tracking, structured logging, and infrastructure metrics.

Time to data: 3-5 minutes

Prerequisites#

  • Next.js 14+ (App Router recommended; Pages Router also supported)
  • Node.js 18+
  • A JustAnalytics account with a Site ID and API key

Install the SDK

npm install @justanalyticsapp/node

Or with your preferred package manager:

yarn add @justanalyticsapp/node
# or
pnpm add @justanalyticsapp/node

Initialize via instrumentation.ts

Next.js 15+ provides an instrumentation.ts hook that runs once when the server starts. This is the recommended way to initialize JustAnalytics.

Zero-config (reads from environment variables):

// instrumentation.ts (project root)
export { register } from '@justanalyticsapp/node/next';

With explicit configuration:

// instrumentation.ts
import { withJustAnalytics } from '@justanalyticsapp/node/next';

export function register() {
  withJustAnalytics({
    siteId: process.env.JA_SITE_ID!,
    apiKey: process.env.JA_API_KEY!,
    serviceName: 'my-next-app',
    environment: process.env.NODE_ENV,
  });
}

Add your credentials to .env.local:

JA_SITE_ID=site_abc123
JA_API_KEY=ja_sk_your_api_key_here

Add API route tracing

Wrap your API route handlers with withTracing to automatically create spans for each request:

// app/api/users/[id]/route.ts
import { withTracing } from '@justanalyticsapp/node/next';

export const GET = withTracing(async (req, { params }) => {
  const { id } = await params;
  const user = await db.users.findUnique({ where: { id } });
  return Response.json(user);
});

export const POST = withTracing(async (req) => {
  const body = await req.json();
  const user = await db.users.create({ data: body });
  return Response.json(user, { status: 201 });
});

Add middleware tracing (optional)

Trace your Next.js middleware to measure authentication, redirects, and other middleware logic:

// middleware.ts
import { withMiddlewareTracing } from '@justanalyticsapp/node/next';
import { NextResponse } from 'next/server';

export default withMiddlewareTracing(async (req) => {
  // Your middleware logic
  const token = req.cookies.get('session');
  if (!token && req.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', req.url));
  }
  return NextResponse.next();
});

export const config = {
  matcher: ['/dashboard/:path*'],
};

Add Server Component tracing (optional)

Trace data fetching in Server Components:

// app/users/[id]/page.tsx
import { traceServerComponent } from '@justanalyticsapp/node/next';

export default async function UserPage({ params }: { params: { id: string } }) {
  return traceServerComponent('UserPage', async () => {
    const user = await getUser(params.id);
    return (
      <div>
        <h1>{user.name}</h1>
        <p>{user.email}</p>
      </div>
    );
  });
}

Add client-side tracking (optional)

For frontend analytics (page views, clicks, Web Vitals), add the tracking script to your root layout:

// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <script
          defer
          data-site-id="site_abc123"
          src="https://justanalytics.up.railway.app/tracker.js"
        />
        <script
          defer
          data-site-id="site_abc123"
          src="https://justanalytics.up.railway.app/monitor.js"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}

Verify Your Setup

Send a request to any API route, then check the Traces tab in your dashboard. You should see server spans with route names like 'GET /api/users/[id]'.

Open Dashboard

Advanced Features#

Error tracking#

Errors thrown inside withTracing handlers are automatically captured. You can also capture errors manually:

import JA from '@justanalyticsapp/node';

try {
  await riskyOperation();
} catch (error) {
  JA.captureException(error, {
    tags: { module: 'payments' },
    extra: { orderId: '12345' },
  });
}

Structured logging#

import JA from '@justanalyticsapp/node';

JA.logger.info('User signed up', { userId: 'u123', plan: 'pro' });
JA.logger.error('Payment failed', { orderId: 'o456', reason: 'insufficient_funds' });

Custom spans#

import JA from '@justanalyticsapp/node';

const result = await JA.startSpan('process-order', async (span) => {
  span.setAttribute('order.id', orderId);
  span.setAttribute('order.total', total);
  return await processOrder(orderId);
});

User identification#

import JA from '@justanalyticsapp/node';

// In your auth middleware or after login
JA.setUser({ id: user.id, email: user.email });

Custom metrics#

import JA from '@justanalyticsapp/node';

JA.recordMetric('custom.queue_size', 42, { queue: 'emails' });

Environment configuration#

| Variable | Description | Required | |----------|-------------|----------| | JA_SITE_ID | Your site ID from the dashboard | Yes | | JA_API_KEY | API key (starts with ja_sk_) | Yes | | JA_SERVICE_NAME | Service name for traces | No (defaults to package name) | | JA_ENVIRONMENT | Deployment environment | No (defaults to NODE_ENV) |

Pages Router support#

If you are using the Pages Router, initialize the SDK in a custom server or at the top of _app.tsx:

// pages/_app.tsx
import JA from '@justanalyticsapp/node';

if (typeof window === 'undefined') {
  JA.init({
    siteId: process.env.JA_SITE_ID!,
    apiKey: process.env.JA_API_KEY!,
    serviceName: 'my-next-app',
  });
}

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

For API routes in Pages Router, wrap handlers manually:

// pages/api/users.ts
import JA from '@justanalyticsapp/node';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  return JA.startSpan(`${req.method} /api/users`, async (span) => {
    const users = await db.users.findMany();
    res.json(users);
  });
}