UTM Tracking for X (Twitter) Ads: How to Build and Validate Campaign Links

For X (Twitter) Ads, use utm_source=twitter with utm_medium=cpc. Despite the platform rebrand from Twitter to X, utm_source=twitter remains the correct value for GA4 attribution — it is the value GA4's default channel group conditions recognise for routing sessions to the Paid Social channel group. Using utm_source=x instead causes sessions to fall into "Unassigned" unless you define a custom channel group. X's t.co link shortener wraps every link in a tweet, creating a redirect chain that UTM parameters must survive — validating that chain before launch is essential.

Terminal showing mlz build command with utm_source=twitter and utm_medium=cpc, a GA4 Paid Social channel label, and the assembled tracked URL at the bottom.

Why UTM parameters matter for X (Twitter) Ads

Unlike Google Ads, X Ads does not have a universal auto-tagging mechanism that feeds session data directly into GA4. The Twitter Ads tracking system reports conversions within the X Ads dashboard, but it doesn't pass structured source and medium signals to GA4 in the way that Google's gclid integration does. Without UTM parameters on your X Ads destination URLs, GA4 typically attributes those sessions as Direct or routes them incorrectly based on the referring domain.

GA4 acquisition reporting
UTM parameters are the primary mechanism GA4 uses to populate the Traffic Acquisition report with source and medium dimensions. Without utm_source=twitter&utm_medium=cpc, paid X Ads sessions don't appear as a distinct, labeled row in your acquisition data — they blend into Direct or Other.
Cross-platform attribution consistency
If you run campaigns across X, LinkedIn, TikTok, and Google simultaneously, UTM parameters provide a consistent attribution layer. Every analytics tool — Mixpanel, Amplitude, Segment, Heap, or custom pipelines — reads UTM values directly. X Ads conversion reporting only exists inside X Ads itself.
t.co redirect chain integrity
Every link posted on X is wrapped in a t.co short URL. When a user clicks your ad, the request goes through the t.co redirect before reaching your landing page. In most configurations, t.co preserves query string parameters including UTM — but it depends on your landing page setup. A CDN redirect, URL rewrite, or landing page platform can silently strip parameters after the t.co hop. Validating the full redirect chain before launch is the only reliable way to confirm UTM parameters arrive at GA4.
Paid vs. organic separation
If you post organic content and run paid ads simultaneously on X, UTM parameters are the only way to separate paid and organic traffic in GA4. utm_medium=cpc on paid links vs. utm_medium=social on organic posts creates a clean channel split in your acquisition reports.

The correct utm_source and utm_medium for X Ads

The key decision most teams face post-rebrand is whether to use utm_source=twitter or utm_source=x. The answer is twitter — for now — because that is the value GA4's built-in channel group conditions are designed to recognise:

X campaign type utm_source utm_medium
Promoted Post (paid) twitter cpc
Promoted Video ad twitter cpc
X Amplify (pre-roll) twitter cpc
Organic post with link twitter social

GA4's default Paid Social channel group condition matches sessions where utm_source contains the platform name and utm_medium matches cpc, ppc, paid, or similar paid indicators. GA4's list of recognised social sources includes twitter — it does not yet include x as a separate recognised source. Using utm_source=x sends sessions to the "Unassigned" channel group in most GA4 configurations unless you build a custom channel group rule to match it.

For organic X posts with links, use utm_medium=social. GA4 routes utm_source=twitter&utm_medium=social to the Organic Social channel group, keeping paid and organic X traffic cleanly separated in your acquisition reports.

Building X (Twitter) UTM links with mlz build

The mlz build command generates the tagged URL and normalises all values to lowercase automatically. For X Ads, the core command is:

mlz build — paid and organic X links
# Paid X Ad (Promoted Post)
$ mlz build \
  --url "https://example.com/landing" \
  --source "twitter" \
  --medium "cpc" \
  --campaign "spring-launch-2026"

