Next.js SDK

Integrate Perly churn prevention into your Next.js application using the instrumentation hook and a user resolver.

@perly/nextjsv1.0.05 minutes

Installation

npm install @perly/nextjs @perly/core

Usage

The Next.js SDK uses the instrumentation hook pattern. Start by creating a Perly initialization file and importing it from instrumentation.ts.

1. Initialize Perly

// lib/perly.ts
import { init, PerlyBuilder } from '@perly/nextjs';

init({
  apiKey: process.env.PERLY_API_KEY!,
  userResolver: (req) => {
    const userId = req.headers.get('x-user-id');
    if (!userId) return null;
    return new PerlyBuilder()
      .setId(userId)
      .build();
  },
});

2. Register via Instrumentation

// instrumentation.ts (project root)
export async function register() {
  await import('./lib/perly');
}

This ensures Perly is initialized once when the Next.js server starts.

User Resolver

The userResolver is an async function that receives the incoming request and returns a Perly user. Return null for unauthenticated requests to skip tracking.

// lib/perly.ts
import { init, PerlyBuilder } from '@perly/nextjs';
import { getServerSession } from 'next-auth';

init({
  apiKey: process.env.PERLY_API_KEY!,
  userResolver: async (req) => {
    const session = await getServerSession();
    if (!session?.user) return null;

    return new PerlyBuilder()
      .setId(session.user.id)
      .setMetadata({
        plan: session.user.plan,
        region: session.user.region,
      })
      .linkStripeById(session.user.stripeCustomerId)
      .linkHubspotById(session.user.hubspotContactId)
      .build();
  },
});

Tracking Events

Use the getPerly() helper inside API routes and server actions to track customer events.

// app/api/onboarding/complete/route.ts
import { getPerly } from '@perly/nextjs';

export async function POST(req: Request) {
  const perly = getPerly();
  await perly.track('onboarding_completed');
  return Response.json({ success: true });
}

// app/api/reports/export/route.ts
export async function POST(req: Request) {
  const perly = getPerly();
  const body = await req.json();
  await perly.track('report_exported', { format: body.format });
  return Response.json({ url: reportUrl });
}

Expansion Signals

Send expansion signals from server-side code when customers approach usage limits.

import { getPerly } from '@perly/nextjs';

export async function POST(req: Request) {
  const perly = getPerly();

  await perly.signal('seat_limit_near', {
    current: 48,
    limit: 50,
  });

  await perly.signal('token_usage_high', {
    current: 950000,
    limit: 1000000,
    period: 'monthly',
  });

  return Response.json({ acknowledged: true });
}