martechdevs has been acquired by Growth and Analytics Partners LLC

Tracking troubleshooting

GA4 Unassigned and (not set) diagnosis

Diagnoses GA4 Unassigned, (not set), Direct and (other) rows from the underlying fields before anyone edits channel groups or relabels traffic. Walks a cause tree from UTMs and redirects to consent, server events, referrals and bots, checks each cause in explorations, the Data API or the BigQuery export, then orders the fixes and confirms them in new data.

FreeVersion 0.3.0Reviewed 17 October 2026

Unassigned, (not set), Direct and (other) are four different findings. Unassigned means no channel rule matched. (not set) means one dimension has no value. Direct means GA4 found no referrer, no campaign and no earlier non-direct source within the property's lookback window to carry over for that identity. (other) means rows were condensed. This skill finds which one you have, which field caused it and which journey produced it, then proves the repair with new data. Relabelling comes last, if at all.

When to use

Use this skill when:

  • Unassigned or Direct rises in Traffic acquisition, or a key event (purchase, lead) is credited to Unassigned.
  • Session source / medium, Session campaign or Landing page shows (not set).
  • A newsletter, agency, QR or AI link lands in the wrong channel.
  • Server-side, Measurement Protocol or Data Manager API events appear with no source.
  • A payment provider or your own domain shows up as a referral.
  • Someone proposes a custom channel group or a filter to "clean up" Unassigned.

Use something else when:

  • No events arrive at all, or the break could be anywhere from click to report: use tracking-break-map first.
  • The work is designing the UTM vocabulary: use utm-convention-and-registry. This skill only tests pairs against the rules.
  • The consent implementation itself needs testing across tags: use consent-debugging.
  • A cross-domain or single-page-app journey needs end-to-end QA: use cross-domain-and-spa-qa.
  • A backend sender must be built or rebuilt: use ga4-measurement-protocol.
  • A custom dimension or content group shows (not set): compare the payload key with the definition on events whose contract carries it, then use tracking-plan-builder.
  • An app stream shows source (not set): use mobile-attribution-fundamentals. A web linker cannot fix an app instance ID.
  • The report shows a thresholding or sampling message: that is a reporting limit, not missing source data. See references/where-to-look.md.

If a skill named here is not installed, use the official pages for that topic in sources.yaml.

Inputs

Read first, if martech-context/ exists:

  • stack.md: GA4 property and streams, GTM web and server containers, CMP and whether consent mode is basic or advanced, every domain the journey crosses, payment providers, and every system that sends server events (Measurement Protocol or Data Manager API).
  • naming-rules.md: the approved UTM source and medium pairs.
  • decisions.md: existing custom channel groups, unwanted referral list, cross-domain list, and the release log.

Then gather:

  • The symptom: report, exact dimension name with its scope prefix (First user, Session, or none), metric, reporting identity (Blended, Observed or Device based), channel group in use (default, primary or custom), date range, property timezone, filters and comparisons.
  • The first date the pattern changed and every release near it: GTM versions, CMP changes, redirects, checkout or payment changes, new server integrations, campaign launches, and GA4 Admin changes from the property's change history (data filters including hostname filters, channel groups, unwanted referrals, cross-domain list, session timeout).
  • Which key events matter, so the investigation is ranked by business impact.
  • The event data retention setting. Explorations show nothing for dates older than it.
  • Access: GA4 Viewer for reports and the Data API, read access to the BigQuery export if it exists (and the dataset location), and a clean test browser.

Never ask for or record Measurement Protocol API secrets, service account keys or customer personal data.

Procedure

1. Write the symptom record and check the denominator

Copy assets/incident-record.md and fill it in.

  • Pull the affected row's count, total sessions and key events for the affected period and for a completed baseline with the same weekday mix. Leave out the last two days: processing can take 24 to 48 hours.
  • If the baseline is older than the retention setting, take its counts from standard reports or the export. An empty exploration date is not zero.
  • Compute any (not set) share over the eligible population only, for example web-stream sessions for Landing page.
  • If the affected count is flat (inside the min to max range of the previous 8 completed weeks) and only its share rose, the first question is why total traffic fell. Record that and investigate the total.
  • If the count rose, continue. Rank findings by key events affected, not sessions (step 5 combines this with the fix tiers).

