X Ads
Send website conversions to X (formerly Twitter) through the X Ads Conversion API.
Why route X Ads through Datafly Signal
- Conversions survive ad blockers and tracking prevention. Signal sends the event from your own infrastructure, so the conversions X optimises against are not filtered by the browser.
- Identifiers are hashed before they leave your infrastructure. Signal normalises and applies SHA-256 inside your own deployment, so X receives match keys, not raw personal data.
- Click and cookie identifiers are captured first-party and replayed on later conversions, so attribution survives when the landing-page cookie has expired.
- One consent decision governs every destination. X is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
- Presets for Retail, Travel, Media and Insurance. The mapping starts from a working configuration for your vertical, and every field can be changed afterwards.
Prerequisites
- An X Ads account with an X Pixel event source (Tools > Events Manager). Copy the Pixel ID.
- For each conversion type you track, create an event with Install with Conversion API (or reuse your Pixel event so X can deduplicate) and copy its Event ID (for example
tw-o8z3j-o8z3k). - In Events Manager choose Install Pixel > Manual > Conversion API > Generate access token and copy the Conversion API access token. No developer app or OAuth signing is needed.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
pixel_id | string | Yes | The ID of your X Pixel event source, from X Ads Manager > Tools > Events Manager. It forms the request path. |
access_token | secret | Yes | A Conversion API access token generated in Events Manager (Install Pixel > Manual > Conversion API > Generate access token). Sent as the X-Pixel-Token header. |
event_id | string | No | The Events Manager event ID used for any conversion type that has no event ID of its own below. Leave empty to send only the conversion types you configure individually; an event whose type has no event ID is not sent. |
event_id_page_view | string | No | The Events Manager event ID of your Page View conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_content_view | string | No | The Events Manager event ID of your Content View conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_add_to_cart | string | No | The Events Manager event ID of your Add to Cart conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_checkout_initiated | string | No | The Events Manager event ID of your Checkout Initiated conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_added_payment_info | string | No | The Events Manager event ID of your Added Payment Info conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_purchase | string | No | The Events Manager event ID of your Purchase conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_lead | string | No | The Events Manager event ID of your Lead conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_sign_up | string | No | The Events Manager event ID of your Sign Up conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_search | string | No | The Events Manager event ID of your Search conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_add_to_wishlist | string | No | The Events Manager event ID of your Add to Wishlist conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_download | string | No | The Events Manager event ID of your Download conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_subscribe | string | No | The Events Manager event ID of your Subscribe conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
event_id_start_trial | string | No | The Events Manager event ID of your Start Trial conversion event. Use the same event ID as your X Pixel so X can deduplicate on conversion_id. |
Configure in Signal
- In the Management UI, go to Integrations > Integration Library and select X Ads.
- Choose a preset, fill in the fields above and choose the pipelines and consent categories (advertising destinations default to marketing).
- Click Install Integration.
Or with the Management API:
curl -X POST http://localhost:8084/v1/admin/integration-catalog/x_ads/install \
-H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "X Ads", "variant": "default", "config": {"pixel_id": "o8z3j", "access_token": "..."}, "delivery_mode": "server_side"}'API endpoint
POST https://ads-api.x.com/12/measurement/conversions/{{pixel_id}}Authentication: X-Pixel-Token: <Conversion API access token> header. Allow egress to ads-api.x.com from the network your delivery workers run on.
Presets and event mapping
Every preset sends only the fields it maps (the strict output contract is on). Events not listed are not sent.
Retail (ecommerce)
Full retail funnel: page views, product and list views, search, wishlist, add to cart, checkout, payment info and purchases with contents, value, currency and the order ID as conversion ID for Pixel deduplication.
| Signal event | X event |
|---|---|
page | event ID for page_view |
view_item_list | event ID for content_view |
search | event ID for search |
view_item | event ID for content_view |
add_to_wishlist | event ID for add_to_wishlist |
add_to_cart | event ID for add_to_cart |
begin_checkout | event ID for checkout_initiated |
add_payment_info | event ID for added_payment_info |
purchase | event ID for purchase |
sign_up | event ID for sign_up |
generate_lead | event ID for lead |
Travel (travel)
Travel funnel: destination, flight and hotel searches, listing views and saves, booking start, payment and completed bookings, and leads.
| Signal event | X event |
|---|---|
page | event ID for page_view |
search | event ID for search |
destination_searched | event ID for search |
flight_searched | event ID for search |
hotel_searched | event ID for search |
listing_viewed | event ID for content_view |
view_item | event ID for content_view |
listing_saved | event ID for add_to_wishlist |
booking_started | event ID for checkout_initiated |
begin_checkout | event ID for checkout_initiated |
add_payment_info | event ID for added_payment_info |
purchase | event ID for purchase |
booking_completed | event ID for purchase |
generate_lead | event ID for lead |
Media (media)
Publisher and subscription funnel: content views, sign-ups, leads, podcast and paid subscriptions.
| Signal event | X event |
|---|---|
page | event ID for page_view |
content_viewed | event ID for content_view |
view_item | event ID for content_view |
generate_lead | event ID for lead |
sign_up | event ID for sign_up |
podcast_subscribed | event ID for subscribe |
begin_checkout | event ID for checkout_initiated |
purchase | event ID for subscribe |
subscription_renewed | event ID for subscribe |
Default (default)
X Conversion API core funnel: page views, content views, search, add to cart, checkout, leads, sign-ups and purchases, matched on the X click ID, hashed email and phone, IP and user agent. Each conversion type is routed to the Events Manager event ID configured for it.
| Signal event | X event |
|---|---|
page | event ID for page_view |
view_item | event ID for content_view |
search | event ID for search |
add_to_cart | event ID for add_to_cart |
begin_checkout | event ID for checkout_initiated |
generate_lead | event ID for lead |
sign_up | event ID for sign_up |
purchase | event ID for purchase |
Insurance (insurance)
Insurance quote and policy funnel: quote requests and leads as Lead conversions (the Signal event name in description), checkout, payment info and policy purchases as Purchase with the policy number as conversion ID.
| Signal event | X event |
|---|---|
page | event ID for page_view |
view_item | event ID for content_view |
get_quote | event ID for lead |
quote_requested | event ID for lead |
generate_lead | event ID for lead |
lead_submitted | event ID for lead |
begin_checkout | event ID for checkout_initiated |
add_payment_info | event ID for added_payment_info |
purchase | event ID for purchase |
policy_purchased | event ID for purchase |
sign_up | event ID for sign_up |
Identity and hashing
| X field | Signal source | Treatment |
|---|---|---|
identifiers[0].hashed_email | $traits.email | trim, lowercase, SHA-256 |
identifiers[0].hashed_phone_number | $traits.phone | E.164, SHA-256 |
identifiers[0].twclid | twclid click ID | sent as captured |
identifiers[0].ip_address, user_agent | visitor request | only with another identifier |
Email, phone and names come from datafly.identify() traits (a legacy properties.email / properties.phone is read when no trait is set). Raw personal data is never sent.
Deduplication and consent
event_id is the Events Manager event ID of the conversion type, read from the per-type Event ID field or the Default Event ID. An event whose type has no event ID is not sent. conversion_id carries the Signal event ID, or the order ID on purchases, and must match the Pixel’s conversion_id for deduplication.
Example: purchase (Default preset)
datafly.identify('crm-user-7', { email: 'jane.doe@example.com', phone: '07700 900123', first_name: 'Jane', last_name: 'Doe' });
datafly.track('purchase', {
transaction_id: 'T_1001', value: 139.99, currency: 'GBP',
items: [
{ item_id: 'SKU_1', item_name: 'Helmet', item_category: 'Motorbike', item_brand: 'Shoei', price: 120.00, quantity: 2 },
{ item_id: 'SKU_2', item_name: 'Gloves', price: 19.99, quantity: 1 }
]
});Request Signal sends (rendered from the preset):
{
"conversions": [
{
"contents": [
{
"content_id": "SKU_1",
"content_name": "Helmet",
"content_price": 120,
"content_type": "Motorbike",
"num_items": 2
},
{
"content_id": "SKU_2",
"content_name": "Gloves",
"content_price": 19.99,
"num_items": 1
}
],
"conversion_id": "T_1001",
"conversion_time": "2025-09-22T00:13:20.123Z",
"event_id": "tw-o8z3j-purch",
"event_source_url": "https://shop.example.co.uk/p/123?utm_source=x",
"identifiers": [
{
"hashed_email": "86e0b9e56c17cc4d12387e1949b85053fbe73bc3ce5a1188713a9d300cc6133d",
"hashed_phone_number": "a8acc3a90a7b4e4dc65e93db9240ed26523050ef754d63b75b5161de76781436",
"ip_address": "203.0.113.7",
"twclid": "twclick",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
}
],
"number_items": 2,
"price_currency": "GBP",
"value": 139.99
}
]
}Known limitations
number_itemsis the number of order lines, not the unit total (#1389).
Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
401 / 403 | Invalid, expired or under-privileged credential | Re-issue the credential described under Prerequisites and update the integration. |
400 | A field the vendor rejects | Open the event in the Delivery Log; the vendor’s message names the field. |
| Event dead-lettered with a required-field error | A value the vendor requires is missing (for example currency and value on a purchase) | Send the property in the track() call, or map it in the integration. |
| Low match rate | Few identifiers | Call datafly.identify() with email and phone when you know them, and keep click-ID capture enabled. |
Vendor reference: https://docs.x.com/x-ads-api/measurement/web-conversions.