Skip to content

Mapping conversion actions

Every conversion in Google Ads has two identifiers, used by two different products:

IdentifierUsed byExample
gtag conversion labelBrowser-side gtag('event', 'conversion', { send_to: ... })abcDEF1234
Ads API resource nameServer-side Ads API uploadClickConversionscustomers/1234567890/conversionActions/9876543210

These describe the same conversion in the Ads UI. They look completely different in code. Mixing them up — sending a resource name to gtag, or a label to the Ads API — fails on both sides with confusing errors.

Trackbridge keeps them in their lanes. The conversionActions map on createServerTracker is the bridge.

import { createServerTracker } from '@trackbridge/server';
createServerTracker({
// ...
ads: {
// ...
conversionActions: {
purchase: 'customers/1234567890/conversionActions/9876543210',
signup: 'customers/1234567890/conversionActions/1122334455',
lead: 'customers/1234567890/conversionActions/3344556677',
},
},
});

Keys are your friendly labels — strings you choose for your own readability. The same label you pass as label to trackConversion. They are not the gtag conversion label; they are not visible to Google.

Values are Ads API resource names in the format customers/{customerId}/conversionActions/{actionId}.

When you call:

await serverTracker.trackConversion({
label: 'purchase',
// ...
});

The server tracker looks up 'purchase' in conversionActions, gets 'customers/1234567890/conversionActions/9876543210', and sends that to the Ads API as the conversionAction field of the upload request.

The browser side does not use conversionActions. It uses the friendly label directly to construct the gtag send_to:

await tracker.trackConversion({
label: 'purchase',
// ...
});
// Internally becomes:
gtag('event', 'conversion', {
send_to: 'AW-1234567890/purchase', // ← `${adsConversionId}/${label}`
// ...
});

But wait — 'purchase' isn’t a valid gtag conversion label. Google’s gtag labels are short opaque strings like abcDEF1234.

This is the part that needs deliberate setup in the Ads UI: name your conversion action with the same string you’ll use in code. When you create the conversion action in Ads UI → Tools & Settings → Measurement → Conversions, give it a clear name (e.g. “Purchase”), and configure its conversion label to match — or, more commonly, give the Ads action a normal name and configure the gtag to fire on a friendly identifier you choose.

The cleanest setup is to use the same string in three places:

  1. The key in conversionActions map: 'purchase'.
  2. The label you pass to both tracker.trackConversion and serverTracker.trackConversion: 'purchase'.
  3. The gtag label configured in the Ads UI for that conversion action: 'purchase'.

When all three match, your code stays readable, the dual-send pairs up correctly, and Google sees consistent identifiers from both sides.

In the Ads UI:

  1. Tools & SettingsMeasurementConversions.
  2. Click into the conversion action you want to map.
  3. Open the Tag setup view, then choose Use Google Tag Manager or Use the Google tag — both expose the resource name (look for “Conversion ID” + “Conversion label” or the API resource path, depending on UI version).

If you can’t find it in the UI, query the Ads API directly:

Terminal window
curl -X POST \
-H "Authorization: Bearer <accessToken>" \
-H "developer-token: <devToken>" \
-H "Content-Type: application/json" \
https://googleads.googleapis.com/v17/customers/1234567890/googleAds:searchStream \
-d '{
"query": "SELECT conversion_action.id, conversion_action.name FROM conversion_action"
}'

The resource name is customers/1234567890/conversionActions/<conversion_action.id>.

When you ship a new event (say, “lead”):

  1. Create the conversion action in Ads UI. Name it Lead. Give it a friendly identifier you’ll use in code — lead.

  2. Find its resource name (or API ID).

  3. Add to conversionActions:

    conversionActions: {
    purchase: 'customers/1234567890/conversionActions/9876543210',
    signup: 'customers/1234567890/conversionActions/1122334455',
    lead: 'customers/1234567890/conversionActions/3344556677', // new
    },
  4. Call tracker.trackConversion({ label: 'lead', /* ... */ }) and serverTracker.trackConversion({ label: 'lead', /* ... */ }) from your application code.

If you forget step 3, the server side throws at call time:

Error: [trackbridge] no conversionAction configured for label "lead" — add it to ads.conversionActions on createServerTracker
  • Resource name passed as gtag label: the browser-side send_to becomes AW-1234567890/customers/.../conversionActions/..., which Ads doesn’t recognize. The browser fire is silently lost (or, with debug: true, gtag may emit its own warning).
  • Friendly label passed to Ads API: the server-side Ads API rejects with INVALID_CONVERSION_ACTION_RESOURCE_NAME. With debug: true, you’ll see the rejection in your logs.

The map prevents both, as long as you put the right string in the right slot.