Skip to content

← Atlas

Migrate from Universal Analytics to Matomo: Step-by-Step Guide

Matomo's data model is the closest UA twin — minimal mental-model swap. Cloud or self-host, recreate goals, validate against archive.

Why Matomo, not GA4

If you skipped GA4 deliberately, Matomo is the closest UI/concept analog. Sessions are sessions, goals are goals, custom dimensions are custom dimensions. The mental-model swap is minimal compared to GA4’s event-only world.

If you skipped GA4 reluctantly, Matomo is also the lowest-friction destination — your team’s GA Universal muscle memory mostly carries over.

Pre-migration checklist

  1. Decide deployment. Matomo Cloud (€19+/mo, EU-hosted, managed) vs self-host (PHP + MySQL + 2GB RAM, ongoing patching).
  2. Inventory UA goals + custom dimensions. Matomo replicates ~95% of UA’s data model.
  3. Plan e-commerce. Matomo has native cart/checkout/refund tracking via `_paq.push` ecommerce calls — different API from UA’s, rewrite required.
  4. Set retention. Matomo defaults to indefinite. Configure 26 months (or per your policy) before launch.
  5. Archive UA. Same urgency as any UA migration — Google has signalled “early 2026” deletion.

Step-by-step

1. Archive UA (Days 1–3)

bash Export UA
<br />
ga-export \<br />
  –property=UA-XXXXX-X \<br />
  –output=/archive/ua-export.parquet \<br />
  –dimensions=date,source,medium,campaign,landingPage \<br />
  –metrics=sessions,users,pageviews,bounceRate,goalCompletions<br />

2. Provision Matomo (Days 3–6)

Cloud: signup, get site_id, copy tracking code. 10-minute job.
Self-host: composer create-project matomo/matomo, configure DB, run web installer, generate site_id.

html Matomo tracking code
<br />
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
  var u = "https://stats.example.com/";
  _paq.push(['setTrackerUrl', u + 'matomo.php']);
  _paq.push(['setSiteId', '1']);
  var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
  g.async = true; g.src = u + 'matomo.js';
  s.parentNode.insertBefore(g, s);
})();
</script><br />

3. Recreate goals (Days 6–8)

Each UA goal → Matomo goal with the same trigger logic. UA destination goals → Matomo URL-match goals. UA event goals → Matomo trackEvent calls.

js UA event goal → Matomo
<br />
// UA: trackEvent(‘Account’, ‘sign_up’, ’email’)<br />
// Matomo equivalent<br />
_paq.push([‘trackEvent’, ‘Account’, ‘sign_up’, ’email’]);<br />

4. Map custom dimensions (Days 8–10)

Matomo also calls them “Custom Dimensions” — same nomenclature. Configure in admin, set scope (action vs visit), wire to your data layer.

js Custom dimension
<br />
_paq.push([‘setCustomDimension’, 1, ‘logged-in’]);<br />
_paq.push([‘trackPageView’]);<br />

5. Configure GeoIP + retention (Day 10)

Cloud handles GeoIP. Self-host: install MaxMind DB (`./console diagnostics:run`). Set retention period under Admin → Privacy.

6. Validate (Days 10–21)

UA isn’t collecting, so no live parallel run. Validate against your server logs and your archive. Use the Parallel-Run Validator to compare Matomo’s first month vs UA archive’s last month — expect double-digit deltas.

Common gotchas

  • E-commerce schema is rigid — Matomo doesn’t accept arbitrary item arrays. Restructure your data layer before sending purchases.
  • Reporting API rate limits — Heavy Looker Studio dashboards hit limits. Cache aggressively.
  • Self-host backup discipline — Matomo’s archive tables grow fast. Daily MySQL backup + monthly archive purge required.
  • Plugin compatibility — Premium plugins (Heatmaps, Form Analytics) cost extra. Verify versions before promising features.

Frequently asked

Cloud vs self-host?

Cloud if traffic <500k pageviews/mo and no ops appetite. Self-host if you need data residency, EU compliance, or have >2M pageviews/mo (Cloud climbs fast).

Can I import UA historical data into Matomo?

Partially — Matomo’s Log Analytics CLI ingests Apache/nginx access logs, useful for backfilling pageview history from raw server logs. Event-level history doesn’t migrate.

Will Looker Studio work?

Yes via Reporting API + community connector. Performance is slower than GA4’s native connector. Cache.

What about Google Ads remarketing?

Matomo doesn’t replace ad-platform audiences. Run Google Ads Customer Match or server-side conversion APIs separately.

LCP impact of Matomo's tracker?

matomo.js is ~25 kB gzipped — heavier than Plausible (~1.4 kB), lighter than GA4 (~87 kB). Async loading recommended.