defineServerTracker()
Wraps createServerTracker in a lazy module-level singleton suitable for Next.js route handlers and Server Actions. Avoids re-constructing the tracker (and re-reading env vars) on every request.
Signature
Section titled “Signature”import { defineServerTracker } from '@trackbridge/sdk/next/server';
function defineServerTracker(configFn: () => ServerTrackerConfig): ServerTrackerFactory;
type ServerTrackerFactory = () => ServerTracker;Behavior
Section titled “Behavior”The returned factory is the entry point. On first call:
- Invokes
configFn(). - Passes the result to
createServerTracker. - Caches the resulting
ServerTrackerand returns it.
On subsequent calls, returns the cached instance without re-invoking configFn.
If configFn (or createServerTracker) throws, the error is cached and re-thrown on every subsequent call without re-invoking the factory. This prevents a misconfigured tracker from blasting the same env-var resolution on every request, and surfaces the original error verbatim. To recover, fix the config and reload the module.
Why a wrapper
Section titled “Why a wrapper”createServerTracker itself is cheap — no network calls, just builds an OAuth token provider and caches it in closure. But re-constructing it per request would mean:
- Re-reading
process.envon every request. - Re-instantiating the OAuth refresh-token cache (so every request would refresh anew).
- Re-applying any future cold-start initialization.
The singleton avoids all of that with one line of code, and matches the standard Next.js pattern for module-level resources (Prisma, Redis, etc.).
Example
Section titled “Example”import 'server-only';import { defineServerTracker } from '@trackbridge/sdk/next/server';
export const getServerTracker = defineServerTracker(() => ({ ga4MeasurementId: process.env.NEXT_PUBLIC_GA4_MEASUREMENT_ID!, ga4ApiSecret: process.env.GA4_API_SECRET!, ads: { developerToken: process.env.GOOGLE_ADS_DEVELOPER_TOKEN!, customerId: process.env.GOOGLE_ADS_CUSTOMER_ID!, refreshToken: process.env.GOOGLE_ADS_REFRESH_TOKEN!, clientId: process.env.GOOGLE_OAUTH_CLIENT_ID!, clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET!, conversionActions: { purchase: process.env.GOOGLE_ADS_PURCHASE_RESOURCE_NAME!, }, }, conversionLabels: { purchase: process.env.NEXT_PUBLIC_GOOGLE_ADS_PURCHASE_LABEL, },}));Use it from a route handler:
import { getServerTracker } from '@/lib/tracker.server';
export async function POST(req: Request) { const event = await verifyStripeSignature(req); if (event.type !== 'checkout.session.completed') return new Response();
const order = await db.orders.findByStripeId(event.data.object.id); const serverTracker = getServerTracker();
const result = await serverTracker.trackPurchase({ transactionId: order.id, value: order.total, currency: order.currency, items: order.items, clientId: order.gaClientId, gclid: order.gclid, userData: { email: order.customer.email }, });
if (!result.ads.ok && !('skipped' in result.ads)) reportError(result.ads.error); return new Response();}See also
Section titled “See also”createServerTracker()— the underlying constructor.readEnvelopeFromRequest()— companion for envelope-driven flows.- Next.js App Router setup guide