End of the month, two tabs open. Klaviyo says email and SMS drove 30% of revenue. GA4 says 8%. Both dashboards are completely confident, and everyone quotes whichever number makes them look better. I've walked through this reconciliation on plenty of ecommerce accounts — the gap is almost never a bug. It's two tools answering different questions and labeling both answers "revenue from email."
Why does Klaviyo show more email revenue than GA4?
Because Klaviyo casts a wide net and GA4 a narrow one. Klaviyo credits itself for any order placed within its attribution window after someone opened or clicked a message. GA4 only credits email if the buyer clicked, the UTMs survived to the landing page, and that session got the credit. One counts "was recently touched by an email." The other counts "clicked and bought in a way I could see."
Opens count in Klaviyo, and opens are broken
By default, Klaviyo's email attribution counts both opens and clicks — last touch, inside a configurable window (5 days by default). SMS is click-based since a text has no open pixel. Then Apple happened. Since iOS 15, Apple's Mail Privacy Protection pre-fetches images in emails — including the invisible pixel that registers an "open" — whether the human ever read the message or not. Subscriber's iPhone fetched the pixel while they slept? Attribution window starts anyway. Any order inside it belongs to email, no click required.
The window compounds this. At a 3x-per-week send cadence with a 5-day window, nearly everyone on your list sits inside some attribution window at all times. Email becomes a tollbooth every customer drives through on the way to checkout.
Klaviyo only competes with itself
Klaviyo's attribution only considers Klaviyo messages. It has no idea a Meta retargeting ad touched the same customer that week. Buyer opens your Tuesday campaign, clicks a Meta ad Thursday, purchases — Klaviyo credits Tuesday's email. Meta claims the same order. GA4 is the only one of the three even attempting to split credit across channels, which is exactly why its email number looks smallest.
GA4 loses email clicks constantly
GA4's requirement — a click with intact UTMs starting a measurable session — fails constantly. Links missing utm_source and utm_medium land as direct, or as a referral from a webmail domain. Link shorteners and redirects sometimes strip query parameters. In-app browsers in mail and SMS apps start cold sessions that privacy features happily sever from the eventual purchase. And every open-based conversion Klaviyo counts is invisible to GA4, because there was never a click at all.
- Email lands overnight — The subscriber never sees it
- Apple Mail prefetches — The invisible open pixel loads by itself
- Open recorded — Attribution window starts, no click needed
- Any order inside it — Credited to email, last touch, for 5 days
- Reported as email — Revenue the message never caused
Why do abandoned-cart flows claim revenue that was coming anyway?
Because flows fire at the exact moment purchase intent peaks, then take credit for the intent. Someone adds to cart, gets distracted, comes back two hours later to finish checkout — plenty of abandoners do this unprompted. If your abandoned-cart email landed in that gap, Klaviyo attributes the order to the flow. The flow didn't generate that sale. It photobombed it.
This is the difference between attributed revenue (orders that happened near your message) and incremental revenue (orders that wouldn't exist without it). Every email platform reports the first and lets you read it as the second. Abandoned-cart, browse-abandonment, post-purchase upsell — these fire closest to the money, so they harvest the most credit relative to what they cause.
| Klaviyo | GA4 | Backend order ledger |
|---|---|---|
| Counts opens by default | Clicks only, never opens | Every order, counted once |
| Apple MPP fires phantom opens | Needs UTMs to survive the click | Server-side Purchase with event_id |
| 5-day last-touch window | Shares credit across channels | Matches your store admin |
| Only sees Klaviyo messages | Redirects and in-app browsers break it | What you reconcile both against |
| Overstates email | Understates email |
Klaviyo vs GA4: what each number actually means
| Klaviyo | GA4 | |
|---|---|---|
| Counts opens? | Yes by default (inflated by Apple MPP) | No — clicks only |
| Sees other channels? | No — only Klaviyo messages | Yes — credit is shared across channels |
| Attribution logic | Last touch within its window (5-day default) | Last non-direct click / data-driven, cross-channel |
| What breaks it | Auto-opens, long windows, flows near checkout | Missing UTMs, stripped redirects, broken sessions, ad blockers |
| Bias direction | Overstates email | Understates email |
Your real email contribution sits somewhere between the two. Neither tool will find it for you — which is why the fix below matters more than either dashboard setting.
How do I fix the mismatch?
- Put consistent UTMs on every email and SMS link. Turn on Klaviyo's automatic UTM tagging so every link carries
utm_source=klaviyo(or your convention) andutm_medium=emailorsms, with campaign and flow names filled in automatically. Hand-typed UTMs drift —Emailvsemailsplits one channel into multiple GA4 rows. - Switch Klaviyo's email attribution to clicks only. Mail Privacy Protection poisoned opens as a signal. Revenue-per-campaign drops on paper, gets more truthful in reality.
- Shorten the attribution window. A 5-day window on a high-frequency send schedule attributes half the store to email. Tighten it (many operators use 24–48 hours for campaigns) and accept the smaller, defensible number.
- Audit your redirects. Click a link in a real sent email on a real phone and inspect the final landing URL. Link shorteners and SMS link wrappers can drop query parameters in transit — if the UTMs aren't in the address bar at the end, GA4 never saw them.
- Compare like for like. Set Klaviyo to click-only with a short window before putting it next to GA4's email row. It still won't match — but it'll be explainably different, which is the actual goal.
- Pick one flow — Abandoned cart is the classic suspect — it fires closest to the money
- Exclude 10% at random — Eligible profiles who never receive the message, chosen randomly
- Run it long enough — A few hundred people per group before you read anything into it
- Compare purchase rates — Flow group against holdout; the difference is what the flow actually earns
- Budget off that number — If the holdout converts nearly as often, the flow is mostly photobombing
What does "incremental" mean, and how do I test it without a data team?
Incremental revenue exists because the message was sent — and the only way to measure it is to not send the message to some people. That's a holdout test. The poor man's version:
- Pick one flow — abandoned cart is the classic suspect.
- Randomly exclude a slice of eligible profiles — say 10% — so they never receive it.
- Run it long enough to accumulate a few hundred people per group.
- Compare purchase rates: flow group vs holdout. The difference is what the flow actually earns. The dashboard number is everything it claims.
If the holdout converts nearly as often as the flow group, the flow is mostly photobombing. Keep it (it's nearly free), but budget off the incremental number.
Why is first-party server-side tracking the real fix here?
Because the root problem isn't Klaviyo or GA4 — it's that you have no neutral ledger to reconcile them against, and the browser-based tracking feeding GA4 is itself losing data.
Plain-language version, since the term gets thrown around loosely: today your tracking scripts run in the customer's browser. Ad blockers eat them. Safari's Intelligent Tracking Prevention caps their cookies to days. In-app browsers from mail and SMS apps fragment their sessions — precisely why GA4 undercounts email clicks. Server-side tracking moves that work to a server you control: the browser sends one event to a tagging endpoint on your own subdomain (first-party, so privacy tools treat it as your site talking to itself), and your server forwards clean, complete events to GA4, Meta, Google Ads, and the rest.
For the email attribution mess, that buys you three things. The click-to-purchase path stops leaking: first-party cookies survive longer, so the email session and the purchase actually connect in GA4 instead of splintering into "direct." Purchases get recorded server-side from your backend — with order IDs and an event_id for deduplication — so there's one authoritative Purchase count that matches your store admin. And every platform reconciles against that same ledger: when Klaviyo claims 30% and GA4 says 8%, you line both up against real backend orders and see who's exaggerating. It's the same architecture that fixes Meta and Google Ads tracking. The channels differ; the ledger is the fix.
Frequently asked questions
Why doesn't my Klaviyo revenue match GA4?
Klaviyo attributes orders to opens and clicks within a multi-day window and only sees its own messages; GA4 requires a clicked link with surviving UTMs and splits credit across channels. Different models — they'll never match.
Is Klaviyo or GA4 more accurate for email revenue?
Neither. Klaviyo overstates email (opens, long windows, no view of other channels); GA4 understates it (lost UTMs, broken sessions, invisible opens). The truth sits between; a holdout test is the only way to pin it down.
Does Apple Mail Privacy Protection affect Klaviyo attribution?
Yes. Since iOS 15, Apple Mail pre-fetches email images including the open-tracking pixel, so affected subscribers register opens automatically. Those phantom opens start attribution windows and claim orders no human response touched.
Why does GA4 show my email traffic as direct?
Usually missing or stripped UTM parameters, or a session break between click and visit — in-app mail browsers and redirects are common culprits. Turn on Klaviyo's automatic UTM tagging and test a real sent email to confirm the tags reach the landing page.
How do I know if my abandoned-cart flow actually makes money?
Run a holdout: randomly exclude around 10% of eligible profiles from the flow for a few weeks, then compare purchase rates between groups. The difference is the flow's real, incremental revenue — usually well below the dashboard's claim.
What attribution window should I use in Klaviyo?
Shorter than the 5-day default if you send frequently — many operators use 24–48 hours for campaigns so windows don't blanket the calendar. Choose it deliberately and read revenue claims with the window in mind.
- klaviyo
- attribution
- sms

