Next.js
Call conversions.track() from an App Router route handler or server action. Keep platform tokens on the server — never import adscapi into a Client Component.
Install
shell
npm install adscapi
Environment
Put platform secrets in .env.local (or your host’s env UI). createAdscapi() reads process.env.
env
# .env.local (never commit real tokens) META_CAPI_TOKEN=… META_PIXEL_ID=… GA4_MEASUREMENT_ID=… GA4_API_SECRET=…
Route handler
ts
// app/api/track/route.ts
import { createAdscapi } from 'adscapi';
import { NextResponse } from 'next/server';
// Module-scope client — reuses across warm invocations.
const ads = createAdscapi();
export async function POST(request: Request) {
const body = await request.json();
const results = await ads.conversions.track({
name: body.name ?? 'purchase',
value: body.value,
currency: body.currency ?? 'USD',
transactionId: body.orderId,
user: {
email: body.email,
phone: body.phone,
ip: request.headers.get('x-forwarded-for') ?? undefined,
userAgent: request.headers.get('user-agent') ?? undefined,
fbc: body.fbc,
fbp: body.fbp,
},
clickIds: {
gclid: body.gclid,
fbclid: body.fbclid,
},
consent: {
adUserData: Boolean(body.consent?.adUserData),
adPersonalization: Boolean(body.consent?.adPersonalization),
},
});
return NextResponse.json({ results });
}Fire this from your checkout success path (server-side) after the order is confirmed. Pass raw email/phone plus any click IDs and browser cookies you captured on the client.
Server Action (optional)
ts
// app/checkout/actions.ts
'use server';
import { createAdscapi } from 'adscapi';
const ads = createAdscapi();
export async function trackPurchase(input: {
email: string;
amount: number;
orderId: string;
consent: { adUserData: boolean; adPersonalization: boolean };
}) {
return ads.conversions.track({
name: 'purchase',
value: input.amount,
currency: 'USD',
transactionId: input.orderId,
user: { email: input.email },
consent: input.consent,
});
}Staging & test events
ts
// Dry-run in preview / staging
await ads.conversions.track(event, { dryRun: process.env.VERCEL_ENV !== 'production' });
// Meta Test Events during QA
await ads.conversions.track(event, {
testEventCodes: { meta: process.env.META_TEST_EVENT_CODE! },
});Edge runtime
The dispatch path uses only fetch and WebCrypto, so it runs under export const runtime = 'edge' and on Cloudflare Workers. See the Workers guide if you deploy Next via OpenNext.