Skip to content

readEnvelopeFromRequest()

Reads the auto-captured first-party Trackbridge / GA cookies and an optional x-trackbridge-context JSON header from a Next.js request, returning a TrackbridgeContext envelope ready for serverTracker.fromContext().

The use case: server-side conversions where the user’s session cookies travel with the request but you don’t want to plumb a separate envelope payload through every API call.

import { readEnvelopeFromRequest } from '@trackbridge/sdk/next/server';
function readEnvelopeFromRequest(args: ReadEnvelopeFromRequestArgs): TrackbridgeContext | null;
type ReadEnvelopeFromRequestArgs = {
headers: HeaderReader;
cookies: CookieReader;
};
type CookieReader = { get(name: string): { value: string } | undefined };
type HeaderReader = Pick<Headers, 'get'>;

CookieReader is compatible with both Next’s ReadonlyRequestCookies (returned by cookies() in App Router) and a synthesized stand-in for tests. HeaderReader is compatible with both ReadonlyHeaders and the global Headers.

  1. Reads _tb_gclid, _tb_gbraid, _tb_wbraid from cookies → clickIds.
  2. Reads _ga cookie and parses GA4 client ID (GA1.<v>.<rand>.<timestamp>) → clientId.
  3. Reads x-trackbridge-context header. If present and valid JSON, parses it as a TrackbridgeContext.
  4. Merges header over cookie (header wins per field). Required clickIds and consent are filled in from cookies or default to empty / 'unknown'.
  5. Returns null if neither cookies nor header carry any usable data.

The default consent (when nothing else supplies it) is 'unknown' for all four signals — not 'denied'. The server is reconstructing state, not asserting it; 'unknown' is the honest default and lets the consumer pass an explicit consent via the header if needed.

app/api/orders/route.ts
import { cookies, headers } from 'next/headers';
import { readEnvelopeFromRequest } from '@trackbridge/sdk/next/server';
import { getServerTracker } from '@/lib/tracker.server';
export async function POST(req: Request) {
const order = await createOrder(await req.json());
const envelope = readEnvelopeFromRequest({
cookies: cookies(),
headers: headers(),
});
if (envelope !== null) {
const bound = getServerTracker().fromContext(envelope);
const result = await bound.trackPurchase({
transactionId: order.id,
value: order.total,
currency: order.currency,
items: order.items,
});
if (!result.ads.ok && !('skipped' in result.ads)) reportError(result.ads.error);
}
return Response.json({ order });
}

When to send the x-trackbridge-context header

Section titled “When to send the x-trackbridge-context header”

Most of the data you need (clickIds, clientId) is in cookies that the browser sends automatically. The header is for the cases cookies can’t cover:

  • Pre-login userData that the consumer wants the server to use — emit it from a fetch call:
    await fetch('/api/orders', {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'x-trackbridge-context': JSON.stringify(tracker.exportContext({
    userData: { email: form.email },
    })),
    },
    body: JSON.stringify(order),
    });
  • Cross-origin requests where cookies are blocked but headers go through.
  • Explicit consent state the server should respect for this call.

The header is parsed as TrackbridgeContext (the same shape tracker.exportContext() produces). Malformed JSON is silently treated as absent — the function does not throw on bad input.