{
  "tracked_url": "https://example.com/landing?utm_source=twitter&utm_medium=cpc&utm_campaign=spring-launch-2026",
  "params": {
    "utm_source": "twitter",
    "utm_medium": "cpc",
    "utm_campaign": "spring-launch-2026"
  }
}

# Organic X post with link
$ mlz build \
  --url "https://example.com/landing" \
  --source "twitter" \
  --medium "social" \
  --campaign "product-launch"
"tracked_url": "...?utm_source=twitter&utm_medium=social&utm_campaign=product-launch"

If you run multiple creative variants — different images, different copy — pointing to the same landing page, add --content to distinguish them. For example, --content "image-a" vs --content "image-b". See the utm_content parameter guide for full details on tracking creative variants.

Add --validate to confirm the destination URL responds with HTTPS and a 200 status at build time. This catches broken landing pages before the campaign budget starts spending.

X's t.co redirect and UTM parameter survival

Every link published on X — whether in an organic post or a paid ad — is automatically wrapped in a t.co short URL. When someone clicks your X Ad, the request goes through the t.co redirect before reaching your destination page. In the typical case, t.co appends the original query string (including UTM parameters) to the final destination URL, and GA4 records the session correctly.

However, UTM parameters can still be lost after the t.co hop if:

  • Your landing page platform (e.g. HubSpot, Unbounce, Webflow) performs an internal redirect that drops query strings
  • A CDN or load balancer rewrites URLs before the request reaches your server
  • Your server-side redirect logic doesn't propagate ? query strings to the final URL
  • A vanity URL or URL shortener in your own stack strips parameters

Use mlz check to inspect the redirect chain from your X Ads destination URL before launch:

mlz check — validate the redirect chain
$ mlz check "https://example.com/landing?utm_source=twitter&utm_medium=cpc&utm_campaign=spring-launch-2026"

{
  "url": "https://example.com/landing?utm_source=twitter&utm_medium=cpc&utm_campaign=spring-launch-2026",
  "valid": true,
  "checks": [
    { "check": "url_format", "status": "pass", "message": "URL format is valid." },
    { "check": "ssl", "status": "pass", "message": "URL uses HTTPS." },
    { "check": "resolution", "status": "pass", "message": "Destination responded with 200." },
    { "check": "redirects", "status": "pass", "message": "No redirects detected." }
  ],
  "status_code": 200,
  "response_time_ms": 218
}

If the redirect check returns a warning about parameter stripping, review each hop in your URL chain. See the guide to checking if a redirect strips UTM parameters for a detailed walkthrough of diagnosing and fixing this problem.

X Ads tracking gotchas

utm_source=twitter vs utm_source=x — the naming decision
GA4's default channel group conditions recognise twitter as a social source. Using utm_source=x is technically more current (the platform is now X), but GA4 does not yet natively match x in its Paid Social or Organic Social channel group conditions. Stick with utm_source=twitter until Google updates GA4's channel definitions — or build a custom channel group rule in GA4 that includes x alongside twitter. If your organisation decides to migrate to utm_source=x, do it consistently across all links at once to avoid a split in your historical attribution data.
X's in-app browser and UTM preservation
When a user clicks an X Ad on mobile, the destination loads in X's in-app browser before potentially switching to Safari or Chrome. In most cases, the in-app browser passes UTM parameters correctly to the destination page. The more common failure point is a redirect on the destination side — not X's browser. Validate the destination URL chain (not just the initial URL) before launch.
X Ads dynamic URL parameters ({campaign_name}, {adgroup_id})
X Ads supports dynamic substitution macros like {campaign_name} in destination URLs. If you use these, place them in utm_campaign or utm_content: e.g. utm_campaign={campaign_name}&utm_content={creative_id}. Do not mix dynamic macros with the static UTM values you build with mlz build — build the static base link first, then append dynamic parameters in the X Ads destination URL field.
No gclid equivalent — UTM is your only attribution signal
Unlike Google Ads, X Ads has no automatic click ID (gclid equivalent) that integrates with GA4's native attribution. UTM parameters are the only structured attribution signal that flows from X Ads into GA4. This makes UTM accuracy more critical for X than for Google campaigns: a missing or malformed UTM parameter on an X Ad means that traffic has no attribution at all in GA4.

