UTM Tracking for ChatGPT Ads in GA4
TL;DR: Without UTM parameters, GA4 lumps every ChatGPT Ads click into one chatgpt / cpc bucket. Tag utm_source=chatgpt, utm_medium=cpc, and at minimum a distinct utm_campaign per campaign, and the traffic lands in Paid Other. UTMs feed GA4 and are separate from OpenAI's pixel and oppref. Ads Manager has a beta "Landing page query parameters" feature with ID macros, but confirm it exists in your account first, since static hand-typed UTM URLs work either way.
If you're running ChatGPT Ads without UTM parameters on your destination URLs, GA4 has no way to tell your campaigns apart. Every click shows up as the same session source and medium, chatgpt / cpc, whether it came from your $50/day brand campaign or a $2,000/day prospecting campaign. That's close to useless for deciding where to put budget. UTM parameters fix this by writing the campaign, ad group, and ad identity directly into the URL, so GA4 can split that one bucket into something you can actually act on.
This is a different piece of tracking from the OpenAI Pixel and oppref click reference covered in setting up conversion tracking on OpenAI Ads Manager. That post is about OpenAI's own ad-platform attribution. This one is about GA4's session attribution. They run side by side and don't replace each other, more on that distinction below.
UTMs and oppref are two separate systems, not two ways of doing the same thing
It's easy to assume these overlap, so it's worth being explicit up front.
opprefis OpenAI's own click reference, appended automatically to your landing page URL by the OpenAI Pixel and used inside OpenAI Ads Manager's own reporting and Conversions API matching. You don't add it yourself, and it has nothing to do with GA4.- UTM parameters (
utm_source,utm_medium,utm_campaign,utm_content,utm_term, and the optionalutm_id) are the parameters GA4 (and most other analytics tools) reads to populate its own session source, medium, campaign, ad content, and term dimensions. OpenAI Ads Manager does not add these for you unless you configure it to.
You need both if you want OpenAI's reporting and GA4's reporting to each work correctly. Neither substitutes for the other.
What utm_source and utm_medium actually control in GA4
GA4 doesn't have a "ChatGPT Ads" channel built in. It assigns every session to a channel using rules that check utm_source, utm_medium, and sometimes utm_campaign. Get the medium wrong and your paid traffic either lands in Unassigned (useless) or, worse, gets miscategorized as something like AI-referral traffic that isn't paid at all.
Google's own default channel group rules (verify these haven't changed since this was written, Google does update them) define Paid Other as any session where the medium matches the pattern ^(.*cp.*|ppc|retargeting|paid.*)$ and the source doesn't match a recognized search, social, or shopping source list. cpc matches that pattern (it contains "cp"), and chatgpt isn't on any recognized source list, so:
utm_source=chatgpt
utm_medium=cpc
lands cleanly in Paid Other, which is the correct, expected bucket for a paid channel GA4 doesn't have a dedicated category for. Worth flagging: GA4 also has a separate AI Assistant channel, but that one triggers only when the medium is exactly ai-assistant, and it's meant for organic referral traffic from AI chat tools, not paid ads. Don't use ai-assistant as your medium for ChatGPT Ads, it would misclassify paid spend as organic traffic. Stick with cpc.
Google's own reference on default channel groups, including the exact source and medium rules, is Default Channel Group definition and the manual tagging and dimensions reference.
What utm_campaign, utm_content, and utm_term map to
Once source and medium are right, the rest of the string is what actually gets you past the single bucket:
utm_campaignpopulates GA4's session campaign dimension, shown by default in the Traffic Acquisition report.utm_contentpopulates the "Session manual ad content" dimension.utm_termpopulates the "Session manual term" dimension.utm_idis optional and populates a session campaign ID dimension, mainly useful if you're importing ad cost data and need to join GA4 sessions to spend rows by ID rather than by name.
The standard Traffic Acquisition report only shows source, medium, and campaign by default. Content and term don't show up there, you have to build a free-form table in Explore and add "Session manual ad content" and "Session manual term" as dimensions to see them. This is exactly where most people give up on ad-group or ad-level attribution: they tag the campaign name and stop there, because the content and term data doesn't show up anywhere obvious.
Google's own reference for what each UTM parameter is meant to hold is the URL builders / campaign data collection page.
What OpenAI Ads Manager actually supports for building these URLs
This is the part worth getting right rather than assuming. Google Ads has had automatic ValueTrack parameters like {campaignid} and {adgroupid} for years. Whether OpenAI's Ads Manager has an equivalent isn't something to guess at.
As of this writing, OpenAI's own help documentation describes a "Landing page query parameters" feature in Ads Manager Beta that does exactly this: you can append custom text or supported macros to a landing page URL, and Ads Manager fills the macros in automatically at delivery time. The documented macros are {campaign_id}, {ad_group_id}, {ad_id}, and {ad_account_id}.
You configure it from the three-dot menu on the Campaigns, Ad groups, or Ads page, selecting Edit campaign, Edit ad group, or Edit ad, then filling in the "Landing page query parameters" field. Parameters can be set at any of those three levels, and the precedence when they overlap is Ad URL, then Ad, then Ad Group, then Campaign, so a more specific setting always wins over a broader one, and nothing set at the Ad URL level itself gets overwritten.
Two things worth flagging honestly rather than papering over:
- This is a beta feature, and OpenAI's own public documentation has been inconsistent about it. Independent write-ups have noted the help center content changed to describe this capability after previously stating dynamic macro syntax wasn't supported. Confirm the "Landing page query parameters" field actually appears in your own account's campaign, ad group, and ad edit screens before building a UTM strategy that depends on it, don't assume it's there because a doc (including this one) says so.
- OpenAI's help documentation separately confirms static tagging always works, that is, typing a full UTM-tagged URL by hand into each ad's destination URL field, with no macros at all. That path has no beta caveat attached to it.
So there are two ways to actually get ad-group and ad-level UTMs into GA4 today, depending on what your account exposes:
If your account has the Landing page query parameters field with macro support, set this once at the campaign level (or per ad group, if you want cleaner control) and let Ads Manager fill in the IDs automatically on every click:
utm_source=chatgpt&utm_medium=cpc&utm_campaign=spring-promo&utm_id={campaign_id}&utm_content={ad_group_id}&utm_term={ad_id}
One real limitation to know about before you rely on this: the macros populate numeric IDs, not the human-readable campaign, ad group, or ad names. You'll see utm_content=8842103 in GA4, not the ad group's name. You'll need to keep a lookup sheet mapping IDs to names, the same way many advertisers already do with Google Ads' {campaignid} and {adgroupid} ValueTrack parameters, if you want readable labels in a report rather than a spreadsheet lookup every time.
If that field isn't available in your account, or you'd rather not depend on a beta feature, build a distinct, fully static UTM string for every ad by hand (or via a spreadsheet-driven URL builder) and paste it into that ad's destination URL directly:
utm_source=chatgpt&utm_medium=cpc&utm_campaign=spring-promo&utm_content=emergency-repair-adgroup&utm_term=ad-v1-headline-a
This gets you exactly the same GA4 outcome, campaign, ad group, and ad-level breakdown, it's just manual labor instead of an automatic fill. It's also more failure-prone: it only works if you're disciplined about typing a genuinely distinct string into every single ad rather than reusing one URL across a whole ad group and losing the ad-level distinction you were after.
Either way, at minimum, tag utm_campaign distinctly per campaign. That alone gets you past the single "chatgpt / cpc" bucket and into per-campaign GA4 reporting, which is the floor, not the ceiling.
OpenAI's own reference for campaign structure, which confirms ChatGPT Ads uses a Campaign, Ad Group, Ad hierarchy similar in shape (though not identical in mechanics, ad groups here are built around themes and "context hints" rather than keyword targeting) to Google Ads, is Create Campaigns for ChatGPT Ads and Create Ad Groups for ChatGPT Ads. OpenAI's documentation on landing page query parameters and measurement is under Measure Results. Because this is a beta capability, treat the field names and macro syntax there as something to reconfirm against your own account rather than take as permanent.
Why this is worth the setup
Without campaign, content, and term tagging, "chatgpt / cpc" in GA4 tells you that ChatGPT Ads exists as a channel and roughly how much traffic it sends. It tells you nothing about which campaign, ad group, or specific ad is actually producing engaged sessions or conversions. If you're running more than one ChatGPT Ads campaign, or more than one ad within a campaign, that single bucket can't tell you where to shift budget.
With the UTMs in place, you can open Explore, build a free-form table with session campaign, session manual ad content, and session manual term as row dimensions, and see engaged sessions, conversions, or revenue broken out by exactly which ad drove them. That's the difference between "ChatGPT Ads seems to be working" and "this specific ad in this specific ad group is what's actually working."
Frequently asked questions
Do I still need the OpenAI Pixel if I'm using UTM parameters?
Yes, they do different jobs. The pixel and oppref feed OpenAI's own ad-platform attribution and bidding. UTM parameters feed GA4's session attribution. You need both if you want both platforms' reporting to work correctly.
What GA4 channel should ChatGPT Ads traffic land in?
Paid Other, if you tag utm_source=chatgpt and utm_medium=cpc. There's no dedicated ChatGPT Ads channel in GA4's default channel groups, and Paid Other is the correct catch-all for a paid channel GA4 doesn't have a specific category for.
Can OpenAI Ads Manager fill in campaign, ad group, and ad IDs automatically like Google Ads' ValueTrack parameters?
OpenAI's help documentation describes a beta "Landing page query parameters" feature with macros for {campaign_id}, {ad_group_id}, {ad_id}, and {ad_account_id}. Confirm it's actually present in your account before relying on it, since it's a beta capability and OpenAI's own public documentation on it has been inconsistent. Static, hand-typed UTM URLs work regardless of whether that field is available to you.
Why don't I see utm_content or utm_term in my GA4 Traffic Acquisition report? GA4's standard report only shows source, medium, and campaign by default. Content and term require building a free-form table in Explore with "Session manual ad content" and "Session manual term" added as dimensions.
What's the minimum I should tag if I don't want to deal with ad-group or ad-level detail?
At minimum, tag utm_source=chatgpt, utm_medium=cpc, and a distinct utm_campaign value per campaign. That alone moves you from one lump bucket to per-campaign reporting in GA4, even without touching content or term.
Getting GA4 to actually reflect what's happening in a newer ad platform, rather than lumping it into one bucket or letting it fall into Unassigned, is exactly what conversion tracking is for. If you're adding ChatGPT Ads on top of Google and Meta, it's worth getting the UTM structure right from the first campaign rather than rebuilding your naming convention after three months of unusable data.
Questions about how this affects your account?
Let's talk