---
title: Ad platforms
description: The 29 ad platforms Retidal reports conversions to, and how a business event becomes a platform-native conversion callback.
---

Once an event is attributed to a click (see
[Cross-device attribution](/docs/attribution/cross-device)), Retidal can report
it back to the ad platform that click came from as a conversion — closing the
loop between spend and outcome. This page covers the supported platforms and how
your event name gets translated into what each platform actually expects.

## Prerequisites

- Events sent with [Click IDs](/docs/sending-data/click-ids) attached, so there is a click
  to report a conversion back to.
- A project event mapping configured on
  [Event mappings](/docs/sending-data/event-mappings) (`Console → Projects → Event
  Mappings`) — postback cannot happen for an event with no standard-event mapping.

## Three-layer event mapping

Retidal never sends your raw `eventName` to an ad platform. It goes through
three layers:

<Steps>
  <Step title="Project mapping (per-project, configured in the console)">
    Your business event name is mapped to one of Retidal's 17 standard events.
    For example, `user_paid` → `PURCHASE`. Configured per project in **Project
    settings → Event mapping**; changes take up to a minute to take effect
    (the mapping is cached for 1 minute).
  </Step>
  <Step title="Platform mapping (built in, no configuration needed)">
    The standard event is translated to each platform's native event
    identifier. For example, `PURCHASE` becomes Baidu's `"3"`, Meta's
    `"Purchase"`, or Google's `"PURCHASE"`.
  </Step>
  <Step title="Pixel-level override (optional)">
    An individual ad pixel's configuration can override the platform-level
    default for a specific standard event — for example, overriding a
    particular Baidu pixel's `PURCHASE` mapping from the default `"3"` to
    `"19"`.
  </Step>
</Steps>

```
"user_paid" (your event name)
  → PURCHASE (layer 1: project mapping)
  → pixel override present? use it : platform default (layer 2/3)
  → "3" (Baidu) / "Purchase" (Meta) / "PURCHASE" (Google)
  → sent to the platform asynchronously via Cloudflare Queues
```

<Note>
  The sources for this integration document the mapping *mechanism* and these
  three worked examples (Baidu, Meta, Google → `PURCHASE`), not a complete
  matrix of all 17 standard events against all 29 platforms' native event
  names. Not every platform necessarily supports every standard event — check
  a pixel's configuration in the console for what it accepts.
</Note>

## The 17 standard events

Your project event mapping (layer 1 above) always maps into one of these, grouped
by AARRR stage. Events marked "amount" should carry `properties.amount` in minor
units — Retidal forwards it to the platform automatically.

| Stage | Event | Amount | Description |
| --- | --- | --- | --- |
| Acquisition | `REGISTRATION` | | User completes registration |
| Acquisition | `LEAD` | | User submits a lead / inquiry form |
| Acquisition | `FORM_SUBMIT` | | User submits any form |
| Acquisition | `APP_INSTALL` | | User installs the app |
| Activation | `APP_ACTIVATE` | | User opens the app for the first time |
| Activation | `COMPLETE_TUTORIAL` | | User completes onboarding |
| Engagement | `PAGE_VIEW` | | User views a page |
| Engagement | `CONTENT_VIEW` | | User views specific content |
| Engagement | `SEARCH` | | User performs a search |
| Engagement | `SHARE` | | User shares content |
| Monetization | `ADD_TO_CART` | ✓ | User adds an item to cart |
| Monetization | `CHECKOUT` | ✓ | User begins checkout |
| Monetization | `PURCHASE` | ✓ | User completes a purchase |
| Monetization | `SUBSCRIBE` | ✓ | User starts a subscription |
| Monetization | `SUBSCRIBE_RENEW` | ✓ | User renews a subscription |
| Retention | `LOGIN` | | User logs in |
| Retention | `RE_ENGAGE` | | User becomes active again after a gap |

## The 29 supported platforms

| Category | Platform | Click ID parameter(s) |
| --- | --- | --- |
| Domestic (CN) | Baidu oCPC | `bd_vid` |
| Domestic (CN) | Douyin / Oceanengine | `clickid` |
| Domestic (CN) | Tencent Ads | `gdt_vid` |
| Domestic (CN) | Kuaishou | `callback` |
| Domestic (CN) | Kuaishou KWAI | `clickid` |
| Domestic (CN) | Xiaohongshu | `xhs_click_id` |
| Domestic (CN) | Bilibili | `buvid` |
| Domestic (CN) | Weibo | `weibo_cid` |
| International | Google Ads | `gclid` / `gbraid` / `wbraid` |
| International | Google Measurement (GA4 MP) | `client_id` (SDK `clickIds` only) |
| International | Meta / Facebook | `fbclid` |
| International | TikTok | `ttclid` |
| International | Microsoft / Bing Ads | `msclkid` |
| International | Twitter / X Ads | `twclid` |
| International | LinkedIn Ads | `li_fat_id` |
| International | Snapchat Ads | `ScCid` |
| International | Pinterest Ads | `epik` |
| International | Bigo | `bbg` |
| Programmatic | TrafficStars / Xiaobu | `click_id` |
| Programmatic | TrafficJunky | `aclid` |
| Programmatic | PropellerAds | `subid` |
| Programmatic | DeepClick | `abclid` |
| Programmatic | Mgsky | `pixel_click_id` |
| Attribution / traffic | Adjust | `adid` / `gps_adid` |
| Attribution / traffic | OkSpin | `tkid` |
| Attribution / traffic | Snaptube | `globalId` |
| Attribution / traffic | AppLuck | `clickId` |
| Attribution / traffic | Macan | `clk_id` |