2. Rule out reading artifacts and channel group configuration

These need no collection fix. Check them before touching collection:

  • Event-scoped Source / medium on events that are not key events is (not set) by design.
  • Event metrics (Event count) broken down by Session or First user dimensions show (not set) for events not tied to a session or user.
  • Google Ads dimensions are (not set) for traffic that never came from Google Ads. Filter to paid Google traffic first.
  • Session dimensions pair with Sessions; First user dimensions pair with Total users and New users.
  • For most dimensions a blank value means an empty string was sent and (not set) means nothing arrived. Exception: content_group sent empty shows as (not set).
  • Source Platform values such as Unlabeled describe the platform managing the traffic, not the channel, and are not Unassigned. Google reclassified some values on 11 June 2026; annotate comparisons across that date.
  • An (other) row is cardinality condensing, not lost traffic. Stop the source investigation there.
  • Key event attribution credit can keep changing for up to 12 days.
  • Rebuild the row with Session default channel group. If the increase exists only in a custom or primary group, stop the cause tree and diagnose the group (references/channel-rules.md).

Rule: rebuild the view in a Free-form exploration with one scope throughout (references/where-to-look.md). If the symptom disappears, record it as an artifact and stop.

3. Split the row by its underlying fields

In the session-scope exploration, break the affected row down by Session source / medium, Session manual source / medium, Session campaign, Landing page + query string, Stream name, Hostname and Device category, with Sessions and Key events. Then branch:

  • Source and medium both readable: taxonomy branch (causes A, I, J).
  • One of source or medium readable, the other (not set), and a utm_ parameter in Landing page + query string: a partial UTM set. Taxonomy branch (A, and J when the source is an assistant).
  • Both (not set), or no utm_ parameter in the landing URL: collection branch (causes B to H).
  • (direct) / (none) grew: Direct branch. Start with K, then B, then the identity causes C, D and F. People typing the URL is one hypothesis, not the default.
  • A payment provider or your own domain is a source: handoff branch (cause F).
  • One pair or one landing path holds 50% or more of the growth: start there.

4. Walk the cause tree

Mark each cause confirmed, ruled out or not applicable, with evidence. Checks, fixes and confirmation for every cause are in references/cause-tree.md; the queries are in references/bigquery-checks.md. Run the export coverage check (QC) first: a partial export cannot rule a cause out.

  • A. UTM values that miss channel rules. Signal: a readable pair in Unassigned with utm_ parameters on the landing URL. Check the pair against references/channel-rules.md. Rules ignore case, so case is never the cause. UTMs on internal links are a defect here too.
  • B. Parameters lost before collection. Signal: the published link carries UTMs or gclid but Landing page + query string does not. Click the real link through every redirect, shortener and consent step.
  • C. Google tag initialized late. Signal: sessions with events but no session_start. Check the Google tag uses an Initialization trigger and consent defaults still run before it.
  • D. Consent sequence errors. Signal: sessions without session_start concentrated in one consent state. A gap in Yes sessions is the signature of default used where update belongs; a gap in No sessions points to denied events sent after a granted choice, or consented-away data. Read Q4a first: it shows whether denied rows can form sessions at all. A visitor who declines is not a defect.
  • E. Measurement Protocol, Data Manager API or other server events without session context. Signal: server events with one or a few user_pseudo_id values, no session ID, no page_location. Check cardinality, not null counts, and which API each backend uses.
  • F. Cross-domain handoffs and payment referrals. Signal: a payment host or a different registrable domain you own as a session source, a payment host as the event-scoped source of a key event, or user_pseudo_id changing across a domain boundary. A return inside the session timeout normally starts no new session (test T5 checks it), so check event-scoped credit as well.
  • G. Events outside a session. Signal: events without a session ID in the export. Q4a measures whether denied cookieless pings carry one.
  • H. Landing page (not set). Signal: sessions without a page_view. Group by first event, stream and platform before calling it a defect.
  • I. Campaign (not set) on Direct, organic and referral rows is expected. It is a defect only on rows whose landing URL carried UTMs, or on Google Ads traffic.
  • J. AI assistant referrers. Recognized assistants get medium ai-assistant and the AI Assistant channel (announced 13 May 2026); unrecognized ones stay in Referral; manual media such as ai match no rule; an assistant source with medium (not set) can land in Unassigned; copied links land in Direct.
  • K. Direct inflation. Signal: (direct) / (none) rises, often with a falling engagement rate. Check bot clusters, referrer loss on owned links and redirects, identity resets by browser, and lost paid click IDs.