X (Twitter) UTM naming conventions

The same lowercase-hyphen convention that applies to all UTM parameters applies here. GA4 treats twitter and Twitter as different sources, fragmenting what should be a single channel into multiple rows in your acquisition reports. The mlz build CLI normalises all values automatically, but if you generate links in a spreadsheet or URL builder, enforce lowercase manually.

Recommended conventions for X campaigns:

  • utm_source: twitter (always lowercase — not "Twitter", "X", or "x")
  • utm_medium: cpc for paid ads, social for organic posts
  • utm_campaign: lowercase hyphen-separated, e.g. spring-launch-2026
  • utm_content: creative variant identifier, e.g. image-a, video-30s

For a full cross-channel naming reference, see the UTM naming conventions guide.

FAQ

Should I use utm_source=twitter or utm_source=x now that the platform is called X?
Use utm_source=twitter. GA4's default channel group conditions still match on twitter as a known social source. Using utm_source=x causes sessions to fall into the "Unassigned" channel group because x is not yet a recognised source in GA4's built-in definitions. Until Google updates GA4 to recognise x alongside twitter, stick with twitter for consistent Paid Social attribution. If your team wants to future-proof, add a custom channel group condition in GA4 to match both twitter and x.
Does X's t.co shortener always preserve UTM parameters?
The t.co redirect itself generally preserves UTM parameters — it passes the full query string to the destination URL. The risk is not the t.co hop but what happens after it: any redirect on your own infrastructure (CDN, landing page platform, vanity URL) can strip parameters. Always validate the destination URL with mlz check before your campaign goes live, particularly if your landing page uses a custom domain that redirects to another URL.
Do I need UTM parameters if I'm using X Ads conversion tracking?
X Ads conversion tracking (via the X Pixel or App Events API) reports conversions within the X Ads dashboard. It does not feed structured source and medium attribution data into GA4. If GA4 is your primary analytics source — or if you use any analytics tool outside of X Ads — UTM parameters are the only way to get session-level attribution from X campaigns into your analytics platform. Even if you only use GA4, UTM parameters make the Traffic Acquisition report readable: utm_source=twitter / cpc is immediately interpretable, while traffic attributed via X's tracking pixel only shows up in GA4 if the landing page fires a GA4 event with the right source data.
Can I use utm_term for X Ads?
utm_term is designed for paid search keywords — the specific keyword that triggered an ad. X Ads targeting is audience-based, not keyword-triggered, so utm_term doesn't have a natural use for standard X Ads campaigns. Some teams use it to tag audience segments (e.g. utm_term=lookalike-q2) but this is non-standard. For X Ads, prefer utm_content for creative variant tracking and leave utm_term blank unless you have a specific reason to use it.
What if I use a link shortener in addition to t.co?
If you paste a pre-shortened URL (e.g. from Bitly or Rebrandly) into your X Ad, the redirect chain becomes: t.co → your shortener → destination. Each hop is an opportunity for parameters to be dropped. Validate the full chain end-to-end with mlz check before launch. See the UTM links + link shortening guide for guidance on how to safely combine UTM parameters with link shorteners.

Build X (Twitter) UTM links from the terminal

Pass --source "twitter" --medium "cpc" to mlz build and get a normalised, validated URL ready for your X Ads destination field. Lowercase formatting ensures GA4 routes every session to the Paid Social channel group correctly — and mlz check confirms UTM parameters survive the full redirect chain before your campaign goes live.

npm install -g missinglinkz

Free plan: 50 links/month. No credit card. See the UTM tracking for developers guide for the full programmatic workflow.