createServerTracker()
The server tracker. Sends GA4 events via the Measurement Protocol and Google Ads conversions via the Ads API. Manages the OAuth refresh-token / access-token cycle internally — you give it a refresh token once, it handles the rest.
Import only from server-side code. The credentials this takes must never reach the browser.
Signature
Section titled “Signature”import { createServerTracker } from '@trackbridge/server';
function createServerTracker(config: ServerTrackerConfig): ServerTracker;ServerTrackerConfig
Section titled “ServerTrackerConfig”type ServerTrackerConfig = { ga4MeasurementId: string; ga4ApiSecret: string; ads?: ServerAdsConfig; debug?: boolean; fetch?: typeof globalThis.fetch; now?: () => number; generateTransactionId?: () => string;};
type ServerAdsConfig = { developerToken: string; customerId: string; refreshToken: string; clientId: string; clientSecret: string; loginCustomerId?: string; conversionActions: Record<string, string>; /** Default: 'v17'. */ apiVersion?: string;};| Field | Required | Notes |
|---|---|---|
ga4MeasurementId | yes | The GA4 property of the form G-XXXXXXXXXX. |
ga4ApiSecret | yes | The Measurement Protocol API secret minted in GA4 Admin → Data streams. |
ads | no | Required to call serverTracker.trackConversion. Omit for GA4-events-only setups. |
ads.developerToken | yes (if ads) | Google Ads developer token from your manager (MCC) account. |
ads.customerId | yes (if ads) | Customer ID, digits only — 1234567890, not 123-456-7890. |
ads.refreshToken | yes (if ads) | Long-lived OAuth refresh token. Best obtained from a Workspace account, not personal. |
ads.clientId | yes (if ads) | OAuth client ID from Google Cloud Console. |
ads.clientSecret | yes (if ads) | OAuth client secret. |
ads.loginCustomerId | no | Manager (MCC) ID, digits only. Only required if your MCC sits between the access-granted account and the customer account. |
ads.conversionActions | yes (if ads) | Mapping from your friendly labels to Ads API resource names. See Mapping conversion actions. |
ads.apiVersion | no, default 'v17' | The Ads API version segment in the request URL. |
debug | no, default false | When true, non-2xx responses and network errors are logged via console.warn. The auto-transactionId warning fires regardless. |
fetch | no, default globalThis.fetch | Test seam. |
now | no, default Date.now | Test seam. |
generateTransactionId | no | Test seam. Default: tb_${crypto.randomUUID()}. |
Returns
Section titled “Returns”type ServerTracker = { trackEvent(input: ServerEventInput): Promise<void>; trackConversion(input: ServerConversionInput): Promise<void>;};See:
Behavior on initialization
Section titled “Behavior on initialization”If ads is configured, the constructor wires an OAuth access-token provider (which will refresh on first use, then cache until ~60 seconds before expiry) and an Ads API client. No network requests fire at init — the first trackConversion call triggers the first refresh.
The constructor itself never throws on unreachable APIs or invalid credentials; those failures surface at call time.
Errors
Section titled “Errors”Throws synchronously at init if either of these is missing:
Error: [trackbridge] ga4MeasurementId is requiredError: [trackbridge] ga4ApiSecret is requiredtrackConversion throws at call time if ads is not configured, or if the label you pass isn’t in the conversionActions map. See trackConversion.
Example
Section titled “Example”import 'server-only';import { createServerTracker } from '@trackbridge/server';
export const serverTracker = createServerTracker({ 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: 'customers/1234567890/conversionActions/9876543210', signup: 'customers/1234567890/conversionActions/1122334455', }, }, debug: process.env.NODE_ENV !== 'production',});The import 'server-only' line is the cheapest insurance against accidentally importing this from a client component. Next.js will fail the build; other frameworks have equivalent guards.
See also
Section titled “See also”- Setting up Google Ads OAuth — obtaining the five
ads.*values. - Mapping conversion actions — the
conversionActionsmap in detail.