5. Fix in this order

Every fix is a draft (change list, GTM diff, link template, settings change) that stops for the owner's approval. Tiers set the order; key events affected set the order within a tier. A link-template-only fix (A, J) can ship alongside a higher-tier engineering fix when it affects more key events.

  1. Artifacts: document, no change. Custom group defects: a draft change to the group.
  2. Defects that lose identity or key events: C, D sequence errors, E, and F when identity breaks across domains.
  3. Transport: B and K referrer loss (redirects, shorteners, link wrappers, consent reloads, untagged owned links).
  4. Referral hygiene: F (unwanted referrals for third-party payment processors; cross-domain for domains you own and tag).
  5. Future link taxonomy: A and J, through the UTM registry.
  6. Contamination: K bot clusters go to the site owner, browser identity resets to server-side work.
  7. Reclassification, only if still needed (references/channel-rules.md). Never reclassify (not set) pairs.

Collection fixes change future data only. Nothing recreates source values that were never collected.

6. Confirm the fix in data

Plan controlled tests in assets/test-matrix.csv: every affected path, in each consent state (accept, deny, saved choice), with expected values written before running. human rows are run by a named person with approval (see Boundaries). Run them as references/confirmation-tests.md describes:

  • First record the data filter states. An Active internal or developer traffic filter drops test data from reports and BigQuery for good, which looks like a failed fix.
  • Debug runs (Tag Assistant, DebugView) prove the same-day sequence only. Confirmation runs avoid preview mode and every Active filter, and record the client ID and the UTC time of the first click.
  • Next day, once QC passes: query Q8 shows each test session with session_start, a session ID and the expected traffic source fields. Server events: distinct user_pseudo_id close to distinct orders.
  • After 48 hours: the processed report puts each test session in the expected channel.
  • After a completed window with the same weekday mix: the affected count falls while total sessions and key events hold. If Unassigned falls by N and total sessions fall by roughly N, data was lost, not repaired. Reopen. UI session totals are approximate, so settle small differences with exact export counts.
  • Annotate the release date in the incident record and in dashboards.

Common failure modes

  • Custom channel group first. The chart looks clean and the collection defect stays.
  • The non-null trap. Server rows carry a constant, non-null source and medium. Count distinct values.
  • Deleting or pausing the server events that were Unassigned. Unassigned falls and so do purchases.
  • Unwanted referrals in place of cross-domain measurement or a shared cookie domain when user_pseudo_id changes across the boundary. The label goes away and the identity break stays.
  • New manual media such as ai, chatgpt or newsletter. They match no rule.
  • A source-only, unanchored AI regex in a custom group. It pulls tagged email and partner links and look-alike hosts into the AI channel.
  • Comparing AI or Referral across the first date ai-assistant appears in the property without an annotation.
  • Marking test devices as internal while an internal or developer traffic filter is Active. The confirmation data never arrives.

Worked example

Acme Outdoor (fictional, example.com) saw weekly Unassigned sessions rise from 1,200 to 4,800 and Unassigned purchases from 30 to 410 while total sessions held near 60,000. The causes: backend purchases sent by Measurement Protocol with a fixed client ID, a CMP update calling consent default where update belongs, and newsletter and partner link templates whose pairs match no rule. The walk-through, queries and confirmation numbers are in references/worked-example.md.

