MuninMunin
Sign inStart free
Home/Journal/Analytics that sits next to the customer record.
Engineering · 10 min read

Analytics that sits next to the customer record.

Plausible stores nothing on the device. Matomo sets a 13-month cookie by default. PostHog's repository is MIT except the `ee/` directory. Here is what each of them actually stores and licenses, read off their own pages — and how to stand up analytics that can tell you which reader became a customer.

Shot square-on and close, a floating pale-oak shelf in a bright modern hallway holds a slim ceramic holder of plain white cards standing in a row, with one gap where a card has been taken out and laid flat beside it, and a figure walking past far behind — a record you can remove a row from.
The row that isn't there any more.

Somewhere in your account there is a dashboard with a line going up. It says 4,180 people came last month and most of them left immediately. It cannot tell you which of them is paying you now, because the people who pay you live in a different system, behind a different login, run by a different company. The number is real. It just doesn't connect to anything.

What makes an analytics tool privacy-first?

Three things, and all three are checkable in about ten minutes. It either stores no persistent identifier on the visitor's device or tells you exactly what it stores. It does not retain raw IP addresses. And the data sits somewhere you chose — your own database, or a cloud region you picked. Everything else on a privacy page is copywriting.

The reason to check rather than trust is that the field genuinely differs on all three, and the differences are not the ones the marketing implies. One of the products below stores nothing at all in the browser. One sets a first-party cookie with a thirteen-month lifetime unless you go and turn it off. One stores its identifiers in a cookie and in local storage by default. They are all described as privacy-friendly, and they are all telling the truth about themselves — the phrase just covers a lot of ground.

Which privacy-first analytics tools are worth looking at in 2026?

Plausible, Matomo, Umami, PostHog and Fathom, and they are not interchangeable. Plausible is the strictest on device storage and hosts only in the EU. Matomo is the most complete and the only one here with heatmaps and session recording. Umami is the smallest MIT option. PostHog is a full product-analytics suite with a million free events a month. Fathom is hosted-only.

Prices below were read off each vendor's own pricing page on 17 August 2026 and are indicative: every one of them has tiers, toggles and volume bands that a table cannot carry.

  • Plausible AnalyticsPlausible CE is AGPL-3.0-or-later; the JS tracker is separately MIT. Its data policy is the strictest of the five — "We do not use cookies, browser cache or local storage" — and visitors are counted with a hash of a daily rotating salt plus IP, user agent and domain, with the salt deleted every 24 hours and raw IPs never stored. Cloud is EU-only, on servers in Germany. Starter is listed at $9 a month for 10,000 monthly pageviews.
  • MatomoGPL-3.0-or-later, the most feature-complete option here, and the only one with heatmaps, session recording and A/B testing. The default tracking code sets first-party cookies: _pk_id carries a visitor id for 13 months. Cookieless operation is a setting you switch on, not the default. IP masking is on by default at two bytes, which Matomo's own documentation warns "is often still personal data". Cloud is hosted in Frankfurt; Business is listed at 29 a month excluding tax for 50,000 hits.
  • UmamiMIT, with no separately-licensed directory in the repository. The tracking code sets no cookies; it reads one umami.disabled key from local storage and never writes one. Sessions are identified by a hash of IP address, user agent and website id. Cloud has a free Hobby tier at 100,000 events a month and Pro at $20 a month for a million. Cloud servers are in the US and the EU.
  • PostHogProduct analytics, session replay, feature flags and experiments in one product, with 1,000,000 events a month free. By default the JS library stores its identifiers in both a cookie and local storage, and the cookie expires after 365 days; a cookieless server-hash mode exists and has to be turned on. EU organisations default to IP capture off. Cloud is Virginia or Frankfurt, chosen at signup.
  • Fathom AnalyticsHosted only — the current product's source is not published, and the open-source Fathom Lite is MIT but is maintained rather than developed. The hosted tracker is cookie-free, and raw IPs are kept for security only and never form part of customer data. EU isolation strips the IP inside the EU and then stores the anonymous row on US servers. From $15 a month for 100,000 pageviews across 50 sites.
  • Munin analyticsMIT throughout, with no ee/ or extra/ directory and no separately-licensed subtree. The tracker sets no cookies and writes one random uuid to local storage. The client IP is used for a country lookup against a database on your own disk and is never persisted. Events land in analytics_view_events in the same Postgres as the contacts, conversations and articles. Cloud Free is €0 a month; self-hosting has no volume meter.

