Two entries on that list get miscounted constantly, so to be explicit:
Microsoft Clarity is not self-hostable. Its capture library is MIT licensed on GitHub, which is genuine and useful, but it is a set of TypeScript packages (clarity-js, clarity-decode, clarity-visualize, clarity-devtools), not a deployable backend. Running Clarity means sending your data to Microsoft.
Matomo's session recording is not open source. Matomo core is, and that is often what people remember. The Heatmap and Session Recording plugin is licensed under the InnoCraft EULA and sold per user tier. You can self-host it, you cannot fork it.
Why teams self-host, and which reason is yours
The three reasons are different and they point at different tools, so it is worth knowing which one you actually have.
Reason one: you are not allowed to send it anywhere. Health, finance, public sector, EU organisations with counsel who has read a wiretapping complaint. For you, self-hosting is not a preference and cost is not the constraint. What matters is that the deployment is small enough to get through review and that you can evidence deletion. The relevant detail is that US wiretapping suits under statutes like California's CIPA turn substantially on the site having transmitted visitor interactions to a third-party vendor. Self-hosting does not make you compliant with anything, and anyone who tells you software does is selling. It does remove that specific factual element, and it removes the international transfer question entirely if your database is in the same jurisdiction as your users. The GDPR guide works through the mechanisms.
Reason two: per-session pricing does not fit your traffic. Hosted session replay is priced per session, so your bill scales with engagement, which is the thing you are trying to increase. At high volume the arithmetic stops working and self-hosting becomes a straightforward storage question.
Reason three: you want the recordings to outlive the vendor's retention window. Hosted retention is a plan feature and it is shorter than people expect. Microsoft Clarity keeps playback data for 30 days, after which its own docs say only 1% of your recordings or 10 per day, whichever is higher, survive for up to 9 months. PostHog's replay retention is 30 days on free, 90 days on pay-as-you-go, a year on Boost and Scale. LogRocket's extended one year retention is Pro and above and capped at 5% of your quota. Self-hosted, retention is a number you choose and a disk you buy.
If your reason is one or three, the operational surface below is the whole decision. If it is reason two, do the storage math first, because at genuinely large volume the ClickHouse-based tools have a real efficiency argument.
The operational surface is the actual decision
Here is the thing nobody puts on a comparison page: the reason self-hosted analytics gets abandoned is almost never that the software was bad. It is that six months later there is a Kafka consumer lag alert at 2am and nobody remembers who owns it.
So count the systems.
OpenReplay documents deployment on AWS, GCP, Azure, DigitalOcean, Scaleway and OVHcloud, via Ubuntu, Kubernetes, Docker or source. The stack behind it is Postgres plus ClickHouse plus Redis plus its backend services. It is a real, mature, well-documented distributed system, and it is a distributed system.
PostHog is the most capable product on this list by a wide margin, and it is the one whose own documentation argues hardest against self-hosting it. Their docs state that self-hosted deployments are officially unsupported, that they do not offer customer support for product, infrastructure or other questions on self-hosted instances, and, decisively for most readers, that all paid-plan features are cloud only. Their own disclaimer says the self-hosted open-source deployment is made for hobbyists or for hosting PostHog in weird and wonderful ways, and is unlikely to scale past a couple of hundred thousand events without significant effort. Their alternatives page concedes plainly that self-hosting PostHog is operationally complex at scale and names self-host-first tools as better for that use case. Take them at their word. They are being unusually honest and it is a credit to them.
Filmroom is one Docker image plus one Postgres database. Migrations run on boot. There is no ClickHouse, no Redis, no Kafka, no separate worker fleet, no object store to configure. Events are stored as gzip-compressed chunks in Postgres, and inlined image assets are hashed and deduplicated so a repeated logo is stored once rather than once per snapshot. The container serves the recorder script, the ingest endpoint, the API and the dashboard, so the whole deployment is one process to watch and one database to back up.
That is the trade we made, deliberately, and it has a ceiling. A single Postgres instance is not the right architecture for tens of millions of sessions a month, and we would rather say so than sell you a story about infinite scale. If you are at that volume, the ClickHouse-based options exist for a reason.
What it costs to run
Honest answer: less than people expect, and nobody in this category publishes the math, which is itself telling.
The cost is storage plus a small always-on compute footprint. Events compress well because a DOM mutation stream is highly repetitive. The variable that actually dominates is images, because Filmroom inlines them at record time (encoded as webp) so replays stay self-contained and do not break when the original URL stops resolving, which is the failure the Next.js guide covers in detail. An image-heavy app stores meaningfully more per session than a text-heavy one. Deduplication by content hash takes most of the sting out of that, since the same assets recur across every snapshot of every session.
The number we will stand behind: about 20 KB of compressed event data per minute of recorded session, measured on a controlled visit to a reference page. Images are the separate, additive term, and each unique image is stored once, deduplicated across all sessions, so an image costs storage the first time any visitor sees it rather than on every recording. The practical consequence is that the first visitor to a page funds its images and every later session on that page stores roughly the event stream alone. Our methodology is in docs/perf/measurements.md in our repository, including why there is no single honest bytes-per-session figure.
Two things we are deliberately not publishing yet, rather than estimating them. The container's baseline memory and CPU at rest have not been measured, so there is no figure for them above. Neither are there production storage percentiles: real-traffic medians would have to come from a live database, and until that is measured the per-active-minute figure is the only storage number here.
Two controls matter more than the per-session number anyway: an age-based retention limit in days, and a total storage cap that prunes the oldest unpinned recordings once you cross it. There are also low-value disposal rules that discard sessions under a wall-clock duration or under an amount of genuinely active time, which is how you avoid paying to store ten thousand three-second bounces. Anything pinned is exempt from every pruner, and a session that hits a conversion goal is pinned automatically.
A technical opinion: should you just build it on rrweb?
Every tool on this page except Matomo is built on rrweb, which is MIT licensed. So the honest question is whether you need a product at all.
You should build it yourself if the requirement is "capture sessions from one internal app and let three engineers watch them". rrweb plus an endpoint that writes gzipped batches to Postgres plus its Replayer in an iframe is a weekend. We know, because that is where Filmroom started.
The reason it stops being a weekend is a list of things that are individually unglamorous and collectively months:
fetch with keepalive and sendBeacon cap bodies at roughly 64 KB, so events must be chunked with a single in-flight guard, and chunks arrive out of order and have to be sorted on read.- Sessionization. A new session id after 30 minutes idle or 30 minutes total age, per tab, or a left-open tab becomes one eight hour session.
- Assets. Store images by reference and your replays rot, because framework image transforms change across deploys, auth-gated assets return a login page to the player, and
blob: URLs die with the tab. Inline them and you need content-hash deduplication or your storage explodes. - Masking that you can trust, plus a way to find the sensitive data somebody forgot to mask.
- Error capture that groups into issues rather than listing 400 copies of one bug, which means a fingerprint that normalizes build hashes and ignores line numbers, or every deploy forks your list.
- Retention, storage caps, and disposal of worthless sessions.
- Auth, roles, and the entire dashboard: search, filters, sorting, pagination, the player timeline.
- And the actual hard one: nobody watches the recordings, so you need triage, which is the problem the AI layer exists to solve.
Build the weekend version. It is genuinely useful and you will learn what you need. Just cost the list above before committing to it as infrastructure.
What the open source options do better
Real, and if any of these is load-bearing for you, pick accordingly.
- You can read and fork the source. Filmroom is proprietary. OpenReplay is AGPL v3, PostHog is MIT outside its
ee/ directory. If auditable source is a hard requirement, whether for security review or for insurance against us disappearing, that is a legitimate requirement and we do not meet it. - Zero licence cost. OpenReplay and PostHog self-hosted are free software. Filmroom is a paid product you run yourself.
- OpenReplay has mobile SDKs, co-browsing, live session viewing, video calling and remote control. Filmroom has none of those. It is web plus Electron.
- OpenReplay and LogRocket log network requests. Filmroom does not.
- PostHog is a whole platform: product analytics, feature flags, experiments, surveys, data warehouse. Filmroom does session replay and the insight layer on top of it. If you want one vendor for everything, we are not it, and PostHog Cloud is a genuinely good answer.
- ClickHouse-backed storage is the better architecture at very large event volume. That is not marketing, it is what the database is for.
Pick something else if
- You need auditable source. OpenReplay (AGPL v3).
- You need mobile session replay, co-browsing, or live session viewing. OpenReplay.
- You need an analytics platform, not a replay tool. PostHog, and use their cloud rather than self-hosting it, because their own docs tell you to.
- You are at tens of millions of sessions a month. OpenReplay or PostHog Cloud.
- You want free with no traffic cap and can live with 30 day playback retention. Microsoft Clarity, hosted. It is genuinely good and its masking defaults are the strongest of the incumbents (inputs masked in all modes and not even configurable).
- You already run Matomo and want recordings in the same place. Matomo's plugin, understanding that the plugin itself is a paid, non-open-source licence.
Pick Filmroom if
You want the smallest thing that is actually a product. One container, one Postgres, masking on by default, and an AI layer that reads the sessions so the recordings do not just accumulate.
Concretely, what you get for running it yourself:
- Every input masked in the browser before transmission, plus element-level text masking and blocking, route-level
data-deny globs that keep a page from loading the recorder at all, and a do-not-record list matched at ingest by IP, email or identity. - Automatic detection of sensitive data in rendered text (emails, Luhn-valid card numbers, dashed SSNs, prefixed secret tokens), filed as redaction flags with a selector and rolled up across sessions so you fix the component once.
- Self-contained replays. Images inlined at record time and deduplicated by content hash, so a replay still works when the original asset URL is gone.
- Errors grouped into issues, linked to the replay where they happened, marked on the player timeline, and surviving the recording being deleted.
- Conversion goals as URL patterns or
track() calls, which retro-match your existing history when you define them, so a goal created today already has numbers. Converting sessions are pinned automatically so no pruner touches them. - AI that reads the sessions worth reading, with your own Anthropic or OpenAI key, no markup, a monthly token budget you set, and a hardcoded gate so tokens are not spent narrating somebody reading one page and leaving. Every number in the weekly report is computed in SQL before the model is called; the model is limited to a short note per row and cannot produce a metric.
- First-touch attribution that follows a visitor across tabs, subdomains and return visits, and deliberately ignores OAuth and hosted-checkout bounce referrers so a return from Stripe is not credited as the channel that acquired the customer.
The install guide shows the snippet and the CSP directives, and pricing is published on the product page.