Field-level detail on how to attach these Click IDs to events lives on
[Click IDs](/docs/sending-data/click-ids).

## Delivery

Conversion callbacks are sent to platforms asynchronously via Cloudflare
Queues, after event ingestion and attribution resolution have completed — this
happens automatically once a project event is mapped and the relevant pixel is
configured, no separate API call needed.

## What this unlocks

Once a business event maps to a standard event and a pixel is configured, postbacks flow
without any further API call. What that unlocks downstream is spend-to-conversion
reporting: [data queries](/docs/console/queries) can then close the
clicks → visits → events → conversions → postback funnel and report conversions against
total spend, which is what makes ROAS and CPA answerable.

(The [event mapping](/docs/sending-data/event-mappings) and the
[Click ID](/docs/sending-data/click-ids) on the attributed event are the upstream
prerequisites for that, not the payoff.)

## Verify it worked

<Steps>
  <Step title="Confirm the project mapping is live">
    Console → Projects → Event Mappings, or, from a browser session already logged
    into the console (so the `trackly_session` cookie is sent automatically) — these
    are **Management API** calls, host `https://retidal.com`:
    ```bash
    curl -s https://retidal.com/api/projects/{projectId}/event-mappings \
      -H "Cookie: trackly_session=$SESSION_COOKIE"
    # expect: 200 { "mappings": [...] } with your appEventName mapped to the
    # target standard event (e.g. PURCHASE)
    ```
  </Step>
  <Step title="Confirm the pixel is configured">
    ```bash
    curl -s https://retidal.com/api/projects/{projectId}/platforms \
      -H "Cookie: trackly_session=$SESSION_COOKIE"
    # expect: 200 { "platforms": [...] } containing the pixel, "isActive": true
    ```
  </Step>
  <Step title="Confirm the platform-side conversion">
    In a sandbox/test project only, send one mapped test purchase event with a
    valid Click ID for that platform (see [Click IDs](/docs/sending-data/click-ids)),
    then check the platform's own ads dashboard for the conversion 24–48 hours later
    (platform-side reporting lag, not a Retidal delay). Do not use a mapped conversion
    event name against a production project purely to test this — it reports a real
    (fake) conversion to the platform.
  </Step>
</Steps>

## If it doesn't work

If the standard-event mapping or platform postback fails, so the ad platform never
credits the conversion, work through
[Conversions failing](/docs/troubleshooting/conversions-failing).

## Worked example

A `user_paid` event mapped to `PURCHASE`, reported to a Baidu oCPC pixel with a
pixel-level override. First, the project mapping (see
[Event mappings](/docs/sending-data/event-mappings) for how to look up
`eventDefinitionId`):

```json title="POST /api/projects/{projectId}/event-mappings"
{
  "appEventName": "user_paid",
  "eventDefinitionId": "evtdef_9f2a1c"
}
```

Then the pixel-level override, on an already-configured Baidu pixel (`platformId`
`plat_7f3a9c21`) — a partial update needs only the field you're changing:

```json title="PATCH /api/projects/{projectId}/platforms/{platformId} (platformId=plat_7f3a9c21)"
{
  "eventMapping": { "PURCHASE": "19" }
}
```

With this configuration, a `user_paid` event carrying `bd_vid` in its `clickIds` maps
`user_paid` → `PURCHASE` (layer 1), then the pixel override sends Baidu's native code
`"19"` instead of the platform default `"3"` (layer 3) — the override wins because it is
more specific than the platform-level default.

<Note>
  Creating a brand-new pixel instead of updating an existing one requires the full
  `PlatformCreateRequest` — `platform`, `name`, and `credentials` are all required
  alongside the optional `eventMapping` shown above.
</Note>

## Guardrails

The 1-minute mapping cache means a project mapping change is not visible to the next
in-flight conversion until the cache entry expires — testing immediately after saving a
new mapping can look like a **missed conversion** when it is really the cache not having
rolled over yet. Wait a full minute after saving before treating a test conversion as a
mapping failure, and check the pixel's own configuration in the console before assuming
the mapping itself is wrong — a platform not supporting a given standard event produces
the same "conversion never shows up on the platform side" symptom as a broken mapping.

## Next steps

<CardGroup cols={2}>
  <Card title="Click IDs" href="/docs/sending-data/click-ids">
    Attach these platforms' Click IDs to your events.
  </Card>
  <Card title="Sending events" href="/docs/sending-data/events">
    Report the events that feed the mapping above.
  </Card>
</CardGroup>
