← Blog

SEO

GA4, Plausible, Matomo: the migration cheatsheet for agencies

It's Tuesday again. A client wants to know why GA4 says 4,200 sessions and their old UA screenshot says 11,000. Pick the tool, ship the answer by Friday.

Jacob Molkenboer· Founder · A Brand New Company· 4 Jun 2026· 8 min
Three brass map-measurer wheels on a forest-green leather blotter, beside a folded cream card with a chartreuse ribbon.

It's the third Tuesday in a row that the same Slack thread opens: "Why does GA4 say 4,200 sessions when the old screenshot from UA says 11,000?" The client has skimmed a blog post about Plausible, watched a LinkedIn rant about Matomo, and now wants to pick whichever tool will tell the truth. You are the one who has to ship a decision by Friday.

This is the cheatsheet we keep open in a pinned tab when a Dutch client moves off Universal Analytics for the third time. Every line is a gotcha that cost us at least one afternoon. Use it before the kickoff call, not after the report goes out.

GA4: the four numbers that will get you yelled at

Thresholding silently hides data

If a report combines a user dimension with a tiny audience, GA4 drops the row entirely. The threshold is roughly fewer than 50 users in the slice. Google calls this "data thresholding" and it kicks in automatically when Google Signals is on or when demographics are used. On a B2B site with 800 monthly visits, this can hide your top three landing pages from a country breakdown. Google documents the behaviour, but the toggle to turn it off is not in the obvious place. Switch the report identity to "Device-based" before the client sees the dashboard.

Sessions are not what they were

A GA4 session ends after 30 minutes of inactivity, same as UA. But a GA4 session no longer ends at midnight, and it no longer ends when the traffic source changes. A user who clicks a Google Ad at 23:55 and another at 00:05 counts as one session in GA4, two in UA. Tell the client this on the kickoff call. Do not let them discover it inside the first monthly report.

Consent Mode v2 is not optional in the Netherlands

Since March 2024, Google requires Consent Mode v2 on any EEA-targeted account that uses GA4 with Ads remarketing. Without it, the remarketing audience evaporates and the conversion modelling silently switches off. The implementation guide is dry but accurate. Cookiebot, Usercentrics and Complianz all support it, but only if the integration was updated past their April 2024 builds. Older Complianz installs on WordPress will pass ad_user_data=denied even after the visitor accepts. Check the dataLayer with Tag Assistant before declaring victory.

Sampling on the free tier kicks in earlier than the docs suggest

GA4 starts sampling explorations once you cross around 10M events in the date range, not 10M sessions. On a busy e-commerce site that fires view_item on every product card, you hit that in week two. The fix is BigQuery export, which is free up to 1M events per day. Wire it up on day one or you will be re-wiring it on day forty, after the client has already screenshotted a sampled report and sent it to their board.

Warning

If the client wants a year-on-year comparison and they migrated mid-2023, you do not have a baseline. UA stopped collecting on 1 July 2023 and Google deleted the historical data on 1 July 2024. Anything before that lives only in client screenshots or a BigQuery backup someone might have remembered to make.

Plausible: the simple tool with five footnotes

The default script blocks itself

A meaningful share of Dutch desktop visitors run uBlock Origin or a similar list, and the default plausible.io/js/script.js sits on most of them. The fix is the proxy: serve the script from your own domain via Cloudflare Workers, Vercel rewrites, or Caddy. Plausible's proxy guide covers all three. Skip this step and your traffic looks like it dropped 30 percent the day you migrated.

Goals are not events

Plausible calls form submissions "custom events" and pageview-based goals just "goals". A Mailchimp signup is a custom event, a /thanks pageview is a goal, and conversion rate is computed differently for each. New users wire up a custom event, then ask why the conversion column is empty. Wire the goal first, the event second.

Outbound links need the extension script

The base script does not track outbound links. You need script.outbound-links.js or the explicit data-domain attribute with outbound-links enabled. We have shipped Plausible to clients twice where the affiliate-revenue page silently stopped tracking for three weeks because nobody flipped the script tag.

No historical import from UA

Plausible does not import GA4 or UA data. Period. If the client wants "last year's numbers in the new dashboard", the answer is no. Build a static comparison page from the UA export CSV, drop it on a hidden URL, and link to it from the dashboard's notes panel.

Matomo: powerful, paid, and easy to misconfigure

The "cookieless" mode still fingerprints by default

Matomo's config_id is a hash of IP plus user agent plus browser plugins. Even with cookies disabled, that counts as a unique identifier under GDPR Article 4(1). The Dutch Autoriteit Persoonsgegevens has been quiet on Matomo specifically, but the same reasoning that troubled GA4 in 2022 applies. Set [Tracker] config_id_cache_timeout = 0 and enable_fingerprinting_across_websites = 0 in config.ini.php, or use the Privacy Manager UI.

