X (Twitter) Conversions API
Server-side event delivery to X's (Twitter's) Conversions API for enhanced ad attribution and privacy-compliant conversion tracking.
X Conversions API is a server destination in the walkerOS flow:
Sends conversion events server-side to X's Conversions API, bypassing browser limitations for improved data quality. Deduplicates with the browser-side X Pixel via `conversion_id`.
Installation
npm install @walkeros/server-destination-twitter- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationTwitter } from '@walkeros/server-destination-twitter';
await startFlow({
destinations: {
twitter: {
code: destinationTwitter,
config: {
settings: {
pixelId: 'YOUR_PIXEL_ID',
eventId: 'tw-xxxxx-xxxxx',
consumerKey: 'YOUR_CONSUMER_KEY',
consumerSecret: 'YOUR_CONSUMER_SECRET',
accessToken: 'YOUR_ACCESS_TOKEN',
accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"twitter": {
"package": "@walkeros/server-destination-twitter",
"import": "destinationTwitter",
"config": {
"settings": {
"pixelId": "YOUR_PIXEL_ID",
"eventId": "tw-xxxxx-xxxxx",
"consumerKey": "YOUR_CONSUMER_KEY",
"consumerSecret": "YOUR_CONSUMER_SECRET",
"accessToken": "YOUR_ACCESS_TOKEN",
"accessTokenSecret": "YOUR_ACCESS_TOKEN_SECRET"
}
}
}
}Configuration
This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.
Settings
| Property | Type | Description | More |
|---|---|---|---|
pixelId | string | X Pixel ID used in the Conversions API endpoint URL | |
eventId | string | Default pre-registered conversion event ID | |
consumerKey | string | OAuth 1.0a API Key (Consumer Key) for X Ads API | |
consumerSecret | string | OAuth 1.0a API Key Secret (Consumer Secret) | |
accessToken | string | OAuth 1.0a User Access Token | |
accessTokenSecret | string | OAuth 1.0a User Access Token Secret | |
apiVersion | string | X Ads API version number | |
doNotHash | Array<string> | Array of user data fields that should not be hashed | |
url | string | Custom base URL for the X Conversions API endpoint | |
user_data | Record<string, string> | Mapping configuration for user identifiers |
Mapping
Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
| Property | Type | Description | More |
|---|---|---|---|
eventId | string | Override the default conversion event ID for this event | |
value | string | number | Conversion monetary value (sent to X as a string) | |
currency | string | ISO 4217 currency code | |
number_items | integer | Number of items in the conversion | |
description | string | Free-text description of the conversion |
Examples
Lead
A form submission is sent to X as a conversion with the SHA-256 hashed email as the identifier.
{
"name": "form submit",
"data": {
"string": "foo",
"number": 1,
"boolean": true,
"array": [
0,
"text",
false
]
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"email": "user@example.com"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000901000",
"trigger": "test",
"entity": "form",
"action": "submit",
"timestamp": 1700000901000,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}sendServer("https://ads-api.x.com/12/measurement/conversions/o8z6j", "{\"conversions\":[{\"conversion_time\":\"2023-11-14T22:28:21.000Z\",\"event_id\":\"tw-o8z6j-o8z21\",\"identifiers\":[{\"hashed_email\":\"b4c9a289323b21a01c3e940f150eb9b8c542587f1abfd8f0e1cc1ffc5e475514\"}],\"conversion_id\":\"ev-1700000901000\"}]}", {
"headers": {
"Authorization": "<OAUTH_SIGNATURE>",
"Content-Type": "application/json"
}
})Purchase
A completed order is sent to the X (Twitter) Conversions API with conversion value and the hashed email.
{
"name": "order complete",
"data": {
"total": 249.99,
"currency": "EUR"
},
"context": {
"shopping": [
"complete",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"email": "jane@example.com"
},
"nested": [
{
"entity": "product",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "product",
"data": {
"id": "cc",
"name": "Cool Cap",
"size": "one size",
"price": 42
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "gift",
"data": {
"name": "Surprise"
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
}
],
"consent": {
"functional": true
},
"id": "ev-1700000900000",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000900000,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"settings": {
"value": "data.total",
"currency": {
"key": "data.currency",
"value": "EUR"
}
}
}sendServer("https://ads-api.x.com/12/measurement/conversions/o8z6j", "{\"conversions\":[{\"conversion_time\":\"2023-11-14T22:28:20.000Z\",\"event_id\":\"tw-o8z6j-o8z21\",\"identifiers\":[{\"hashed_email\":\"8c87b489ce35cf2e2f39f80e282cb2e804932a56a213983eeeb428407d43b52d\"}],\"conversion_id\":\"ev-1700000900000\",\"value\":\"249.99\"}]}", {
"headers": {
"Authorization": "<OAUTH_SIGNATURE>",
"Content-Type": "application/json"
}
})Purchase with twclid
A purchase is sent to X with both the hashed email and the twclid click id for ads attribution.
{
"name": "order complete",
"data": {
"total": 89.99,
"currency": "USD"
},
"context": {
"twclid": [
"23opevjt88psuo13lu8d020qkn",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"email": "buyer@co.com"
},
"nested": [
{
"entity": "product",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "product",
"data": {
"id": "cc",
"name": "Cool Cap",
"size": "one size",
"price": 42
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "gift",
"data": {
"name": "Surprise"
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
}
],
"consent": {
"functional": true
},
"id": "ev-1700000902000",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000902000,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"settings": {
"value": "data.total",
"currency": {
"key": "data.currency",
"value": "USD"
}
},
"data": {
"map": {
"user_data": {
"map": {
"twclid": "context.twclid"
}
}
}
}
}sendServer("https://ads-api.x.com/12/measurement/conversions/o8z6j", "{\"conversions\":[{\"conversion_time\":\"2023-11-14T22:28:22.000Z\",\"event_id\":\"tw-o8z6j-o8z21\",\"identifiers\":[{\"hashed_email\":\"484c39bfb51212665d9673805c112b5ba04cbf0460b6d3f00bcdc18b92afed66\"},{\"twclid\":\"23opevjt88psuo13lu8d020qkn\"}],\"conversion_id\":\"ev-1700000902000\",\"value\":\"89.99\"}]}", {
"headers": {
"Authorization": "<OAUTH_SIGNATURE>",
"Content-Type": "application/json"
}
})User identification
The destination builds an identifiers array. Each identifier is a separate single-key object in the payload. At least one primary identifier is required. Events without one are silently skipped.
Primary identifiers:
hashed_email: resolved fromevent.user.emailor auser_data.emailmapping. The email is normalized (trimmed, lowercased) and SHA-256 hashed before sending. SetdoNotHash: ['email']if you are pre-hashing upstream.hashed_phone_number: resolved fromevent.user.phoneor auser_data.phonemapping. SHA-256 hashed. UsedoNotHash: ['phone']to skip.twclid: X click ID (pass-through, not hashed). Typically forwarded from the browser session:
"settings": {
"pixelId": "$env.TWITTER_PIXEL_ID",
"eventId": "$env.TWITTER_EVENT_ID",
"user_data": {
"twclid": "context.twclid"
}
}Secondary identifiers (optional): ip_address, user_agent, pass-through.
Per-event overrides
The default eventId from settings applies to all events. Override it per event via mapping to route different events to different pre-registered conversion events:
"mapping": {
"order": {
"complete": {
"settings": {
"eventId": { "value": "tw-o8z6j-purchase01" },
"value": "data.total",
"currency": { "key": "data.currency", "value": "EUR" },
"number_items": "data.count"
}
}
}
}Browser deduplication
When running both the browser-side X Pixel and this server destination, the walkerOS event id is sent as conversion_id on both sides. X deduplicates conversions that share the same conversion_id and conversion event, so only one conversion is counted.