Read the directory, not the badge

Two of these repositories carry a licence badge that doesn't cover all the code in them. PostHog's root LICENSE puts everything outside ee/ under MIT and everything inside it under the PostHog Enterprise License. Plausible's extra/ directory holds the Enterprise Edition, which Plausible says it grants no rights to use or distribute — and it ships no licence file of its own. Both companies documented the split in their own release notes. A one-word badge cannot.

How do I set up privacy-first analytics on my own site?

Two calls and one line of HTML. Mint a tracker key with analytics_create_tracker, naming the exact origins allowed to use it. Paste the script tag into your layout with that key in data-key. The bundle fires one page view on load and later enriches that same row with dwell time and scroll depth. There is nothing else to configure and no SPA flag to set.

The key is public by design. It resolves to one org and can only write view events — it can never read them — so shipping it in your page source is the intended behaviour, the same way a measurement id is.

jsoncmint the key, then paste the tag
{
  "name": "analytics_create_tracker",
  "arguments": {
    "name": "example.com marketing site",
    "allowedOrigins": ["https://example.com", "http://localhost:3000"]
  }
}

// → { "trackerId": "atr_…", "trackerKey": "mn_track_…" }   shown once

// then, in your layout:
// <script async
//   src="https://api.getmunin.com/tracker.js"
//   data-key="mn_track_…">
// </script>
  • 01One tracker per site, not one per org. Every row records the tracker that wrote it, so separate keys are what lets you ask how the docs site is doing rather than only how everything is doing. Sharing a key merges two sites permanently — past rows keep the tracker they were written with.
  • 02allowedOrigins is required and exact. Scheme, host and port, no wildcards, no path prefixes. List production, staging and localhost separately. The Origin header is browser-set and spoofable, so treat this as hygiene rather than as a security boundary; rotation and per-IP rate limiting are the real defences.
  • 03Country resolution is opt-in and local. Set MUNIN_GEOIP_DB_PATH to a MaxMind-format country database on your own disk. The reader memory-maps it once at boot, so there is no per-request network call to anyone. Leave it unset and the column stays null.
  • 04Fold locale prefixes you can't infer. /en/pricing on a page declaring lang="en-US" is folded to /pricing automatically. A prefix that disagrees with the tag — /no/priser on lang="nb-NO" — needs naming once with analytics_update_tracker({ canonicalLocales: ["no"] }), and it applies from the next event with no redeploy.
  • 05Rotation is revoke plus create. analytics_revoke_tracker 401s the old key immediately; analytics_list_trackers gives you id, name, prefix, last-used and revoked-at for the audit. To stop tracking one page, delete the script tag from it — the bundle is per-page-load opt-in.

What does the tracker put in a visitor's browser?

One key in local storage, holding a random uuid. No cookies, and nothing else. The uuid is what makes a returning reader count as the same reader rather than as two, and it carries no name, no email and no IP address. Plausible is the strictest answer in this field on exactly this point — it stores nothing on the device at all — so if a zero-storage tracker is a hard requirement, that is the one to buy.

What the uuid buys you is a deletion story you can actually execute. The identifier is a random value in a table in your own Postgres, so "delete everything about this visitor" is DELETE FROM analytics_view_events WHERE visitor_id = $1 and it is finished — not a support ticket, not a 30-day window, not a data-subject request routed through a processor in another jurisdiction.

The rest of the row is deliberately thin. The client IP is read once, at request time, to resolve a country against a database file sitting on your own disk, and is never written down. dwell_ms counts only the time the page was actually visible. read_depth is one of four scroll milestones. There is no fingerprint, no cross-site identifier, and nothing that survives the visitor clearing site data. And because the tracker is a script tag rather than a platform integration, the unit of opt-out is a page: remove the tag and that page stops reporting.