Acceptance checks

  • Symptom record: dimension with scope prefix, metric, reporting identity, channel group, dates, timezone, filters and first-change date are filled. Pass: another person can rebuild the same view from it.
  • Denominator: counts, totals and key events for both periods are recorded. Pass: the record says whether the count rose or only the share.
  • Artifacts and channel group: each item in step 2 is marked, and the increase is reproduced in Session default channel group or the custom group diagnosis is recorded. Pass: no collection fix is proposed for an artifact or a group defect.
  • Export coverage: QC passed for every day used as evidence, with denied events counted separately on advanced consent mode. Pass: no cause was ruled out from a partial export.
  • Cause tree: A to K each marked confirmed, ruled out or not applicable, with a screenshot reference, query result or test note. Pass: no cause is marked without evidence.
  • Fix list: ordered per step 5, each with an owner and an approval state. Pass: nothing was changed in GA4, GTM, the CMP or a sender without recorded approval.
  • Confirmation: data filter states are recorded, every row in the test matrix has observed values next to expected values, and each human row names who ran it and the approval. Pass: all match, or each mismatch has a ticket.
  • Window comparison: the affected count fell and total sessions and key events did not fall by a similar amount. Pass: the numbers are in the record, with exact export counts for any difference under 2% of total sessions.
  • Reclassification, if any: rule order, matching conditions, an unknown bucket and the default group kept for comparison are documented in decisions.md. Pass: no rule matches (not set) source or medium.

Boundaries

  • Read-only. The skill reads reports, the Data API and the export, and runs controlled test visits. Changes to channel groups, data filters, unwanted referrals, cross-domain settings, session timeout, GTM, the CMP or a server sender are drafts for a human with Editor access or the system owner.
  • The agent never places orders, completes payments, enters payment details or creates accounts. Purchase and sign-up tests are run by a named person with written approval. Prefer staging with a test property, or the payment provider's test mode. On production, use an agreed test product and record transaction IDs for refund and downstream exclusion by transaction_id, not by marking the device as internal traffic while that filter is Active.
  • Consent choices belong to the privacy owner. Never propose changing denied states to granted to recover data.
  • The incident record is saved where the user chooses. Propose a dated summary for martech-context/decisions.md; never write it silently.
  • Hand-offs:
    • Google's GA4 MCP server (googleanalytics/google-analytics-mcp, labelled Experimental) runs locally with the analytics.readonly scope and cannot change settings. Use run_report for the session and first-user breakdowns.
    • BigQuery's remote MCP server: use execute_sql_readonly (SELECT only, one query per call), and ask the admin to block execute_sql with an IAM deny policy. Row limits, timeouts and polling are in references/bigquery-checks.md.
    • Server senders: Google recommends the Data Manager API for new or rebuilt server-to-server integrations; the Measurement Protocol stays supported.
    • GTM changes: gtm-container-audit, if installed, for the read-only audit, then the team's GTM change process.
    • Deeper work, if installed: consent-debugging, cross-domain-and-spa-qa, ga4-measurement-protocol, server-side-tracking-debug, ga4-bigquery-export-and-sessions, ai-traffic-tracking. Otherwise use the matching pages in sources.yaml.

Live docs

Platform settings, limits and menu paths change. Before stating any parameter name, limit, quota or UI path:

  • Fetch the current page from the vendor docs MCP server or llms.txt listed in sources.yaml, or open the canonical URL.
  • If the live page disagrees with this skill, follow the live page and tell the user what changed.
  • Cite the URL you used.

Google publishes no llms.txt for these docs. The Developer Knowledge MCP server in sources.yaml covers developer and Cloud pages, not support.google.com; open help centre URLs directly.

Most important entries: default channel group, (not set) causes, Direct traffic, custom channel groups, unwanted referrals, cross-domain measurement, data filters, the Measurement Protocol and Data Manager API guides, the BigQuery export schema and MCP reference, and the release notes. Check the export schema in the table itself too. Every fact here was checked on 2026-10-17.

Book a Free Call

Thirty minutes on your stack and what it needs. Free, and no pitch.

Thirty minutes, and you leave with a plan

We look at what you have, what it is costing you and what to do about it first.

  • 30 minutes
  • Video call, link on booking
  • No obligation

What we'll cover

  • Your current stack and where it hurts
  • Quick wins we can ship first
  • An integration roadmap
  • Timeline, scope and next steps

Calendar not loading? Open it in a new tab or email hello@martechdevs.com.