How to merge email campaign results with GA4 conversions
By the Analistable team · Updated · 6 min read
Make sure every email link carries utm_source, utm_medium=email and a utm_campaign that identifies the send. Export campaign stats from your email platform and a GA4 report of sessions, key events and revenue by session campaign, normalise the campaign values, then join on them. You get sends, clicks, sessions and conversions on one row per email.
Part of our guide: How to answer questions across multiple spreadsheets
Why the two sides need joining
Your email platform (Mailchimp, Klaviyo, Brevo and similar) knows who received and clicked each email. GA4 knows what those visitors did on the site. Neither knows both. The email platform's own revenue figures, where it has them, use its own attribution rules; GA4's use GA4's. Joining them on the campaign shows the full path — 20,000 sent, 600 clicked, 540 sessions, 27 purchases — and makes the gaps between steps visible.
Tag the links consistently
The join key is utm_campaign. Many email platforms can add UTM parameters automatically when you enable Google Analytics link tracking, often using the campaign name or a slug of it. Check what yours writes by clicking a link in a test send and reading the URL. A reliable convention:
| parameter | value | example |
|---|---|---|
| utm_source | your platform or list | newsletter |
| utm_medium | always email | |
| utm_campaign | date + short name | 2026-09-17_autumn_sale |
| utm_content | link position (optional) | hero_button |
Put the send date in the campaign value. Without it, “autumn_sale” from this year and last year merge into one row.
What to export
- Email platform: one row per campaign with campaign name (or the UTM value if the export includes it), send date, recipients, opens, unique clicks, unsubscribes.
- GA4: an Exploration (free form) with Session campaign, Session source / medium as dimensions and Sessions, Key events and Total revenue as metrics, filtered to Session medium = email. Use the same date range as the sends, plus a few days after the last send for late clicks.
GA4 renamed “conversions” to “key events” in 2024, so older guides and exports may use either name. Analistable can also pull GA4 directly through its Google Analytics connection, which fetches the report on the server and loads the rows into your browser — useful when you'd rather not rebuild the Exploration each month.
Opens are unreliable since Apple Mail Privacy Protection began preloading images, which inflates open counts. Use clicks as the email-side engagement metric when joining to GA4.
Normalise and join
GA4 records utm_campaign as sent; the email export may hold the human campaign name. If they differ, build a small mapping table, or, if your platform generated the UTM from the name, reproduce its rule (lowercase, spaces to underscores). Then join:
SELECT e.campaign_key, e.recipients, e.unique_clicks,
g.sessions, g.key_events, g.revenue,
g.sessions * 1.0 / NULLIF(e.unique_clicks, 0) AS sessions_per_click,
g.key_events * 1.0 / NULLIF(g.sessions, 0) AS conversion_rate
FROM (
SELECT LOWER(TRIM(utm_campaign)) AS campaign_key, recipients, unique_clicks
FROM email_campaigns
) e
LEFT JOIN (
SELECT LOWER(TRIM("Session campaign")) AS campaign_key,
SUM("Sessions") AS sessions, SUM("Key events") AS key_events,
SUM("Total revenue") AS revenue
FROM ga4_email
GROUP BY 1
) g ON g.campaign_key = e.campaign_key
ORDER BY revenue DESC NULLS LAST;Worked example: September sends
| campaign | recipients | unique clicks | GA4 sessions | key events | revenue |
|---|---|---|---|---|---|
| 2026-09-03_new_range | 20000 | 600 | 540 | 27 | 1620 |
| 2026-09-17_autumn_sale | 20000 | 900 | 810 | 54 | 3780 |
| 2026-09-24_how_to_guide | 19800 | 450 | 405 | 8 | 360 |
| Total | 59800 | 1950 | 1755 | 89 | 5760 |
The autumn sale converted 54 / 810 = 6.7% of sessions; the guide converted 8 / 405 = 2.0%, which is fine for a content email but means it shouldn't be judged on revenue. Across the month, 1,755 sessions from 1,950 unique clicks is a 90% click-to-session rate. A much lower rate on one campaign usually means broken tags, a redirect stripping UTMs, or consent-banner losses.
Common problems
- Campaign shows in GA4 as (not set) or (direct): UTMs were stripped by a redirect or link shortener, or the visitor declined analytics cookies.
- Revenue appears weeks later: GA4 attributes key events by its attribution model, and a returning visitor may convert days after the email session. Pick one date basis and stick to it.
- Same campaign value used twice: resends to non-openers often reuse the original UTM. Add a suffix (_resend) if you want them separated.
For GA4 combined with other Google data, see combining Google Analytics and Search Console data and merging GA4 with ad cost data. The cross-spreadsheet guide covers more question types.
Choose the right GA4 dimension
GA4 has several campaign dimensions with different scopes, and choosing the wrong one changes the numbers:
| Dimension | Scope | Use it for |
|---|---|---|
| Session campaign | The session | Traffic and conversions in the session the email started |
| First user campaign | The user's first visit | New users acquired by an email |
| Campaign (event scope) | The key event | Conversions credited by GA4's attribution model |
For a per-send report, Session campaign is usually the right choice: it answers “what did people do in the visit that started from this email?”. Event-scoped campaign uses GA4's attribution model, so a purchase can be credited to an email even when the buying session came from somewhere else. Neither is wrong, but mixing them across months makes trends meaningless. Name the dimension in the report title.
If GA4 reports a campaign as (organic) or (referral), the visit arrived without UTMs. Clicks from webmail can show as referrals from mail.google.com or outlook.live.com when links are untagged, which is another reason to tag every link.
Turn it into a monthly email scorecard
Once the join works for one month, stack months with a month column and keep one row per send. A scorecard with recipients, clicks, sessions, key events and revenue per 1,000 recipients lets you compare sends of different list sizes. Revenue per 1,000 recipients for the autumn sale is £3,780 / 20 = £189; for the new-range email, £1,620 / 20 = £81. That's a fairer comparison than raw revenue when list size changes month to month.
Adding unsubscribes to the picture
Revenue isn't the only outcome of a send. Join unsubscribes and spam complaints from the email export onto the same row and calculate unsubscribes per 1,000 recipients. An email that earns well but loses an unusual number of subscribers may cost more in future revenue than it brings in now. Comparing both on one row is the main reason to keep the email-side columns rather than replacing them with GA4 data.
Frequently asked questions
- Do I need GA4 Explorations, or will standard reports do?
- The standard Traffic acquisition report with Session campaign as the primary dimension works too. Explorations are handier because you can add a medium filter and export exactly the columns you need.
- What if my email platform doesn't add UTMs automatically?
- Add them by hand to each link, or use a URL builder sheet so the campaign value follows the same pattern every time. Without UTMs, GA4 can't attribute the visit to a specific send.
- Should I trust the email platform's revenue or GA4's?
- Neither is wrong; they use different attribution. Use GA4 when comparing email with other channels, because every channel is then measured the same way.
- Can I join at subscriber level?
- Not with standard GA4 reports, which don't expose personal identifiers. Subscriber-level joins need your own user ID tracking and should respect consent and privacy rules.
- Why are GA4 sessions lower than email clicks?
- Some clicks are bot or security-scanner clicks, some visitors decline analytics cookies, and one person clicking twice in one session counts as one session.