The test

If a reader emailed you today asking what you hold about them, could you answer from your own database — or would you have to ask a vendor?

That is a question for your counsel rather than for a vendor's front page, and the honest answer is that it depends where you are. ePrivacy Article 5(3) governs "the storing of information, or the gaining of access to information already stored, in the terminal equipment of a subscriber or user". It never mentions cookies, and the EDPB's Guidelines 2/2023 name local storage explicitly as in scope.

So the scope question is settled and the consent question is not. The EDPB says so directly: the guidelines cover what Article 5(3) applies to, and refer the exemptions to "the relevant member state transposition(s), and guidance issued by national Competent Authorities". Those transpositions are not identically worded. France's CNIL treats trackers whose purpose is limited to audience measurement as strictly necessary — conditioned on exclusive first-party use, no cross-site tracking and no transmission to third parties. Germany's DSK declines to bless a general exemption. The UK gained a statutory statistical-purposes exception through the Data (Use and Access) Act 2025, conditioned on clear information and a free, simple means of objecting rather than on consent.

Two practical consequences. If your rule is no storage on the device, ever, then Plausible and Fathom's hosted tracker are built for that rule and it is a good reason to pick one of them. And whatever you pick, the useful property is that you can describe it precisely: one local-storage key, one random uuid, no cookies, no retained IP, a country derived from a file you installed, and a one-line deletion path. That is the answer a DPO can work with, and it is the same reasoning we applied to what EU data residency actually covers. None of this is legal advice — it is the set of facts your lawyer will ask you for.

Every analytics tool can tell you a page was read 4,180 times. The question worth paying for is which of those readings turned into a customer.

What can you ask when analytics sits next to the customer record?

Questions that normally need two systems and a join nobody wrote. Which articles a named lead read before booking a call. Which search queries came back empty last month. Where the drop-off is between the pricing page and the second onboarding step, counted as an ordered sequence rather than as three unrelated totals. These are one tool call each because the events and the contacts are rows in the same database.

analytics_get_contact_journey is the one that changes how a week feels: page views, searches and conversations for one contact, in order. It works because mn.analytics.identify links an anonymous visitor to a known end-user when — and only when — you decide to, and analytics_get_funnel then groups by the identified person, so the anonymous-to-identified transition doesn't get counted twice. That is the whole argument behind asking which article closed the deal, made concrete.

The second habit is smaller and pays faster. analytics_list_zero_result_searches returns the queries that came back with nothing — readers telling you, in their own words, what you have not written yet. Point your site search at it with mn.analytics.trackSearch and the list stops being about Munin's own search and starts being about your whole site.

jsonctwo questions, two calls
// What did this lead read before they booked?
{
  "name": "analytics_get_contact_journey",
  "arguments": { "contactId": "cct_…", "sinceDays": 90 }
}

// Where do people fall out between pricing and onboarding?
{
  "name": "analytics_get_funnel",
  "arguments": {
    "steps": [
      { "subjectType": "page", "subjectId": "/pricing" },
      { "subjectType": "page", "subjectId": "/signup" },
      { "pathLike": "/onboarding/%" }
    ],
    "sinceDays": 30,
    "stepWindowHours": 24
  }
}
0
raw IP addresses persisted
1
line of HTML to install
204
MCP tools at one endpoint
€0
Munin Cloud Free, per month

Which one should you pick?

Pick Plausible if the requirement is nothing stored on the device and nothing hosted outside the EU, and traffic numbers are all you need. It is the cleanest expression of that position anyone ships, and its data policy is worth reading even if you buy something else.

Pick Matomo if you want heatmaps, session recording, A/B testing or a decade of ecommerce reporting. Check the plugin page first: several of those live in separate, unpublished plugins under InnoCraft's EULA rather than in the GPL core, which is a fair commercial model and a thing to know before you plan around it.

Pick PostHog if you are instrumenting a product rather than a website. A million events a month free with replay and feature flags is a genuinely strong offer, and the MIT core is real — the ee/ directory is the part that isn't.