Cloud and On-Premise are not the same product

Matomo Cloud bills per hit, runs on matomo.cloud, and includes heatmaps and session recordings as paid add-ons. On-Premise is free, runs on your own server, and the same add-ons cost between €199 and €499 a year as separate plugins from the Matomo Marketplace. Quote the right one. We once quoted a client for On-Premise and had to migrate them mid-project because their procurement team refused to host PII themselves.

Geo-IP needs a paid database

The free GeoLite2 database from MaxMind requires a signup and a cron job to update it. Without that cron, Matomo falls back to a coarser PHP lookup that gets country-level data wrong for IPv6 visitors. Half a Dutch ISP's IPv6 range gets attributed to Germany. Set the cron on day one.

Raw log retention grows forever

Default Matomo keeps raw visitor logs indefinitely. Storage grows linearly. On a 200k-pageview-per-month site, that is roughly 4 to 6 GB per year of MySQL. Set log retention to 90 days unless legal explicitly says otherwise, then segment your dashboards on the aggregate tables.

The three-question decision tree

Before the kickoff, ask the client three questions. The answers pick the tool for you.

  1. Are you still running Google Ads or YouTube Ads? If yes, you need GA4. The Ads-to-Analytics link only works with GA4. Plausible and Matomo cannot fill this role.
  2. Do you need session recordings, heatmaps, or A/B testing in the same tool? If yes, Matomo. The plugins exist and they integrate cleanly. GA4 has nothing native, and Plausible has nothing at all.
  3. Is the only consumer a marketing manager who wants one number per week? If yes, Plausible. Setup is twenty minutes, the dashboard is a single page, and there is no consent banner to argue about because there are no cookies.

Anything else is a hybrid. We run Plausible and GA4 side by side on many client sites: Plausible for the weekly Slack screenshot, GA4 for ad attribution. The duplicated JS is around 4KB. The duplicated mental model is the part that costs you.

The five-minute audit before you commit

Open the client's current GTM container, then run these five checks against the live site. If any of them returns nothing, your migration estimate is wrong by at least a week.

# Run these against the live site before you quote
curl -s https://CLIENT.com | grep -Eo 'gtag\(.config.,.G-[A-Z0-9]+' | sort -u
curl -s https://CLIENT.com | grep -Eo 'plausible|matomo|piwik'
curl -s https://CLIENT.com/robots.txt | grep -i 'analytics\|matomo\|plausible'
curl -sI https://CLIENT.com | grep -i 'content-security-policy'
curl -s https://CLIENT.com | grep -Eo 'data-domain="[^"]+"'

The Content-Security-Policy line is the one most agencies forget. A strict CSP without a script-src entry for the new analytics host means the new tag silently fails and the old one keeps reporting for another week. The client signs off on the report, the migration is declared complete, and three weeks later the numbers go to zero overnight.

What we tell clients on the call

The honest version: there is no analytics tool that gives you the same numbers as UA. The data model changed, the consent regime changed, and the browsers changed. Anyone who promises a 1:1 migration is lying or has not done one yet. Pick the tool that fits the next three years of decisions, not the last three years of reports.

When we rebuilt analytics for a Rotterdam SaaS client last quarter, the thing we ran into was a CSP header we did not control: Cloudflare Pages was injecting one on every response. We solved it with a Worker that rewrote the headers, then wired their process automation to log every analytics deployment back to a Notion table so the next engineer would not have to guess. Boring, but it has caught two regressions since.

The smallest thing you can do today: take the five curl commands above and run them against your three biggest client sites. If any of them returns nothing for the analytics tag, that client's last monthly report was already wrong.

Key takeaway

There is no 1:1 migration from UA. Pick the tool that fits the next three years of decisions, not the last three years of reports.

FAQ

Can we run Plausible and GA4 on the same site?

Yes. The combined script weight is around 4KB. We run both on most client sites: Plausible for the weekly Slack screenshot, GA4 for ad attribution and remarketing.

Is GA4 still legal in the Netherlands in 2026?

Yes, with Consent Mode v2, IP anonymization, and a signed DPA with Google. The Dutch DPA has not banned it. A cookie banner that defaults to denied is mandatory.

Does Matomo Cloud comply with GDPR out of the box?

Closer than GA4, but the default fingerprint-based config_id can still count as a unique identifier. Switch it off in the Privacy Manager before launch.

Can we import historical UA data into GA4 retroactively?

No. Google deleted historical UA data on 1 July 2024. Your only baseline is what was exported to BigQuery before then, or PDF screenshots clients saved.

Why did our Plausible traffic look 30 percent lower than GA4 on day one?

The default plausible.io script is on most adblock lists. Proxy the script through your own domain via Cloudflare Workers or Vercel rewrites and the gap closes.

seomigrationstrategyoperationsintegrationstooling

Building something?

Start a project