# Channel rules

Per-channel tagging recipes. Platform facts were checked on 2026-10-17; the URL for each is in `sources.yaml`. Fictional values throughout: Acme Analytics, `example.com`, initiative `2026_11_forecasting_launch`.

Two rules apply on every paid platform:

- `utm_campaign` is the platform's campaign name, inserted by the platform's name macro where one exists. Google's campaign data import page asks for dynamic values such as `utm_campaign={{campaign.name}}` where the platform supports them, and its campaign URL page asks for names that match the platform's own names so reports do not fragment. Name platform campaigns with the initiative's registry name plus a qualifier (`2026_11_forecasting_launch_prospecting`), or by campaign-naming-convention when the team uses it. When that skill is in use, its templates for `utm_campaign`, `utm_id` and `utm_content` win; check them here against the channel and cost rules.
- `utm_id` is the ID of the platform object that cost is reported on, inserted by macro. Record each resolved ID and name in the platform campaign map.

Every recipe ends the same way: enter the parameters, click the real ad or link (a preview where possible), capture the final URL after redirects, and compare the next day's Session source / medium and channel with the registry's `expected_channel`.

## Google Ads

- Keep auto-tagging on. Path checked on 2026-10-17: Admin, Account settings, Auto-tagging, "Tag the URL that people click through from my ad". It is on by default for new accounts. Google notes that App campaigns do not respect auto-tagging features.
- While the click ID is usable, GA4 takes source, medium, campaign and channel from auto-tagging and has no override setting (unlike Universal Analytics). Manual UTMs then fill only manual ad content and manual term in GA4, and give other tools (CRM, form handlers) readable values.
- When the GCLID cannot be used as intended and any UTM is present, GA4 derives every cross-channel source value, the channel included, from the UTMs alone. A full `google / cpc` set then classifies those clicks as Paid Search whatever the campaign type (Performance Max and Demand Gen would otherwise be Cross-network, Display campaigns Display), and the aggregate identifiers that otherwise cover such clicks may go unused. A partial set produces `(not set)` source and medium.
- Decision rule: add manual UTMs to Google Ads only when a tool that reads UTMs (CRM form handler, marketing automation) must attribute Google Ads leads and cannot store `gclid`, `gbraid`, `wbraid` and `gad_campaignid` instead. If you add them, add the full set and record the fallback channel (Paid Search) next to the auto-tagged prediction in `expected_channel`. Revisit the choice when click ID capture ships (first-party-click-id-capture, planned).
- Put landing page parameters in the final URL suffix, not the tracking template. With parallel tracking, the tracking template is for click trackers; parameters the landing page needs belong in the suffix or the final URL.
- Suffix resolution: Google takes the suffix from the lowest level that defines one (account, campaign, ad group, ad, keyword, sitelink). A campaign suffix replaces the account suffix. If one campaign needs an extra parameter, repeat the whole set there.
- ValueTrack has `{campaignid}` but no campaign name parameter. Carry the campaign's own name through a campaign-level custom parameter, typed to equal the Google Ads campaign name, so fallback clicks carry the same name GA4 shows for auto-tagged clicks. Custom parameter values cannot contain spaces, which the naming rules already exclude. Custom parameters cannot be set at account level; names are alphanumeric (referenced with a leading underscore), up to 8 per entity, and the API caps keys at 16 bytes and values at 200 bytes.

Account-level final URL suffix, entered without a leading `?`:

```text
utm_source=google&utm_medium=cpc&utm_campaign={_campaign}&utm_id={campaignid}&utm_content={creative}&utm_term={keyword}
```

