ChatGPT Ads dynamic URL parameters: macros, UTMs, and stitching clicks to revenue
ChatGPT Ads supports dynamic URL parameters — macros such as {campaign_id}, {ad_group_id}, {ad_id} and {ad_account_id} that you place in your landing page query string and OpenAI populates automatically at delivery time. They are how you get campaign structure out of Ads Manager and into GA4, your CRM, and your warehouse, so you can attribute pipeline to the specific ad group that produced it rather than to "ChatGPT" as an undifferentiated blob. This guide covers each macro, how to build a tracking template, how they relate to UTMs and to oppref, and the mistakes that quietly break the join.
The 2-sentence answer
Put a macro like {campaign_id} inside a query parameter on your landing page URL, and ChatGPT Ads replaces it with the real ID when the ad is delivered. Combine those macros with standard UTM parameters so that human-readable source data and machine-readable IDs both arrive on the landing page, then persist them to your CRM so closed revenue can be traced back to an ad group.
The supported macros
Four macros are supported in landing page query parameters. Each is written in braces, and each is substituted at delivery time — meaning the value is resolved when the ad is served, not when you save the campaign.
| Macro | Resolves to | Use it for |
|---|---|---|
{campaign_id} | The ID of the campaign serving the ad | Campaign-level reporting joins and budget attribution |
{ad_group_id} | The ID of the ad group serving the ad | The most valuable one — ad groups are where context hints live |
{ad_id} | The ID of the specific ad creative | Creative-level performance and creative testing |
{ad_account_id} | The ID of the ad account | Multi-account agencies and multi-brand advertisers |
For most advertisers {ad_group_id} is the one that changes how you work. Because a ChatGPT Ads ad group is the container for context hints, ad-group-level attribution is effectively hint-theme-level attribution — the closest thing this platform has to knowing which buyer intent produced the revenue. That is the single most useful join available to you, and it is the reason to implement these macros even if you are otherwise happy with your reporting.
Building a tracking template
A landing page URL with macros looks like an ordinary URL with placeholder values:
https://example.com/pricing?utm_source=chatgpt&utm_medium=cpc&utm_campaign=q3-launch&ch_campaign={campaign_id}&ch_adgroup={ad_group_id}&ch_ad={ad_id}
At delivery, the macros are replaced with real IDs and the visitor lands on a URL carrying both your human-readable campaign labels and the platform's machine-readable structure. A few rules make this durable:
- Namespace your parameter keys. Use a prefix such as
ch_so ChatGPT Ads parameters never collide with parameters from another channel on a shared landing page. - Keep macro braces intact. Do not URL-encode the braces yourself.
%7Bcampaign_id%7Dwill not be substituted — it arrives literally. - Put macros in values, not keys. The macro belongs on the right-hand side of the equals sign.
- Mind existing query strings. If your landing page URL already has parameters, append with
&, not a second?. - Do not put macros in the path or the fragment. These are query-parameter macros; a value after
#also never reaches your server.
Build the template once, then reuse it across ad groups. Our UTM builder is useful for the human-readable half; the macro half you append by hand.
Mapping macros to UTM parameters
Macros and UTMs solve different problems and you want both. UTMs are the labels you chose and are readable by any analytics tool without a lookup. Macro IDs are what the platform knows and are the only values that reliably join back to Ads Manager reporting after somebody renames a campaign.
| Parameter | Suggested value | Why |
|---|---|---|
utm_source | chatgpt | Stable channel identity across reports |
utm_medium | cpc | Groups correctly with other paid channels |
utm_campaign | Your campaign label | Readable in GA4 without a join |
utm_content | Your creative label | Readable creative-level split |
ch_campaign | {campaign_id} | Survives campaign renames |
ch_adgroup | {ad_group_id} | Joins revenue to a hint theme |
ch_ad | {ad_id} | Exact creative attribution |
The renaming point deserves emphasis. Labels drift — somebody renames a campaign mid-quarter and every historical UTM row silently stops matching the current name. IDs do not drift. If you only have budget for one of the two, take the IDs and reconstruct the labels from a lookup table.
How oppref is different — and why you need both
There is a third value in play and conflating it with the macros causes real confusion. oppref is OpenAI's privacy-preserving click identifier, appended to your landing page URL automatically and captured by the oaiq pixel into a first-party cookie named __oppref. It identifies this click and it is what makes conversion attribution work.
| Macros | oppref | |
|---|---|---|
| Identifies | Campaign structure | An individual ad interaction |
| You configure it | Yes, in your URL | No, added automatically |
| Used by | Your analytics and CRM | OpenAI's attribution |
| Cardinality | Low — a handful of IDs | High — one per click |
In short: oppref is how OpenAI credits a conversion to an ad; macros are how you credit a customer to an ad group. Neither substitutes for the other, and stripping oppref at your edge — a redirect, a consent wall, a CDN rule — breaks conversion tracking entirely. See conversion tracking for the full mechanics.
Reading the parameters in GA4
GA4 collects your UTM parameters natively but ignores custom parameters like ch_adgroup unless you tell it not to. The sequence:
- Capture the query parameter on page load — in GTM, a URL Variable of type Query with the key
ch_adgroup. - Send it as an event parameter on your page_view and conversion events.
- Register it in GA4 as a custom dimension (Admin → Custom definitions), scoped to event or user as appropriate.
- Persist it. A parameter present only on the landing page is lost by the time somebody converts three pages later — write it to a first-party cookie or session storage and read it back at conversion time.
That fourth step is the one implementations skip, and it is why so many accounts have a custom dimension that is populated on 4% of sessions and empty everywhere else.
Passing IDs into your CRM
For lead-generation businesses this is where the macros earn their keep. Revenue lives in the CRM, not in Ads Manager, and the join between them is the ID you captured on arrival.
Write ch_campaign, ch_adgroup and ch_ad into hidden fields on every form, map those fields to custom properties on the lead record, and make sure they survive the lead-to-opportunity conversion in your CRM's object model. Once they do, you can report closed-won revenue by ad group — which means you can report closed-won revenue by context hint theme, and start making budget decisions on pipeline instead of on clicks.
Two cautions. First, if you are running Automatic Advanced Matching, remember that hidden fields are still form fields — keep IDs and hashed identity values clearly distinct so nothing gets double-hashed. Second, if you send conversions back from the warehouse via a partner, carry the same IDs through so both directions of the pipeline agree; our measurement partners guide covers that path.
IDs versus readable names
Macros return IDs, not names. A row reading ch_adgroup=48211903 is precise and completely unreadable, which is why the mature setup keeps a small mapping table — ad group ID to a human label — maintained in a sheet or a warehouse dimension table and joined at report time.
Build that table when you launch, not six months later when nobody remembers what 48211903 was. Add a row every time you create an ad group. It takes seconds at creation time and is genuinely painful to reconstruct after the fact, particularly once ad groups have been paused or renamed.
Failure modes that quietly break the join
- Redirects that drop query strings. A marketing redirect, a trailing-slash rule, or an http→https hop that discards parameters destroys both your macros and
oppref. Test the real ad URL, not the canonical page. - Pre-encoded braces.
%7Band%7Dare not substituted. Paste the raw braces. - Consent walls that strip parameters. Some CMPs reload the page without the original query string after consent. Verify the post-consent URL.
- Landing on a page that immediately routes elsewhere. SPA route changes frequently discard the query string on the first client-side navigation.
- Capturing but never persisting. The parameter exists on entry and is gone by conversion. Persist on arrival.
- Parameter key collisions. A generic key like
cidshared with another platform produces a silently mixed dataset. Namespace them. - Assuming macros populate in preview. Substitution happens at delivery. A preview URL showing literal braces is not necessarily broken — check a real click before concluding anything.
ChatGPT Ads URL parameters: frequently asked questions
What dynamic URL parameters does ChatGPT Ads support?
Four macros are supported in landing page query parameters: {campaign_id}, {ad_group_id}, {ad_id} and {ad_account_id}. Each is replaced with the real ID automatically at delivery time.
How do I add UTM parameters to ChatGPT Ads?
Append them to your landing page URL exactly as you would for any other channel — for example ?utm_source=chatgpt&utm_medium=cpc&utm_campaign=your-label — and add the ID macros alongside them under namespaced keys such as ch_adgroup={ad_group_id}. Use both: UTMs are readable, IDs survive renames.
What is the difference between a macro and oppref?
Macros identify campaign structure and you configure them yourself in the URL; oppref identifies an individual ad interaction and OpenAI appends it automatically. Macros feed your analytics and CRM; oppref feeds OpenAI's conversion attribution. Removing oppref breaks conversion tracking.
Why are my macros showing up as literal text like {ad_group_id}?
The three usual causes are URL-encoded braces (%7B instead of {), the macro being placed in a parameter key rather than a value, or looking at a preview rather than a delivered ad — substitution happens at delivery time. Verify with a real click before changing anything.
Can I see the ad group name instead of the ad group ID?
No — the macros return IDs only. Keep a mapping table of ad group ID to human-readable label and join it at report time. Build it as you create ad groups; reconstructing it later is painful, especially once groups have been renamed or paused.
How do I track ChatGPT Ads in GA4?
Standard UTM parameters are picked up natively. For the ID macros, capture the query parameter (a GTM URL Variable works), send it as an event parameter, register it as a custom dimension in GA4, and persist it to a cookie or session storage so it is still available when the conversion fires several pages later.
Do dynamic URL parameters work with product feed campaigns?
The macros populate landing page query parameters at delivery time and are not specific to a single creative type. As with any tracking change, verify on a live click in the campaign type you actually run rather than assuming parity across campaign modes.
Will adding URL parameters hurt my landing page SEO?
Not if the page carries a self-referencing canonical tag pointing at the clean URL, which is standard practice for any paid landing page. The parameters are for your analytics, not for search engines.
Sources and further reading
- OpenAI Developers — Conversion-optimized campaigns (supported dynamic URL macros and delivery-time substitution).
- OpenAI Help Center — Measure results (reporting columns these IDs join against).
- Context Hints — ChatGPT Ads conversion tracking (the
opprefidentifier, the__opprefcookie, and the pixel). - Context Hints — UTM builder (build the human-readable half of the tracking template).
Want your tracking template audited before you scale?
30 minutes with Tarun. Bring your landing page URLs and we will check that macros actually populate on a live click, that oppref survives your redirects and consent wall, and that ad group IDs are reaching your CRM so you can report revenue by hint theme.
Book a discovery call