Skip to content
adscapi

conversions.track()

The core call. One canonical conversion event in; a result per configured destination out. Platforms without secrets are skipped. One platform failing never blocks the rest.

Signature

ts
import { createAdscapi } from 'adscapi';

const ads = createAdscapi(); // secrets default to process.env

const results: DestinationResult[] = await ads.conversions.track(
  event: ConversionEvent,
  opts?: TrackOptions,
);

Create the client once at process start. Secrets default to process.env; pass an explicit bag for multi-tenant use.

ts
createAdscapi(
  secrets?: AdscapiSecrets,   // default: process.env
  options?: AdscapiOptions,   // getToken, dedupe, onResult hooks
): AdscapiClient

ConversionEvent

The event shape. Pass raw PII — adscapi normalizes and SHA-256 hashes per platform. Consent is required.

FieldTypeNotes
nameCanonicalEventName | stringpage_view, lead, signup_start, signup, checkout_created, purchase, reply_generated, upgrade_clicked — or any custom string
valuenumber?Conversion value
currencystring?ISO 4217, e.g. USD
userConversionUserData?Match keys — see below
clickIdsConversionClickIds?gclid, fbclid, msclkid, ttclid, twclid, epik, sccid, li_fat_id, rdt_uuid, …
consentConversionConsentRequired. adUserData + adPersonalization booleans; optional gppString, gppSectionIds, tcfString, limitedDataUse
eventIdstring?Stable id for pixel/CAPI dedup. Auto-filled as ${name}-${eventTime}-${transactionId|email} when absent
eventTimenumber?Unix seconds
transactionIdstring?Order / checkout id
propertiesRecord<string, string | number | boolean | null | undefined>?Extra custom data forwarded where supported
testEventCodestring?Prefer TrackOptions.testEventCodes — set per destination

ConversionUserData

Every identity field you have raises match rate. All optional; all raw.

FieldType
emailstring?
phonestring?
firstNamestring?
lastNamestring?
citystring?
statestring? (region is an alias)
zipstring?
countrystring?
dateOfBirthstring?
gender'm' | 'f'
externalIdstring?
ipstring?
userAgentstring?
fbcstring?
fbpstring?

TrackOptions

OptionTypeEffect
destinationsRecord<string, boolean>?Per-call allow/deny. { meta: false } skips Meta even when configured
dryRunboolean?Log the fan-out without sending. Results come back with dryRun: true
testEventCodesRecord<string, string>?{ meta: 'TESTxxxxx' } sends a real event to that platform’s Test Events view. Platforms without a documented test param ignore it

Return — DestinationResult[]

One entry per active destination. Never throws for a single platform failure — check ok.

ts
type DestinationResult = {
  platform: string;
  ok: boolean;
  error?: string;   // set when ok === false
  dryRun?: boolean; // set when opts.dryRun
  deduped?: boolean; // set when a DedupeStore saw this eventId:platform
};

Example

ts
import { createAdscapi } from 'adscapi';

const ads = createAdscapi();

const results = await ads.conversions.track(
  {
    name: 'purchase',
    value: 49.0,
    currency: 'USD',
    transactionId: 'ord_123',
    // eventId is auto-derived when absent — set it for cross-pixel/CAPI dedup
    user: {
      email: 'jane@example.com', // raw — never pre-hash
      phone: '+1 415 555 0100',
      firstName: 'Jane',
      lastName: 'Doe',
      city: 'San Francisco',
      state: 'CA',
      zip: '94107',
      country: 'US',
      ip: req.ip,
      userAgent: req.headers['user-agent'],
      fbc: cookies._fbc,
      fbp: cookies._fbp,
    },
    clickIds: {
      gclid: body.gclid,
      fbclid: body.fbclid,
      msclkid: body.msclkid,
      ttclid: body.ttclid,
    },
    consent: {
      adUserData: true,
      adPersonalization: true,
      // optional:
      // gppString, gppSectionIds, tcfString, limitedDataUse
    },
  },
  {
    // dryRun: true,                          // log fan-out, send nothing
    // testEventCodes: { meta: 'TESTxxxxx' }, // real event → Test Events view
    // destinations: { tiktok: false },       // skip one platform this call
  },
);

// One platform failing never throws — inspect per destination.
for (const r of results) {
  if (!r.ok) console.error(r.platform, r.error);
}

Also on the client

ts
// Which platforms are active right now?
ads.destinations.list();
// → [{ key: 'meta', support: 'real-capi', active: true }, …]

// Live credential check (hits each platform API)
await ads.destinations.verify();
await ads.destinations.verify(['meta', 'tiktok']); // optional filter

Related