Campaign custom parameter: name `campaign`, value `2026_11_forecasting_launch_search` (the campaign's name). A campaign rename means updating this value the same day.

- Performance Max fully supports `{campaignid}`, `{assetgroupid}`, `{device}` and the location and `{lpurl}` parameters; `{creative}` and `{keyword}` are not on its list. Give Performance Max campaigns a campaign-level suffix with `utm_content={assetgroupid}` and no `utm_term`. Demand Gen does not support `{keyword}`, `{placement}`, `{network}` or `{targetid}`. Check the live ValueTrack page for other campaign types.
- Redirects must deliver the click identifiers to the final landing page as top-level parameters: `gclid`, `gbraid`, `wbraid` (iOS app to web, per the Google Ads API conversion upload guide), `gad_source` and `gad_campaignid`. Confirm the current set on the live aggregate identifiers page. GA4 added a missing URL parameter diagnostic on 30 July 2026; its help page says it appears when `gbraid` or `gad_` parameters are missing from URLs that carry a `gclid`.
- If the site errors on unknown parameters, fix the server; do not turn auto-tagging off.
- Read-only check with Google's Google Ads MCP server (`search`). Confirm field names with `get_resource_metadata` first:

```sql
SELECT customer.auto_tagging_enabled, customer.final_url_suffix, customer.tracking_url_template
FROM customer
```

Repeat at campaign, ad group and ad level for `final_url_suffix`, `tracking_url_template` and `url_custom_parameters`, so you can see which level wins for each campaign.

## Microsoft Advertising

- Microsoft Click ID (`msclkid`) auto-tagging is on by default for new accounts. Keep it through redirects like any click ID.
- UTM auto-tagging is an account setting (Campaigns, Settings, Account level options, "Add UTM tags to my destination URLs"; `AutoTagType` in the API: `Inactive`, `Preserve`, `Replace`). It writes `utm_source=bing`, `utm_medium=cpc`, the campaign name in `utm_campaign`, the ad group name in `utm_content` and the keyword in `utm_term`, and no `utm_id`.
- Microsoft's help says its keep-existing option checks UTMs in the tracking template, and that manual UTMs in the final URL or final URL suffix combined with UTM auto-tagging can produce duplicates. The API definition of `Preserve` mentions only UTMs in the ad or keyword final URL.
- Recipe:
  - UTM auto-tagging `Inactive`.
  - The full set in the account-level final URL suffix (Campaigns, Settings, Account level options, Final URL suffix; `FinalUrlSuffix` account property in the API). A suffix at a lower level replaces it; Microsoft does not combine levels, so repeat the whole set wherever a lower level needs one.
  - The tracking template only for `{lpurl}`-based click trackers. Parallel tracking is required on all accounts, and Microsoft recommends the suffix for parameters the landing page needs.
  - Keep `Preserve` only for teams that put registry values in the ad or keyword final URL, and only after the URL test tool shows no repeated key.
- Macros confirmed on Microsoft's URL parameters page on 2026-10-17: `{CampaignId}`, `{Campaign}` (campaign name), `{AdGroupId}`, `{AdGroup}`, `{AdId}`, `{keyword}`. For Performance Max, `{AdGroupId}` and `{AdGroup}` return the asset group. Confirm both campaign macros on the live page before use.

```text
utm_source=bing&utm_medium=cpc&utm_campaign={Campaign}&utm_id={CampaignId}&utm_content={AdId}&utm_term={keyword}
```

- `bing` is on Google's search list, so `bing / cpc` is Paid Search.
- Campaigns imported from Google Ads: leave the URL options (tracking templates, suffixes, custom parameters) out of the import, or Google ValueTrack syntax overwrites the Microsoft suffix. Check the option label live, and rerun the URL test tool after every scheduled import.
- Read-only access: Microsoft's Advertising MCP server, read-only through open flight per Microsoft's August 2026 product news, reads campaigns, ad groups, ads and keywords. Its page does not say whether it returns tracking templates or suffixes; confirm live, otherwise an account user reads Account level options and runs the URL test tool in the UI.

## Meta (Facebook, Instagram, Messenger, Audience Network, Threads)

- Set the parameters on each ad. In the API the field is the ad creative's `url_tags`; in Ads Manager it is the ad's URL parameters field (check the current label).
- Macros confirmed in Meta's developer guide on 2026-10-17: `{{campaign.id}}`, `{{adset.id}}`, `{{ad.id}}`, `{{campaign.name}}`, `{{adset.name}}`, `{{ad.name}}`. Meta stores name values in a snapshot when the object is first published and fills name macros from that snapshot, not from the live name. A renamed campaign keeps sending its old name.
- `{{placement}}` and `{{site_source_name}}` are widely used but were not in Meta's developer guide when checked. Confirm them in Ads Manager's URL parameter builder before use. If `{{site_source_name}}` feeds `utm_source`, third-party guides report the values `fb`, `ig`, `msg` and `an`; `msg` and `an` are not in Google's 2023 social file and are predicted Paid Other.
- Default template:

```text
utm_source=facebook&utm_medium=paid_social&utm_campaign={{campaign.name}}&utm_id={{campaign.id}}&utm_content={{ad.id}}&utm_term={{adset.id}}
```

- Name each Meta campaign before its first publish, to the registry name plus a qualifier or to campaign-naming-convention. On a connector route, do not rename it while the connector runs: sessions keep the snapshot name, so if the imported cost carries the current name, cost and sessions split across two names. Report or join by Session manual campaign ID when a rename has happened.
- `facebook` is on Google's social list and, with a paid medium, maps to `Meta Ads` in Source platform. `meta` maps to `Meta Ads` too but is not in the 2023 social file, so it is predicted Paid Other; confirm with a test visit if a team insists on it.
- GA4's Meta connector (Admin, Product links, Meta Links; then Data import, Create import source, Campaign data, Meta) needs Editor on the property. It needs one `utm_medium` for all paid Meta traffic and either one `utm_source` or one per publisher platform (Facebook, Instagram, Audience Network, Messenger, Threads). The page lists `utm_id` and `utm_campaign` as highly recommended on the Meta URLs but does not say which Meta fields fill them; after the first sync, compare campaign names and IDs in the Non-Google campaign report with Meta's export. Ad account, source and medium cannot be changed after creation; you delete and recreate. It attempts to pull at least 24 months of history; delete overlapping Meta datasets first.
- Boosted posts, lead forms and other formats created outside the ad's URL parameters may not carry them. Verify live per format, and test one of each before relying on it.
- Read-only audit with Meta's Ads MCP server: `ads_get_ad_entities`, `ads_get_creatives`, `ads_get_ad_preview`. Do not call create, update or activate tools from this skill.

## LinkedIn

- Tracking parameters are set per campaign, or per ad account (`sponsoredAccount`) from Marketing API version `202608`. The docs do not say which wins when both levels are set. Read the account first (`GET /rest/adTrackingParameters` with the `sponsoredAccount` key), use one level only, and if both are set, test a live creative URL for repeated keys before launch. Campaign Manager's labels can differ from the API names; check the UI live.
- Two kinds: dynamic values, resolved per ad, and custom values, appended as typed. Dynamic values available on 2026-10-17: `ACCOUNT_ID`, `ACCOUNT_NAME`, `CAMPAIGN_GROUP_ID`, `CAMPAIGN_GROUP_NAME`, `CAMPAIGN_ID`, `CAMPAIGN_NAME`, `CREATIVE_ID`, and `CREATIVE_NAME` from version `202606`. The docs do not say whether `CAMPAIGN_NAME` resolves to the current name or the one at creation; check with a test click after any rename.
- Behaviour that matters: changes on a campaign apply to all its running creatives without new review; shortened URLs get the parameters appended; Conversation Ads and Message Ads are not supported (tag those links statically). Static UTMs on the creative URL are kept and the dynamic set is appended, so the same key can appear twice. Remove creative-level UTMs when campaign-level parameters are set.
- LinkedIn's own API sample uses `utm_medium` `social`, which GA4 classifies as Organic Social. Use `paid_social`.
- API body shape for `/rest/adTrackingParameters` (campaign or account entity):

```json
{
  "dynamicValueParameters": {
    "utm_campaign": "CAMPAIGN_NAME",
    "utm_id": "CAMPAIGN_ID",
    "utm_content": "CREATIVE_ID"
  },
  "customValueParameters": {
    "utm_source": "linkedin",
    "utm_medium": "paid_social"
  }
}
```

- `utm_id` takes `CAMPAIGN_ID` because LinkedIn reports spend per campaign. campaign-naming-convention uses the campaign group (`CAMPAIGN_GROUP_NAME`, `CAMPAIGN_GROUP_ID`) as the initiative level; when the team follows it, use its template, put campaign group IDs in the map and export cost by campaign group.
- GA4 has no automated LinkedIn connector. Google's guide for gathering platform data lists LinkedIn's "Amount Spent" export for file import. LinkedIn has no official MCP server or agent skills; third-party servers exist but are not vendor-supported.

## Other paid platforms

- TikTok, Reddit, Pinterest, Snapchat and X follow the Meta pattern: one fixed source and medium per platform, the campaign name and campaign ID by the platform's own macros (check its docs live), ad ID in `utm_content`.
- Sources in Google's 2023 social file: `tiktok`, `reddit`, `pinterest`, `snapchat`, `twitter`. `x` was not listed; test before using it.
- GA4 lists automated campaign data connectors for Meta, Pinterest, Reddit, Snap and TikTok; each expects a single paid source and medium. After the first sync, compare the imported campaign names and IDs with the platform export.
- Pay-per-click listings on review sites or directories: medium `cpc` with a source off the search list lands in Paid Other. That can be the correct channel; record it as expected.
- Ads bought inside AI assistants: paid traffic like any other. Source platform maps `gemini`, `openai` and `perplexity` to `Other Ads`; the default channel is predicted Paid Other unless Google's lists change. Test it.

## Email and newsletters

- Owned newsletter: `utm_source` is the publication (`acme_weekly`), `utm_medium` is `email`, `utm_source_platform` is the ESP (`example_esp`), `utm_campaign` is the registry name of the initiative the link promotes, `utm_content` the link slot (`hero_button`, `article_1`, `footer_link`).
- An issue that promotes several initiatives carries several campaigns. Mint one `utm_id` per initiative per publication (one for `acme_weekly` and the forecasting launch, another for `acme_weekly` and the benchmark report), so each `utm_id` maps to one `utm_campaign`. The issue date goes in the registry's `placement`, not in a parameter.
- Lifecycle and onboarding flows: source is the program (`onboarding`, `renewal`); `utm_campaign` is the always-on name with the month the program started (`2024_03_onboarding_flow`); one `utm_id` per flow version, so a rewrite gets a new ID and the old one stays readable. A change of purpose or audience is a new initiative with a new name.
- If the ESP adds UTMs itself, read which values it writes from a test send. Align them with the registry or turn the feature off. Never let a merge tag put a subscriber field (email, contact ID) into a URL.
- Do not tag transactional links that carry tokens (password reset, magic links, signed download links). Tagging can break a signature and these are not campaigns.
- Test the link after the ESP's click-tracking redirect, not the URL in the editor. Some ESPs encode the destination; a value arriving as `%7B` or `%257B` means a macro or a double encoding.

## SMS and push

- SMS: medium `sms`, source the program or sender (`product_updates`). The SMS rule also fires on a source of `sms`, so do not use `sms` as a source.
- Push: medium `push`, source the app or program. Avoid `mobile` or `notification` in other mediums; they trigger the push rule.

## Partners and affiliates

- Affiliate network or commission links: medium `affiliate` (singular). `affiliates` is untested and may land in Unassigned, because the rule is written `Medium = affiliate` and Google does not say whether it is an exact match. Source is the partner when you report by partner; `utm_source_platform` is the network. `utm_id` is a registry `cmp_` ID per partner and initiative; keep the network's program or offer ID in the registry's `notes`.
- Networks redirect through their own tracking domain and often append their own click ID. Test the resolved URL: UTMs present once, the network's click ID intact.
- Commission is paid per transaction. Join it in the warehouse to orders on the network's transaction or order ID, not on partner and date. Import it to GA4 only as a partner-by-date total when cost must sit in GA4 reports.
- Unpaid partners, integrations and directory listings: medium `referral`, source the partner slug.
- Paid placement in a partner's newsletter: medium `email`, source the partner publication (`example_digest`), cost recorded as a flat fee in the registry. GA4 has no paid email channel; if paid placements must be separate from owned email, add a custom channel rule on those sources rather than inventing a medium.
- Co-marketing sends to a partner's list: medium `email`, source the partner.

## Organic social

- Brand posts: source the network as it appears in Google's social file (`linkedin`, `facebook`, `instagram`), medium `social`, `utm_content` the post type or slot. Expect Organic Social.
- Employee and founder posts: same pair; tell them apart with `utm_content`, never with a person's name.
- Bio and profile links are fine to tag. Test link-in-bio tools and shorteners: some drop or rewrite the query string. Links in your own website footer to your social profiles are outbound and untagged.

## AI assistants

- GA4 added the AI Assistant channel on 13 May 2026. Visits from recognised assistant referrers get medium `ai-assistant` and campaign `(ai-assistant)` automatically. A manual `utm_medium=ai-assistant` also matches.
- OpenAI's publisher FAQ says ChatGPT appends `utm_source=chatgpt.com` to links in its answers. That visit has a manual source and no manual medium. Check what the property records for `chatgpt.com` rows (medium and channel) before writing any rule; do not rewrite them.
- Tag only links you publish inside an assistant surface you control: a published custom assistant or app, links returned by your own assistant connector, a directory listing. Pair: your own app or connector slug as source (`acme_gpt`), medium `ai-assistant`, your registry campaign. Assistant names and hostnames are reserved for traffic the assistant sends on its own; using them as your source mixes your links into those rows and into Source platform's assistant labels. The campaign separates your links from recognised referrals, whose campaign is `(ai-assistant)`.
- Never tag URLs in `llms.txt`, documentation, or pages assistants cite. The tagged URL is copied into answers and reshared, and every later visit inherits your tag.
- Influence without a click (a read answer followed by a typed visit) is not a UTM problem: ai-traffic-tracking (planned) covers self-reported fields and custom channel groups.

## QR codes and offline

- Print a short redirect on your own domain (`https://example.com/go/expo26`), never the tagged URL. You can change the destination after printing, and the code stays less dense and easier to scan.
- The redirect sends the visitor to the landing page with the full tag set, as a server-side 302 or 307 (browsers cache a 301). Test that it passes the UTMs unchanged and does not drop an existing query string.
- Pair: medium `offline`, source the placement (`expo_booth`, `direct_mail`, `packaging`, `billboard`), `utm_content` `qr` or `vanity`, a registry `utm_id`.
- `offline` matches no default rule, so it is Unassigned in the default group by design. Add an Offline channel to a custom channel group (rule in [ga4-channel-rules.md](ga4-channel-rules.md#custom-channel-groups)) and log it in `decisions.md`.
- Do not route around Unassigned with a medium that triggers another rule: `mobile_qr` matches Mobile Push, `video_qr` Organic Video, `qr_cpm` the paid pattern.
- Podcast and radio reads with a vanity URL: medium `audio`, source the show. Expect Audio.
- People who type the bare domain instead of the vanity path arrive as Direct. Expect undercount; offer codes or a "how did you hear about us" field measure what the URL cannot.

## Never tag

- Internal links: navigation, banners, pop-ups, in-product links, links between your own domains (use cross-domain measurement), redirects inside your own site. Measure internal promotions with an event and a placement property.
- Why: the worked example in Google's traffic-source scope documentation shows a tagged click mid-session does not change that session's source but does enter key event attribution, and later direct sessions are attributed to the user's latest campaign values. An internal tag therefore takes credit from the real campaign for every return visit.
- URLs that get indexed or reshared: canonical URLs, sitemap entries, `llms.txt`, links in public documentation.
- Signed or token URLs, and any value unique per click or per person.
