How X Ad Tracking Works
X (formerly Twitter) uses a JavaScript pixel (twq) called the Website Tag to track user behavior on advertiser websites and attribute conversions back to ad interactions on the X platform. The tracking architecture operates as follows:
- A user sees or clicks an ad on X (promoted post, video ad, carousel, or conversation ad)
- On click, X's redirect server appends a
twclid(Twitter Click ID) parameter to the destination URL - The X Website Tag JavaScript loads on the advertiser's site, reads the
twclidparameter, and stores it in a first-party cookie (_twclid) - The tag fires a
PageViewevent on each page load - When the user completes a conversion action, the tag fires the corresponding event to
analytics.twitter.com - X matches the conversion to the original ad interaction via click ID (click-through) or cookie-based matching (view-through)
X also supports a server-side Conversion API (CAPI) that sends events directly from your server to X's measurement endpoint. CAPI can be used alongside or instead of the client-side pixel.
The twclid parameter is the primary attribution key. It is a long alphanumeric string appended as a query parameter on the landing page URL. For view-through attribution, X relies on a third-party cookie set during ad impression and the first-party _twclid cookie set by the Website Tag.
Installing the X Website Tag (Pixel)
Place the base tag code in the <head> of every page. Get your pixel ID from X Ads Manager under Tools > Events Manager > Add Event Source.
<!-- X (Twitter) Website Tag - Base Code -->
<script>
!function(e,t,n,s,u,a){e.twq||(s=e.twq=function(){s.exe?s.exe.apply(s,arguments):s.queue.push(arguments);
},s.version='1.1',s.queue=[],u=t.createElement(n),u.async=!0,u.src='https://static.ads-twitter.com/uwt.js',
a=t.getElementsByTagName(n)[0],a.parentNode.insertBefore(u,a))}(window,document,'script');
twq('config', 'YOUR_PIXEL_ID');
</script>
The twq('config', ...) call automatically fires a PageView event. No separate page view call is needed.
Verification
- Open DevTools > Network tab and filter for
analytics.twitter.comorads-twitter.com - Confirm requests fire on page load
- In X Ads Manager, go to Events Manager and check the pixel status (should show "Active")
- Install the X Pixel Helper Chrome extension for real-time event debugging
Conversion Tracking
Fire conversion events by calling twq('event', 'event_id', { parameters }) after the base tag has loaded.
Creating Events in Ads Manager
Before firing events, create them in X Ads Manager:
- Navigate to Tools > Events Manager
- Click "Add Event"
- Choose the event type (Purchase, Lead, Add to Cart, etc.)
- X generates a unique event ID (e.g.,
tw-xxxxx-yyyyy) - Use this event ID in your pixel code
Standard Events
<script>
// Purchase with revenue
twq('event', 'tw-xxxxx-purchase', {
value: 119.99,
currency: 'USD',
num_items: 2,
conversion_id: 'ORD-TW-12345',
contents: [
{ content_id: 'SKU-001', content_name: 'Product A', content_price: 59.99, num_items: 1 },
{ content_id: 'SKU-002', content_name: 'Product B', content_price: 60.00, num_items: 1 }
]
});
// Lead form submission
twq('event', 'tw-xxxxx-lead', {
conversion_id: 'LEAD-67890'
});
// Sign up / Registration
twq('event', 'tw-xxxxx-signup', {
conversion_id: 'REG-11111'
});
// Add to cart
twq('event', 'tw-xxxxx-addtocart', {
value: 49.99,
currency: 'USD',
contents: [
{ content_id: 'SKU-003', content_name: 'Product C', content_price: 49.99, num_items: 1 }
]
});
// Initiate checkout
twq('event', 'tw-xxxxx-checkout', {
value: 149.99,
currency: 'USD'
});
// Content view (specific page view)
twq('event', 'tw-xxxxx-viewcontent', {
content_id: 'page-pricing'
});
// Search
twq('event', 'tw-xxxxx-search', {
search_string: 'analytics platform'
});
// App install
twq('event', 'tw-xxxxx-appinstall');
// Download
twq('event', 'tw-xxxxx-download');
</script>
Attribution Windows
Configure per-event in Events Manager:
- Post-engagement (click): 1, 7, 14, or 30 days (default 30)
- Post-view: 1, 7, 14, or 30 days (default 1)
- Post-engagement includes clicks, retweets, replies, likes, and follows on promoted content
Audience and Retargeting
Website Activity Custom Audiences
Build audiences from Website Tag data:
- In Ads Manager, go to Tools > Audiences > Create Audience
- Select "Website Activity"
- Define rules:
- All website visitors
- Visitors to specific URLs (URL contains, equals)
- Visitors who fired specific events
- Visitors with specific event parameters (e.g., purchase value > $100)
- Set lookback window (1-90 days)
- Minimum audience size: 100 matched users
List-Based Custom Audiences
Upload first-party data for matching:
# Supported identifiers (CSV, one per row):
# - Email addresses (plain text or SHA-256 hashed)
# - X @handles
# - Mobile advertising IDs (IDFA/AAID)
# - X user IDs
# Minimum list size: 100 rows
# Maximum file size: 4GB
Upload in Ads Manager under Audiences > Upload List.
Follower Lookalike Audiences
Target users similar to the followers of specific X accounts:
- Create a new audience > Follower Lookalikes
- Enter X @handles (your own or competitors)
- X builds an audience of users with similar interests and behaviors
- No minimum follower count required
Conversation and Keyword Targeting
Target users based on their X activity:
- Conversation topics: Predefined topic categories (e.g., "Technology > Artificial Intelligence")
- Keywords: Target users who recently tweeted, searched, or engaged with posts containing specific keywords
- Event targeting: Target users engaging with specific X events (conferences, sports, cultural moments)
Server-Side / Conversion API (CAPI)
X's Conversion API sends events from your server directly to X, improving attribution accuracy, especially when browsers block third-party cookies or the client-side pixel.
CAPI Setup
# Server-side conversion event via CAPI
curl -X POST 'https://ads-api.x.com/12/measurement/conversions/YOUR_PIXEL_ID' \
-H 'Content-Type: application/json' \
-H 'Authorization: OAuth oauth_consumer_key="YOUR_CONSUMER_KEY",oauth_token="YOUR_ACCESS_TOKEN",oauth_signature_method="HMAC-SHA1",oauth_timestamp="...",oauth_nonce="...",oauth_version="1.0",oauth_signature="..."' \
-d '{
"conversions": [{
"conversion_time": "2026-03-01T14:30:00Z",
"event_id": "tw-xxxxx-purchase",
"identifiers": [{
"twclid": "twclid_value_from_url",
"hashed_email": "a1b2c3d4e5f6..."
}],
"conversion_id": "ORD-CAPI-12345",
"value": 199.99,
"number_items": 3,
"price_currency": "USD",
"contents": [{
"content_id": "SKU-001",
"content_name": "Product A",
"content_price": 66.66,
"num_items": 1
}]
}]
}'
CAPI Authentication
CAPI uses OAuth 1.0a. You need:
- Consumer Key and Secret (from your X Developer App)
- Access Token and Secret (generated for your Ads account)
Generate the OAuth signature per the OAuth 1.0a specification, or use an OAuth library:
# Python example using requests-oauthlib
from requests_oauthlib import OAuth1Session
session = OAuth1Session(
client_key='YOUR_CONSUMER_KEY',
client_secret='YOUR_CONSUMER_SECRET',
resource_owner_key='YOUR_ACCESS_TOKEN',
resource_owner_secret='YOUR_ACCESS_TOKEN_SECRET'
)
response = session.post(
f'https://ads-api.x.com/12/measurement/conversions/YOUR_PIXEL_ID',
json={
'conversions': [{
'conversion_time': '2026-03-01T14:30:00Z',
'event_id': 'tw-xxxxx-purchase',
'identifiers': [{
'twclid': 'twclid_value',
'hashed_email': 'a1b2c3d4...'
}],
'conversion_id': 'ORD-99',
'value': 99.99,
'price_currency': 'USD'
}]
}
)
Deduplication Between Pixel and CAPI
When using both the Website Tag and CAPI, X deduplicates events using conversion_id. Always include the same conversion_id in both the client-side twq('event', ...) call and the server-side CAPI request.
X Ads Management API
The X Ads API enables programmatic campaign management.
Campaign Management
# List campaigns
curl -X GET 'https://ads-api.x.com/12/accounts/YOUR_ACCOUNT_ID/campaigns' \
-H 'Authorization: OAuth ...'
# Create a campaign
curl -X POST 'https://ads-api.x.com/12/accounts/YOUR_ACCOUNT_ID/campaigns' \
-H 'Authorization: OAuth ...' \
-H 'Content-Type: application/json' \
-d '{
"name": "Q1 Retargeting",
"funding_instrument_id": "YOUR_FUNDING_INSTRUMENT_ID",
"daily_budget_amount_local_micro": 50000000,
"start_time": "2026-04-01T00:00:00Z",
"entity_status": "PAUSED"
}'
Note: Budgets are specified in micros (1 USD = 1,000,000 micros).
Analytics and Reporting
# Get campaign stats
curl -X GET 'https://ads-api.x.com/12/stats/accounts/YOUR_ACCOUNT_ID?entity=CAMPAIGN&entity_ids=CAMPAIGN_ID&start_time=2026-03-01T00:00:00Z&end_time=2026-03-31T23:59:59Z&granularity=DAY&metric_groups=ENGAGEMENT,BILLING,CONVERSION_TAGS' \
-H 'Authorization: OAuth ...'
API Rate Limits
- 15 requests per 15-minute window for most endpoints
- Analytics endpoints: 100 requests per 15 minutes
- Rate limit headers included in every response:
x-rate-limit,x-rate-limit-remaining,x-rate-limit-reset
Common Issues
twclid Not Persisting
- Some CMS platforms, redirect chains, or URL shorteners strip the
twclidparameter - SPAs using client-side routing often lose query parameters on navigation:
// Capture twclid before SPA router takes over
const params = new URLSearchParams(window.location.search);
const twclid = params.get('twclid');
if (twclid) {
document.cookie = `_twclid=${twclid};max-age=${60*60*24*30};path=/;SameSite=Lax`;
}
- UTM parameters and
twclidcan conflict with URL length limits on some servers. Ensure your server accepts URLs up to 2,048 characters
Conversion Counts Higher Than Expected
- X counts post-engagement conversions, which include likes, retweets, replies, and follows. A user who liked your promoted post and later purchased gets attributed even without clicking through
- Set post-engagement windows to shorter durations (1-7 days) if this inflates numbers
- Use
conversion_idon all events to prevent duplicate counting
CAPI OAuth Signature Errors
- OAuth 1.0a signature generation is sensitive to parameter ordering and encoding
- Use a library (requests-oauthlib for Python, oauth-1.0a for Node.js) rather than building signatures manually
- Ensure your system clock is synchronized (NTP). OAuth signatures include a timestamp; clock skew over 5 minutes will fail
Website Tag Blocked by Browsers
- Safari ITP limits first-party cookie lifetime to 7 days for cookies set via JavaScript
- Firefox Enhanced Tracking Protection may block
analytics.twitter.com - Use CAPI alongside the client-side tag to fill attribution gaps from browser restrictions
Content Security Policy
script-src: static.ads-twitter.com
img-src: analytics.twitter.com t.co
connect-src: analytics.twitter.com
Platform-Specific Considerations
Post-Engagement Attribution: X attributes conversions to engagements beyond clicks, including likes, retweets, replies, quote tweets, follows, and video views (3 seconds or 100%). This is broader than most platforms and can make X appear to drive more conversions than last-click models suggest. Understand this when comparing X performance to other channels.
twclid Length: The twclid parameter can be 100+ characters. Ensure database columns, cookie storage, and URL handling can accommodate the full value without truncation.
Click ID Auto-Append: X automatically appends twclid to all ad click-through URLs. You cannot disable this behavior. If your landing page URL already has parameters, twclid is appended with &. Ensure your server-side URL parsing handles multiple query parameters correctly.
Conversion API vs Pixel Priority: When both fire for the same event, X deduplicates using conversion_id. If no conversion_id is present, both events may be counted. Always include conversion_id in both the pixel and CAPI call.
X API Versioning: The Ads API uses versioned endpoints (e.g., /12/). Check the current version in the X Developer documentation. Deprecated versions are retired with 90-day notice. Pin your integration to a specific version and update proactively.
Promoted Post Engagements Are Free: Organic engagements on promoted posts (retweets of your ad, replies to your ad) are not charged. You pay only for the initial engagement that matched your bid objective. However, all downstream engagements are tracked for attribution.