{"id":3157,"date":"2026-09-29T06:16:16","date_gmt":"2026-09-29T06:16:16","guid":{"rendered":"https:\/\/dmarketertayeeb.com\/blog\/utm-parameters-ga4-campaign-tracking\/"},"modified":"2026-09-29T06:20:08","modified_gmt":"2026-09-29T06:20:08","slug":"utm-parameters-ga4-campaign-tracking","status":"publish","type":"post","link":"https:\/\/dmarketertayeeb.com\/blog\/utm-parameters-ga4-campaign-tracking\/","title":{"rendered":"UTM Parameters: A Complete GA4 Campaign Tracking and QA Guide"},"content":{"rendered":"\n<p>UTM parameters label an incoming link with the source, medium and campaign you chose. To trust the resulting GA4 row, carry those values through the redirect, confirm the landing page sent them with its first measurement event, and read the session-scoped report after processing. This guide follows that whole path, including Google Ads auto-tagging, consent behavior and the common Direct, Unassigned and (not set) cases.<\/p>\n\n\n\n<p>UTM means Urchin Tracking Module; people also call these UTM tags, codes or campaign parameters.<\/p>\n\n\n\n<p>A UTM is a campaign label, not a tracking tag by itself. GA4 still needs to load on the landing page and collect the event. A correct-looking URL cannot prove that the tag fired or that the visit became a session in the intended property. Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/10917952?hl=en\">campaign URL guidance<\/a> and <a href=\"https:\/\/support.google.com\/analytics\/answer\/11242870?hl=en\">manual and automatic tagging reference<\/a> define the fields below.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Choose fields that answer a reporting question<\/h2>\n\n\n\n<p>For a manually tagged external link, use <code>utm_source<\/code>, <code>utm_medium<\/code> and <code>utm_campaign<\/code>. Google recommends including all relevant fields when you set any UTM, especially those three plus <code>utm_id<\/code> and <code>utm_source_platform<\/code>. Treat those five as a complete naming set for a campaign register; <code>utm_content<\/code> and <code>utm_term<\/code> add detail when you will use it. These are recommendations for consistent reporting, not custom dimensions you must create.<\/p>\n\n\n\n<p>The following mapping combines Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/11242870?hl=en\">manual-tagging field table<\/a> with the <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/api-schema\">Data API dimension definitions<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-table\" role=\"region\" aria-label=\"GA4 UTM parameter and dimension mapping\" tabindex=\"0\" style=\"overflow-x:auto;max-width:100%;\">\n<table style=\"min-width:48rem;width:100%;border-collapse:collapse;\">\n<caption>Manual UTM fields and their GA4 manual traffic-source dimensions<\/caption>\n<thead><tr><th scope=\"col\">URL parameter<\/th><th scope=\"col\">Use it for<\/th><th scope=\"col\">GA4 session dimension<\/th><th scope=\"col\">First-user dimension<\/th><th scope=\"col\">Decision<\/th><\/tr><\/thead>\n<tbody>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_source<\/code><\/th><td>The publisher or source sending the visit, such as <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">newsletter<\/code> or <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">linkedin<\/code>.<\/td><td>Session manual source<\/td><td>First user manual source<\/td><td>Use on every manually tagged campaign link.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_medium<\/code><\/th><td>The acquisition method, such as <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">email<\/code>, <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">paid_social<\/code> or <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">referral<\/code>.<\/td><td>Session manual medium<\/td><td>First user manual medium<\/td><td>Use one controlled value for each channel type.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_campaign<\/code><\/th><td>The shared initiative or promotion, such as <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">2026q4_autumn_webinar<\/code>.<\/td><td>Session manual campaign name<\/td><td>First user manual campaign name<\/td><td>Use one stable name across the campaign\u2019s channels.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_id<\/code><\/th><td>A stable campaign identifier that can join campaign data across systems.<\/td><td>Session manual campaign ID<\/td><td>First user manual campaign ID<\/td><td>Recommended when the campaign has a durable internal ID.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_source_platform<\/code><\/th><td>The platform responsible for directing traffic to the property, such as an email or buying platform.<\/td><td>Session manual source platform<\/td><td>First user manual source platform<\/td><td>Recommended when that platform distinction is useful.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_content<\/code><\/th><td>The placement or creative variation, such as <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">header_cta<\/code> or <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">carousel_a<\/code>.<\/td><td>Session manual ad content<\/td><td>First user manual ad content<\/td><td>Optional; use it only when you will compare those placements or creatives.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_term<\/code><\/th><td>A manually supplied paid-search term or another defined term value.<\/td><td>Session manual term<\/td><td>First user manual term<\/td><td>Optional; use it only when the source provides a meaningful value.<\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n\n<p>The campaign-name and campaign-ID labels have been easy to confuse. Use <code>utm_campaign<\/code> for the campaign name and <code>utm_id<\/code> for its ID: Google\u2019s <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/api-schema\">Data API schema<\/a> says <code>sessionManualCampaignName<\/code> is populated by <code>utm_campaign<\/code>, while <code>sessionManualCampaignId<\/code> is populated by <code>utm_id<\/code>. The same mapping is given for first-user dimensions. The API schema describes available report dimensions; a listed dimension does not prove that a particular property collected a value.<\/p>\n\n\n\n<p>Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/11242870?hl=en\">manual-tagging page<\/a> also lists <code>utm_creative_format<\/code> and <code>utm_marketing_tactic<\/code>, while saying those parameters are not currently reported in Analytics properties. The <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/api-schema\">Data API schema<\/a> includes dimension entries for them, but that does not establish that a property will populate them. Do not build a launch report around either field until current Google documentation and a property-level check confirm the data you need.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Set a naming convention before anyone builds links<\/h2>\n\n\n\n<p>Pick one answer for each field and put the allowed values in a shared campaign register. Keep source, medium and campaign separate: <code>linkedin<\/code> is a source; <code>paid_social<\/code> is a medium; <code>2026q4_autumn_webinar<\/code> is the initiative. Use lowercase and a single separator, and make the campaign ID stable if you plan to join reporting to another system. UTM values are case-sensitive, so <code>Email<\/code> and <code>email<\/code> can become different dimension values even where a channel rule matches both.<\/p>\n\n\n\n<figure class=\"wp-block-table\" role=\"region\" aria-label=\"Illustrative autumn webinar campaign register\" tabindex=\"0\" style=\"overflow-x:auto;max-width:100%;\">\n<table style=\"min-width:60rem;width:100%;border-collapse:collapse;\">\n<caption>Illustrative register only. Replace the event name and ID with real campaign details before use.<\/caption>\n<thead><tr><th scope=\"col\">Touchpoint<\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_source<\/code><\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_medium<\/code><\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_campaign<\/code><\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_id<\/code><\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_source_platform<\/code><\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_content<\/code><\/th><th scope=\"col\"><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">utm_term<\/code><\/th><\/tr><\/thead>\n<tbody>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Newsletter<\/th><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">newsletter<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">email<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">2026q4_autumn_webinar<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">aw26_01<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">email_platform<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">issue_42_header<\/code><\/td><td>\u2014<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Paid social<\/th><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">linkedin<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">paid_social<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">2026q4_autumn_webinar<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">aw26_01<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">linkedin_campaign_manager<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">carousel_a<\/code><\/td><td>\u2014<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Partner referral<\/th><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">industry_partner<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">referral<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">2026q4_autumn_webinar<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">aw26_01<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">partner_site<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">newsletter_banner<\/code><\/td><td>\u2014<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Printed QR<\/th><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">conference_badge<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">qr<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">2026q4_autumn_webinar<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">aw26_01<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">offline_print<\/code><\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">registration_desk_card<\/code><\/td><td>\u2014<\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n\n<p>Use one campaign name and ID across the four touchpoints so you can compare them, then distinguish the link placement in <code>utm_content<\/code>. The medium also affects channel grouping. GA4\u2019s current default rules map <code>email<\/code> to Email and <code>referral<\/code> to Referral; Paid Social requires a recognized social source with a paid medium. A custom value such as <code>qr<\/code> may be Unassigned under the default rules. If you need a named QR bucket, check the current <a href=\"https:\/\/support.google.com\/analytics\/answer\/9756891?hl=en\">default channel definitions<\/a> and configure an appropriate custom or primary channel group. The source, medium and campaign dimensions can still be useful even when a medium has no matching default channel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Build the URL without breaking its query or fragment<\/h2>\n\n\n\n<p>The first query parameter follows <code>?<\/code>; later parameters follow <code>&amp;<\/code>. If the destination already has a query, add UTMs with <code>&amp;<\/code>, not another question mark. Keep a page fragment such as <code>#agenda<\/code> after the query string. In a URL like <code>https:\/\/events.example\/register#agenda?utm_source=newsletter<\/code>, the apparent UTM text is inside the fragment, not the query sent with the page request. See the <a href=\"https:\/\/url.spec.whatwg.org\/\">WHATWG URL Standard<\/a> for URL components.<\/p>\n\n\n\n<p>For example, this partner URL keeps the existing <code>lang=en<\/code> query and places the fragment last:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;\"><code style=\"font-size:15px;line-height:1.7;white-space:inherit;overflow-wrap:anywhere;\">https:\/\/events.example\/register?lang=en&amp;utm_source=industry_partner&amp;utm_medium=referral&amp;utm_campaign=2026q4_autumn_webinar&amp;utm_id=aw26_01&amp;utm_source_platform=partner_site&amp;utm_content=newsletter_banner#agenda<\/code><\/pre>\n\n\n\n<p>When code builds links, pass plain values and let the URL API encode them. <code>URLSearchParams<\/code> percent-encodes reserved characters and Unicode when it serializes a query; a space may appear as <code>+<\/code>. Do not pre-encode the values, because encoding a percent sign a second time changes the data. For example, a content value of <code>slot A+B &amp; caf\u00e9<\/code> is safely serialized as <code>slot+A%2BB+%26+caf%C3%A9<\/code>. The <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/URLSearchParams\">URLSearchParams reference<\/a> and <a href=\"https:\/\/url.spec.whatwg.org\/\">WHATWG URL Standard<\/a> define this behavior.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;\"><code style=\"font-size:15px;line-height:1.7;white-space:inherit;overflow-wrap:anywhere;\" class=\"language-javascript\">function buildCampaignUrl(destination, campaign) {\n  const url = new URL(destination);\n  if (url.protocol !== \"http:\" &amp;&amp; url.protocol !== \"https:\") {\n    throw new TypeError(\"destination must use http or https\");\n  }\n  const fields = {\n    utm_source: campaign.source,\n    utm_medium: campaign.medium,\n    utm_campaign: campaign.campaign,\n    utm_id: campaign.id,\n    utm_source_platform: campaign.sourcePlatform,\n    utm_content: campaign.content,\n    utm_term: campaign.term,\n  };\n\n  for (const key of [\"utm_source\", \"utm_medium\", \"utm_campaign\"]) {\n    if (typeof fields[key] !== \"string\" || fields[key].trim() === \"\") {\n      throw new TypeError(`${key} is required`);\n    }\n  }\n\n  for (const [key, value] of Object.entries(fields)) {\n    if (value == null || String(value).trim() === \"\") {\n      url.searchParams.delete(key);\n    } else {\n      url.searchParams.set(key, String(value).trim());\n    }\n  }\n\n  return url.toString();\n}<\/code><\/pre>\n\n\n\n<p>For example, call the function with one row from the register:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;\"><code style=\"font-size:15px;line-height:1.7;white-space:inherit;overflow-wrap:anywhere;\" class=\"language-javascript\">const partnerUrl = buildCampaignUrl(\"https:\/\/events.example\/register?lang=en#agenda\", {\n  source: \"industry_partner\",\n  medium: \"referral\",\n  campaign: \"2026q4_autumn_webinar\",\n  id: \"aw26_01\",\n  sourcePlatform: \"partner_site\",\n  content: \"newsletter_banner\",\n});\nconsole.log(partnerUrl);<\/code><\/pre>\n\n\n\n<p>The expected serialized output is:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;\"><code style=\"font-size:15px;line-height:1.7;white-space:inherit;overflow-wrap:anywhere;\">https:\/\/events.example\/register?lang=en&amp;utm_source=industry_partner&amp;utm_medium=referral&amp;utm_campaign=2026q4_autumn_webinar&amp;utm_id=aw26_01&amp;utm_source_platform=partner_site&amp;utm_content=newsletter_banner#agenda<\/code><\/pre>\n\n\n\n<p>Here are copyable URLs for all four illustrative touchpoints. They use the reserved <code>events.example<\/code> domain; replace the destination and event name before launch.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"max-width:100%;white-space:pre-wrap;overflow-wrap:anywhere;\"><code style=\"font-size:15px;line-height:1.7;white-space:inherit;overflow-wrap:anywhere;\">Newsletter:\nhttps:\/\/events.example\/register?utm_source=newsletter&utm_medium=email&utm_campaign=2026q4_autumn_webinar&utm_id=aw26_01&utm_source_platform=email_platform&utm_content=issue_42_header\n\nPaid social:\nhttps:\/\/events.example\/register?utm_source=linkedin&utm_medium=paid_social&utm_campaign=2026q4_autumn_webinar&utm_id=aw26_01&utm_source_platform=linkedin_campaign_manager&utm_content=carousel_a\n\nPartner referral:\nhttps:\/\/events.example\/register?lang=en&utm_source=industry_partner&utm_medium=referral&utm_campaign=2026q4_autumn_webinar&utm_id=aw26_01&utm_source_platform=partner_site&utm_content=newsletter_banner#agenda\n\nPrinted QR:\nhttps:\/\/events.example\/register?utm_source=conference_badge&amp;utm_medium=qr&amp;utm_campaign=2026q4_autumn_webinar&amp;utm_id=aw26_01&amp;utm_source_platform=offline_print&amp;utm_content=registration_desk_card<\/code><\/pre>\n\n\n\n<p>The function requires an absolute HTTP or HTTPS destination and nonblank source, medium and campaign values. It preserves unrelated query parameters and the fragment, replaces duplicate UTM keys with the new value, and removes old optional UTM fields omitted from the current register. It passed local static checks under Node v24.19.0 for reserved-character and Unicode round-trips, duplicate and stale-field handling, missing core values, invalid URLs and non-web schemes. Those checks tested URL construction only; they did not send a campaign click or verify a live redirect, site tag or GA4 report.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Accept a campaign link from browser to GA4 report<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Freeze the register.<\/strong> Confirm the destination, source, medium, campaign name and ID, platform and any content or term values. Check that the final URL is HTTPS and that no value contains a person&#8217;s name, email, phone number, CRM record ID or other user-level identifier.<\/li>\n<li><strong>Follow each exact link.<\/strong> Use every distinct destination and redirect path that will actually be placed in an ad, email, partner page or QR code. For session-scoped acceptance, use a fresh test browser profile with the site&#8217;s permitted consent state or wait until the prior GA4 session has ended. Opening a second campaign URL inside an active session does not start a new session. Inspect the final address after every redirect and confirm that the target page is correct, each intended UTM is present once, required query parameters survived, and the fragment follows the query. Google documents the mid-session behavior in its <a href=\"https:\/\/support.google.com\/analytics\/answer\/11242841?hl=en\">campaign and traffic-source reference<\/a>.<\/li>\n<li><strong>Check the first measurement event.<\/strong> Use Tag Assistant or your tag manager&#8217;s preview to confirm the intended GA4 property and a landing-page event such as <code>page_view<\/code>. Inspect its <code>page_location<\/code> value while the UTM query is still present. Google documents that UTMs are omitted from the <code>Landing page + query string<\/code> and <code>Page path + query string<\/code> dimensions and are instead included in <code>Page location<\/code>, so those page dimensions are not the right place to look for the full tagged URL; see its <a href=\"https:\/\/support.google.com\/analytics\/answer\/10917952?hl=en\">URL builder and reporting guidance<\/a>.<\/li>\n<li><strong>Use DebugView and Realtime as collection checks.<\/strong> Enable debug mode for your own device through Tag Assistant, then confirm that the expected page event appears in DebugView. Realtime is a quick collection check, while both views provide limited attribution for this diagnosis. Use them to confirm that activity arrived, not as the final campaign-report acceptance test; see Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/9924671?hl=en\">Realtime description<\/a> and <a href=\"https:\/\/support.google.com\/analytics\/answer\/7201382?hl=en\">DebugView guidance<\/a>.<\/li>\n<li><strong>Check the processed session report.<\/strong> In GA4, open <em>Reports \u2192 Acquisition \u2192 Traffic acquisition<\/em>. Inspect session-scoped dimensions such as Session source \/ medium and Session campaign; use Session manual ad content or Session manual term in an Exploration when those values matter. For the first source that acquired a person, use User acquisition and its First user dimensions. Google explains the scope difference in its <a href=\"https:\/\/support.google.com\/analytics\/answer\/12923437?hl=en\">Traffic acquisition report guide<\/a> and <a href=\"https:\/\/support.google.com\/analytics\/answer\/14731736?hl=en\">User versus Traffic acquisition comparison<\/a>.<\/li>\n<li><strong>Record what passed.<\/strong> Save the final destination URL, the observed redirect chain, the GA property\/tag checked, consent state used for the test, the page event and <code>page_location<\/code> observed, the GA4 report dimension and date range, and the date checked. Mark the campaign complete only when the session values match the register in the processed report.<\/li>\n<\/ol>\n\n\n\n<p>Do not treat a fixed delay as a failure rule. Google says processing may take 24\u201348 hours and reports can change during that time, while typical freshness intervals differ by property and report. Realtime may be quick; processed acquisition data is the later acceptance point. See Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/11198161?hl=en\">data freshness guidance<\/a>. If a row is still absent after processing, use the diagnostic order below instead of assuming that consent, attribution or the URL alone caused it.<\/p>\n\n\n\n<p>Consent changes what the test can show. In basic consent mode, Google tags are blocked until the visitor interacts with the banner, and no data is sent before consent. In advanced consent mode, tags can send cookieless pings while consent is denied. However, Google says DebugView does not show events when client-side privacy controls apply or when Analytics cookie consent has not been granted. Run a test in a consent-permitted state under your site&#8217;s rules; do not infer that a denied-consent visit was fully tracked or bypass a visitor&#8217;s choice. See Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/10000067?hl=en\">consent mode description<\/a> and <a href=\"https:\/\/support.google.com\/analytics\/answer\/7201382?hl=en\">DebugView guidance<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Diagnose Direct, Unassigned and (not set) separately<\/h2>\n\n\n\n<figure class=\"wp-block-table\" role=\"region\" aria-label=\"GA4 UTM troubleshooting decision table\" tabindex=\"0\" style=\"overflow-x:auto;max-width:100%;\">\n<table style=\"min-width:58rem;width:100%;border-collapse:collapse;\">\n<caption>Start with the first observable failure and test one layer at a time<\/caption>\n<thead><tr><th scope=\"col\">What you see<\/th><th scope=\"col\">Check first<\/th><th scope=\"col\">What it can mean<\/th><th scope=\"col\">Next step<\/th><\/tr><\/thead>\n<tbody>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">UTMs disappear from the final browser URL<\/th><td>Each redirect target, shortener, click tracker, final URL and fragment placement.<\/td><td>A redirect or URL rule may have rebuilt the destination without the query; a malformed URL may have placed parameters after <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">#<\/code>.<\/td><td>Test the exact campaign destination and preserve the full query at every redirect hop.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Final URL is correct, but no landing event is visible<\/th><td>Tag Assistant, property ID, stream, firing conditions, browser blocking and effective consent state.<\/td><td>The tag may not have loaded or fired on that page, or the test may not be allowed to send Analytics events.<\/td><td>Fix the tag or consent implementation first. Confirm the first event&#8217;s <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">page_location<\/code> before diagnosing report attribution.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Realtime has activity but the campaign report does not<\/th><td>Date range, property, report dimension, processing freshness and whether you chose session or first-user scope.<\/td><td>Realtime gives a quick activity check with limited attribution; the processed report may lag or the chosen scope may answer a different question.<\/td><td>Wait for the property&#8217;s normal processing interval, then check Traffic acquisition with Session dimensions. Use User acquisition only for first-user acquisition.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Traffic appears as <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">(direct) \/ (none)<\/code><\/th><td>Whether GA4 received referral or campaign information on the session&#8217;s first measurement event; inspect final URL and <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">page_location<\/code>.<\/td><td>Google processes a session as direct when referral-source information is unavailable. A missing or stripped UTM is one possible cause, not the only cause.<\/td><td>Check the redirect and tag path, then verify source\/medium in the processed session report. Do not equate every Direct session with a person typing the URL.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Channel group is Unassigned<\/th><td>Session source and medium values against the exact default or custom channel rules in use.<\/td><td>Unassigned means no rule in the selected channel group matched the event data. A custom medium such as <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">qr<\/code> may not match a default rule.<\/td><td>Correct the medium if it was mislabeled, or define and use an appropriate custom or primary channel group for a deliberate new category.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">A dimension shows <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">(not set)<\/code><\/th><td>The exact dimension and scope; for Session source \/ medium, check the <code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">session_start<\/code> event, tag ordering, and whether all relevant UTM values were sent.<\/td><td><code style=\"white-space:normal;overflow-wrap:anywhere;word-break:break-word;\">(not set)<\/code> is GA4&#8217;s placeholder when it has no value for that dimension. Causes vary; missing campaign fields and missing session-start data are documented cases.<\/td><td>Inspect collection and event timing, then retest with complete source, medium and campaign values. Don&#8217;t diagnose from the placeholder alone.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">UTMs show in Page location but not Landing page + query string<\/th><td>The dimension you selected.<\/td><td>GA4 documents that its landing-page and page-path query-string dimensions omit UTM values; Page location carries the full URL.<\/td><td>Use Page location for the captured query or Traffic acquisition&#8217;s native session campaign dimensions for campaign analysis.<\/td><\/tr>\n<tr><th scope=\"row\" style=\"min-width:10rem;\">Google Ads values are missing or unexpected<\/th><td>Auto-tagging, the linked Google Ads account, the final click identifier, the relevant Google Ads dimensions and any manual fallback values.<\/td><td>Unlinked accounts, unavailable click identifiers, incomplete UTMs or privacy-related identifiers can produce gaps or different dimensions.<\/td><td>Keep auto-tagging and the account link healthy. Add manual content or term only for their manual dimensions; if relying on UTMs as fallback, provide a complete consistent set.<\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n\n<p>Use the placeholder at the dimension level. If Session source \/ medium is <code>(not set)<\/code>, GA4 says that traffic is shown as Unassigned in the default channel group because there is no matching channel rule. That does not make the two labels synonyms: one is a missing dimension value, the other is a channel classification. Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/13504892?hl=en\">(not set) guide<\/a> and <a href=\"https:\/\/support.google.com\/analytics\/answer\/14847402?hl=en\">tagging best practices<\/a> list distinct causes, including incomplete manual tags, a missing <code>session_start<\/code>, tag ordering and session identity configuration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Handle Google Ads and internal links with care<\/h2>\n\n\n\n<p>For linked Google Ads traffic, keep auto-tagging enabled so GA4 can use the click identifier and platform-specific dimensions. When manual UTMs and auto-tagging are both present and the click identifier works as intended, Google says the auto-tagged values supply source, medium and other traffic-classification dimensions. You can still add <code>utm_content<\/code> and <code>utm_term<\/code> when you need the native Manual Ad Content or Manual Term dimensions.<\/p>\n\n\n\n<p>There is an important fallback case. If GCLID or DCLID cannot be used as intended and at least one UTM is present, Google says it derives all cross-channel traffic-source values from the UTMs alone. Missing values can then produce <code>(not set)<\/code>. Do not copy a blanket rule that manual <code>utm_content<\/code> or <code>utm_term<\/code> is forbidden with auto-tagging; also do not assume a manual tag will repair an unlinked account or a broken landing-page tag. Check the exact <a href=\"https:\/\/support.google.com\/analytics\/answer\/11242870?hl=en\">auto-tagging precedence<\/a> and the <a href=\"https:\/\/support.google.com\/analytics\/answer\/13504892?hl=en\">Google Ads dimension troubleshooting steps<\/a>.<\/p>\n\n\n\n<p>Keep acquisition UTMs on links that bring visitors onto the site. Google\u2019s <a href=\"https:\/\/support.google.com\/analytics\/answer\/11242841?hl=en\">campaign and traffic-source documentation<\/a> says a new campaign or source encountered mid-session does not start a new session: those values are associated with the events collected at that point and can be used for event-based attribution, but they are not assigned to the existing session. That makes internal UTMs a poor way to label on-site placements. Track internal clicks with an event or content measurement plan instead of relabeling the campaign that acquired the visit. This recommendation follows from the documented session behavior; it is not a claim that an internal UTM always overwrites session attribution.<\/p>\n\n\n\n<p>Never put names, personal email addresses, phone numbers or person-level CRM identifiers in UTM values. GA4 collects the page URL and Google requires both URL paths and parameters sent to Analytics to be free of personal identifying information; <a href=\"https:\/\/support.google.com\/analytics\/answer\/6366371?hl=en\">Google&#8217;s PII guidance<\/a> describes redaction as a best-effort control, not permission to place identifiers in campaign links. Use campaign-level labels that describe the channel, initiative or placement.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Use campaign attribution for the question it can answer<\/h2>\n\n\n\n<p>UTMs let you inspect which labels were attached to incoming traffic and compare sessions or attributed key events under GA4&#8217;s reporting settings. They do not show how many visits or conversions would have happened without the campaign, and they do not prove that a reported key event became a qualified lead or recognized revenue in a CRM. For those decisions, reconcile campaign data with the relevant CRM outcome and use an incrementality design when the question is causal. The separate guide on <a href=\"https:\/\/dmarketertayeeb.com\/blog\/google-ads-measurement-stack-attribution-incrementality-mmm\">separating attribution from incrementality<\/a> covers that measurement distinction.<\/p>\n\n\n\n<p>A link passes QA only when the final URL, the first collected page event and the processed session dimensions agree with the campaign register. Verify every distinct deployed destination, redirect path and creative link before marking the campaign accepted. Keep those three pieces of evidence together so a future report discrepancy can be traced to the URL, collection or reporting layer.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use a consistent campaign register, build tagged URLs, preserve UTMs through redirects, and verify session campaign data in GA4.<\/p>\n","protected":false},"author":1,"featured_media":3156,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[177],"tags":[24,433,448],"class_list":["post-3157","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-digital-marketing","tag-analytics","tag-marketing-analytics","tag-marketing-measurement","has-featured-image"],"_links":{"self":[{"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/posts\/3157","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/comments?post=3157"}],"version-history":[{"count":1,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/posts\/3157\/revisions"}],"predecessor-version":[{"id":3158,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/posts\/3157\/revisions\/3158"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/media\/3156"}],"wp:attachment":[{"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/media?parent=3157"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/categories?post=3157"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dmarketertayeeb.com\/blog\/wp-json\/wp\/v2\/tags?post=3157"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}