Pick Umami if you want the smallest MIT thing that works and you will run it yourself.

There is no session-replay tool, heatmap tool, or A/B-testing tool in Munin's analytics module. Pick Munin when the question you keep failing to answer is not how many but which one: which reader became a lead, which article the lead read twice, which search came back empty the week before they wrote in. Those answers need the page view and the customer to be rows in the same database, which is what Munin is — six modules, one Postgres, one licence with nothing held back. The analytics module is eighteen of Munin's 204 MCP tools, so the same endpoint that answers what did this lead read also files the follow-up, updates the record and publishes the article. And it runs on your machine with three containers and one command if you would rather it never touched anyone else's.

Frequently asked questions

What is the best privacy-friendly alternative to Google Analytics? It depends which of three things you are optimising for. For the strictest device-storage position, Plausible: it stores nothing in the browser at all, hosts only in the EU, and starts at $9 a month for 10,000 pageviews. For feature depth, Matomo, which is GPL-3.0 and self-hosts for free. For analytics that joins to your customer record, Munin, which is MIT and €0 on Cloud Free.

Is Plausible really cookie-free? Yes, and it goes further than that. Plausible's data policy states that it uses no cookies, no browser cache and no local storage, and that raw IP addresses and user agents are never stored — visitors are counted through a hash built on a salt that is rotated and deleted every 24 hours. It is the strictest published position among the tools compared here.

Is PostHog open source? Mostly, and the exception is documented in the repository. PostHog's root LICENSE places everything outside the ee/ directory under MIT, and everything inside ee/ under the PostHog Enterprise License, which requires a paid subscription for production use and forbids redistribution. Plausible has a comparable split: the extra/ directory holds Enterprise Edition code that Plausible grants no rights to use or distribute.

Do I need consent to store an identifier in local storage? Article 5(3) of the ePrivacy Directive applies to "storing of information, or the gaining of access to information already stored, in the terminal equipment" and does not mention cookies at all; the EDPB, CNIL, the ICO and Germany's DSK all name browser local storage as in scope. Whether consent is then required depends on national transposition — France exempts first-party audience measurement under conditions, the UK added a statistical-purposes exception in 2025, Germany has not issued a general one. Ask your counsel; this is not legal advice.

Can I self-host analytics without running a separate analytics server? With Munin, yes — the tracker endpoint, the event tables and the query tools are part of the same install as the CRM, inbox, knowledge base and CMS. There is no second database, no second container and no second set of credentials to rotate.

Can an AI agent query my analytics? Yes. Munin's analytics tools are MCP tools on the same endpoint as everything else, so "which pages did this lead read before booking" is a question you ask in those words from Claude, Claude Code, Cursor, ChatGPT or a runner you wrote. Several other vendors in this comparison also publish MCP servers; the difference worth weighing is what sits behind the endpoint, not whether one exists.

The short version

  • Privacy-first is three checkable facts: what is stored on the device, whether raw IPs are retained, and which region holds the data. Read the vendor's own documentation rather than the badge.
  • The field is real and it differs. Plausible stores nothing in the browser; Matomo sets a 13-month first-party cookie by default; PostHog uses a cookie and local storage by default with a 365-day expiry.
  • PostHog's ee/ directory and Plausible's extra/ directory hold code under terms the repository's headline licence does not cover. Both companies say so in their release notes.
  • Munin's tracker sets no cookies, writes one random uuid to local storage, never persists an IP, and resolves country from a database file on your own disk.
  • Deletion is one SQL statement against your own Postgres, because the events live in your database rather than a vendor's.
  • The payoff for keeping analytics next to the customer record is analytics_get_contact_journey and analytics_get_funnel: which reader became a customer, and where the rest fell out.
  • Munin is MIT with no separately-licensed subtree, 204 MCP tools and 218 REST endpoints over the same data, and €0 a month on Cloud Free.

Mint a tracker key, paste one script tag, and see what people actually read — Munin Cloud is free to start, and the tracker and every query behind it are MIT on GitHub.

Privacy-first isn't a badge on a pricing page. It's a row you can delete.