
The Case of the Unassigned Conversions
Your GA4 sales can come back “Unassigned” — credited to nothing. The obvious fix is usually the wrong one. Here’s how to tell which break you actually have.
9 min read
You paid to get her to the store. The ad, the click, the browse, the sale — and now you want the one fact that justifies the spend: where did she come from? You open Google Analytics, find the order, look at the channel column, and it says: Unassigned. No source. No campaign. Nothing. As far as your analytics is concerned, the sale arrived from nowhere.
It’s one of the quietly maddening things in ecommerce. You know the money worked. You just can’t prove which dollar did it.
I’ve chased this exact ghost across more than one store. The first time, I was certain I knew who did it. I was wrong — and so is almost every post that explains this, because they all name the same suspect and never check whether it’s actually in the room.
This is the case file: the obvious suspect, why I cleared it, the second dead end, and the two culprits actually behind it — plus how to dust for prints on your own store in about five minutes.
First — what Google is actually doing
Before the suspects, the mechanism. You don’t need to be technical to follow this, and it’s the part that makes the rest make sense.
Google Analytics doesn’t really think in “visitors.” It thinks in sessions. A session is everything one person does in a single visit — landed here, viewed that, added to cart, checked out — bundled together, and capped by time. The important part: it stamps where the visitor came from onto the session once, at the very start.
That works fine as long as the chain of events stays connected. The trouble starts when the chain gets cut mid-visit. When Google loses the thread, it doesn’t go hunting for where the person just was. It assumes a brand-new visit has begun — a new session, with no source attached. (It can usually still tell it’s the same device, but the link back to where they originally came from is gone.)
Here’s the trap: on a lot of Shopify stores, the chain snaps at the worst possible moment — right as the customer lands on the order-confirmation page. The sale gets recorded in a fresh, sourceless session. And a sale with no source is exactly what “Unassigned” means.
“Unassigned” is not a fancy word for “Direct”
One myth to kill first, because it changes how alarmed you should be.
Direct means Google saw the visit, recognized the visitor, and genuinely found no source — someone typed your URL or used a bookmark. It’s a real, if uninformative, answer.
Unassigned is different. It means Google got an event it couldn’t file under any channel at all — not even Direct — because the session’s source information was structurally missing, not just blank. A little Unassigned is normal noise. Unassigned on your sales specifically, showing up as a top-three “channel,” is a symptom of something broken.
And the catch that wastes everyone’s afternoon: there are at least two completely different breakages that produce the exact same symptom — and they need different fixes.
Suspect #1: the cross-domain checkout — and why I cleared it
The prime suspect, the one every post names first: the checkout lives on a different web address than the store. Shopify checkout historically ran on its own domain, and the browser’s little “remember this visitor” file — the GA4 cookie (_ga) — can’t be read across that boundary. Cross the line and Google sees a stranger starting fresh; the sale lands sourceless. Textbook.
It’s a real failure mode, so I checked it the fast way with a hostName view in GA4 — a two-minute build in Explore (steps in “Check your own store” below) that simply lists the web addresses your sessions happened on. If the sale-sessions sit on a different address than the browsing-sessions, the cross-domain break is real.
They didn’t. Every session — browsing and buying alike — sat on the one storefront address. This store ran Shopify’s newer checkout, served on the same address as the shop. There was no border to cross. The obvious suspect had an alibi.
“Run the hostName check first. It tells you in a minute whether you’ve got the real cross-domain break — or an imposter wearing its coat.”
Suspect #2: the tracking never saw the campaign — also cleared
Next theory: maybe the store was stripping the campaign tags off the link before Google ever recorded them, so the visit started blind.
Easy to test. Every time GA4 records something, it fires off a small data packet you can watch in your browser. (For the technically inclined: each hit is a request to /g/collect, and its dl value carries the full landing URL, campaign tags and all.)
The tags were right there in the packet. Google did see where the visit came from. So the source wasn’t missing at the start — it was getting lost later, when the visit got stitched together. Second suspect cleared.
The real culprits: two of them, working together
Two things were broken, and both had to be fixed.
Culprit #1 — the order-confirmation page lived on Google’s domain, not the brand’s. In plain terms: even though checkout itself was fine, the “thank you / order status” page — the one that loads right after payment — was being served from a Shopify-owned address instead of the brand’s own. That’s the chain-break from earlier, in the flesh: the sale fired on a page Google treated as a brand-new, sourceless visit. (Shopify’s own documentation says tracking won’t carry to that page unless customer accounts run on the brand’s own domain.) It’s a one-time settings change to fix — exact path in “The fix,” below.
Culprit #2 — the tracking was set to “Optimized,” quietly dropping a key signal. Shopify’s Google connection had a data-sharing setting turned down to “Optimized” instead of “Always on.” The practical effect: it was leaving out the bit of information that records where a visitor came from when they arrive without a campaign tag (the technical name is the document-referrer, dr). That shoved a whole slice of normal organic and referral traffic out of “Direct” and into “Unassigned.” It’s a single toggle to fix — exact path in “The fix,” below.
Culprit #1 produced the headline Unassigned sales; Culprit #2 swelled the Unassigned pile with everyday traffic that should have been Direct. Neither was the cross-domain break everyone blames first.
Check your own store in five minutes
You don’t need a developer for the diagnosis — and which break you have decides which fix you need, so check before you change anything.
Step 1 — confirm you’ve actually got Unassigned sales. Open GA4 → Reports and find the Traffic acquisition report. (Newer properties tuck it under a Business-objectives group like “Generate leads” or “Drive sales”; older ones keep it under Life cycle → Acquisition. If you can’t spot it, type “Traffic acquisition” into the search bar at the top of GA4.) Switch the table’s dimension to Session default channel group, add a filter for Event name = purchase, and set the range to the last 30 days. If “Unassigned” is in your top few channels, you’ve got it. Click in and look at the landing pages — order-status and thank-you URLs confirm the sales are anchoring in the wrong place.
If you have data-API access, it’s one query:
GA4 Data API — find Unassigned sales
Dimensions: transactionId, sessionDefaultChannelGroup,
sessionSource, sessionMedium, landingPagePlusQueryString
Metrics: ecommercePurchases
Filter: ecommercePurchases > 0
Range: last 30–90 days
Look at the SHARE where sessionDefaultChannelGroup = Unassigned
and sessionSource = (not set).Read the share, not the raw count. A stray Unassigned sale is noise; once it’s roughly a fifth or more of your converting sessions, it’s structural.
Step 2 — build the hostName view. This is the one that matters. GA4 has no ready-made hostName report, but it’s a two-minute build. Left nav → Explore → Blank (free-form). In the Variables panel, add the dimensions Hostname and Session default channel group and the metric Sessions (add Key events too if you want purchases in view). Drag Hostname into Rows. Now you can see which web addresses your sessions — and your sales — actually happened on:
- A different address on the sale sessions → you’ve got the genuine cross-domain break.
- The same address but sales still land Unassigned → it’s the order-status-page-and-settings pair, not cross-domain.
Step 3 — for the same-address case, confirm the culprits.
- Culprit #1 (quick check): Shopify Admin → Settings → Domains → the Customer accounts section. If your order-status / account pages sit on a Shopify address rather than a branded one (like
account.yourbrand.com), that’s it. - Culprit #2 (advanced / optional): if you’re comfortable reading network events, run an end-to-end test order and watch the tracking hits on the thank-you page for a missing where-they-came-from signal (
dr). Not comfortable with that? Skip it — just apply the “Always on” fix below and confirm with the single test order at the end.
The fix
Apply the fix that matches what Step 2 told you — not the one the internet told you.
If it’s the genuine cross-domain break
(Step 2 showed a different address on your sale sessions — e.g. the shop is www.yourbrand.com but checkout sits on checkouts.yourbrand.com or shop.app.) One setting in GA4: Admin → Data Streams → your web stream → Configure tag settings → Configure your domains, and add the checkout address (find it under Shopify Admin → Settings → Domains). Save. New sales will carry their source across the handoff.
If it’s the same-address pair (the common one)
(Step 2 showed the same address on browsing and sales — e.g. everything sits on www.yourbrand.com — but sales still land Unassigned.) Two changes:
- Branded account address (Culprit #1): Shopify Admin → Settings → Domains → Customer accounts → set a branded subdomain (enter
accountto getaccount.yourbrand.com). It can take up to ~48 hours to verify. This makes the order-status page count as the same visit as the shopping before it. - “Always on” tracking (Culprit #2): Shopify Admin → Settings → Customer events → open your Google / GA4 pixel → set its data-sharing level from “Optimized” to “Always on.”
Do both — they patch different slices of the same Unassigned pile.
The lower-effort route
Rather not touch settings by hand? Reconnecting GA4 through Shopify’s native Customer events → Google and YouTube channel handles most of this for you. If your GA4 was hand-installed or runs through Tag Manager, the switch is more involved; if it’s already on the Shopify channel and just misconfigured, the reconnect is quick.
Prove it with a single test order
You don’t have to wait weeks for new sales to see if it worked. Place one test order and watch the data packets fire across the visit:
What to watch on a test order
landing → add to cart → begin checkout
→ add payment info → purchase → thank-you page
Before the fix: the thank-you + purchase steps show a DIFFERENT session id
After the fix: every step shares the SAME session idBefore, the visit split in two at the thank-you page — which is why the sale showed up sourceless. After, the whole journey holds together as one session, and the test order lands in your reports with a real source. One order, answered for certain, instead of a week of guessing.
Why this is worth an afternoon
A broken sales-source feed isn’t cosmetic. It’s a number you’ve been trusting to make spending decisions, quietly lying to you. Three things you can’t do until it’s fixed:
- See the real path to a sale. Clicked an ad Monday, came back from search Wednesday, bought Friday — GA4 is what stitches that together. With the visit splitting at the sale, the trail ends at “nothing.”
- Settle the Meta-vs-Shopify argument. When your ad platform and Shopify each claim the sale, GA4 is the neutral third party. A broken feed means no tiebreaker — just two biased opinions.
- Judge channels past the last click. Last-click reporting flatters the bottom of the funnel (brand search, email) and starves the top (paid social, content). A working GA4 is what lets you see the whole journey instead.
The reason it hides for so long: a broken setup looks identical to a healthy one. The dashboards fill in, the charts draw, the totals add up. The only tell is that quiet “Unassigned” row — easy to scroll past if you don’t know what it’s saying. And even when you spot it, the obvious cause usually isn’t yours.
What this doesn’t fix
Closing this gap fixes the Shopify sale-tracking handoff. It doesn’t touch a few other holes every store has:
- Apple Mail privacy. Opens in Apple Mail hide where the click came from, so a lot of email traffic reads as Direct or Unassigned no matter how cleanly you tag links. Your email is almost certainly under-credited.
- iOS “ask app not to track.” Many people decline, which blinds the ad-platform pixel for them. Server-side tracking helps but doesn’t fully close it.
- Phone-to-laptop journeys. Browse on a phone, buy on a laptop, and the trail breaks at the device line unless they log in.
- Brand-name searches. Someone Googles your name and clicks — you get credited “organic search,” but whatever built that awareness upstream gets nothing.
Attribution is an estimate stitched from imperfect sources. The job isn’t to find one perfect number — there isn’t one — it’s to read across the layers and reason about the real journey.
But this particular break is the biggest and easiest to close, and the real lesson is older than analytics: rule out your suspects before you arrest one. The obvious cause is real and common — and it’s only one of at least two that look identical from the outside. The hostName check tells you which one you’re holding, in about a minute. Run it before you reach for the famous fix.