If you're choosing between PostHog Cloud and a self-hosted install, start with two checks before anything else. Compare your expected monthly traffic with Cloud's free allowances, and ask whether any contract or regulator says analytics data must stay on infrastructure you control. If the second answer is no, the decision is usually already made.
PostHog bundles product analytics, session replay, feature flags and error tracking behind one SDK. That bundle is the easy part. The choice that eats months when you get it wrong is the hosting one, because it decides whether you spend a quarter building product or operating a database stack nobody signed up to run. This post gives you the numbers from PostHog's own pages, an event-naming convention that survives growth, and a masking setup for session replay.
Is PostHog Cloud enough, or should you self-host?
For most early-stage SaaS products, PostHog Cloud is the right default, and PostHog says as much itself. Its self-hosting page states that Cloud is "far and away the best experience for the vast majority" of users, which is an unusual thing for the maintainers of both options to write.
The free tier is large enough to test that claim. PostHog's pricing page lists a free monthly allowance of 1M analytics events, 5K session recordings, 1M feature flag requests and 100K exceptions, with no credit card required, and it says the allowance renews every month (checked 30 September 2026). The same page states that 97% of companies use PostHog for free. That figure is PostHog's own claim about its own customers, so read it as a signal about typical volume, not as a benchmark for your product.
Run the arithmetic on your own numbers. Consider a hypothetical B2B tool with 500 active users who each trigger 50 tracked events a day. That's 25,000 events a day and about 750,000 a month, still under the 1M free allowance. For many products, event volume isn't the constraint. Data residency is: does a customer contract, a regulator or your own security policy require that analytics data never leaves infrastructure you control?
Use this decision check, in order. This is my recommendation, not a PostHog rule.
- Does a contract or regulator name the location where analytics data must live?
- If yes, does the Cloud EU option in Frankfurt satisfy it?
- If not, can your team own upgrades, backups and incident response for a single-machine deployment without vendor support?
Only a yes to the first question, a no to the second and a yes to the third points toward self-hosting. Any other combination points to Cloud.
When does self-hosting PostHog actually pay off?
Self-hosting pays off when a legal or contractual requirement forces analytics data onto your own infrastructure and PostHog Cloud can't satisfy it. Check that last condition first, because PostHog's privacy documentation describes a Cloud EU option hosted in Frankfurt, so an EU residency requirement alone doesn't force you to run servers.
If you do need control, know what you're taking on. The self-hosting page says you need something equivalent to a Hetzner VM with 4 vCPU, 16GB RAM and more than 30GB of storage. It also says PostHog doesn't offer customer support for self-hosted instances and that new Kubernetes deployments of the open-source product are no longer supported. The open-source disclaimer adds that everything runs on a single machine and is "unlikely to scale past a couple 100ks events without significant effort in scaling." It also lists what self-hosted deployments leave out, including group analytics, data pipelines, multi-environment support and SAML, RBAC and SSO enforcement.
The same page shows a single-command deploy script, which makes a first install fast. In my view, the install isn't the cost. The cost is the ongoing work of upgrades, backups, disk growth and incident response with no vendor support behind you. A single-machine install lives in one place, which is the opposite of the edge computing idea of running work near users. That's my inference about capture latency, not a PostHog claim, and it matters only if your users are far from your server.
Regulated verticals are where this decision gets real. The Callidus case study describes a multi-tenant B2B SaaS for UK aesthetic clinics built on React, Firebase and Stripe Connect, with Sentry configured in strict GDPR mode. Callidus doesn't use PostHog according to that case study, so treat it as an example of how seriously that kind of product takes data handling, not as a PostHog deployment.
PostHog Cloud vs self-hosted: what does the comparison look like?
| PostHog Cloud | Self-hosted (open source) | |
|---|---|---|
| Setup | SDK snippet, managed by PostHog | Your own VM (4 vCPU, 16GB RAM, 30GB+ storage) and a deploy script |
| Support | Managed product | No customer support, "officially unsupported" |
| Data residency | Cloud EU hosted in Frankfurt | Wherever you run it |
| Scale | Managed by PostHog | "Unlikely to scale past a couple 100ks events" on one machine |
| Cost | Free monthly allowance, usage-based beyond it | Your infrastructure plus your engineering time |
| Feature gaps | Full product | No group analytics, data pipelines, multi-environment support or SSO enforcement |
The last row matters most in practice. If you plan to segment by company or account in a B2B product, the disclaimer says group analytics isn't available when self-hosted. Confirm the feature list on that page against your requirements before you commit.
How do you name events so analytics still make sense at 10 million rows?
Name every event with the category:object_action framework in lowercase snake case with present-tense verbs, and define names as fixed strings in code. That's PostHog's own product analytics guidance, and it keeps the event list searchable as it grows. Its examples are account_settings:forgot_password_button_click and signup_flow:pricing_page_view, and it says to use "submit" and "create" instead of "submitted".
- Pick one scheme before the first event ships, not after fifty events exist under three conventions.
- Write the allowed verb list where the whole team can see it and check it in code review.
- Never build an event name from a variable. PostHog's guidance is to capture
page_viewedwith apage_nameproperty, not to interpolate the page name into the event. - Review every new event in a pull request the way you'd review a database migration.
Why does this matter? My reasoning, which is an inference: analytics decay is a naming problem before it's a volume problem, because when two people name the same action differently, every funnel built on one name under-counts the other. A fixed verb list and a review step are cheap next to rebuilding dashboards later. Properties follow the same discipline. PostHog recommends the object_adjective pattern such as user_id or item_price, is_ and has_ prefixes for booleans, and a _date or _timestamp suffix for time values.
Consider a multi-step booking flow like the one in BookBed. This is a hypothetical about naming, not a description of BookBed's tracking. One event with a step_number property keeps the funnel readable through redesigns, whereas a new event name per step forces you to rewrite every funnel when the flow changes.
Why pair feature flags with session replay?
Feature flags control who sees a change, and session replay shows what those users did with it, so together they let you inspect a rollout instead of guessing. PostHog's recording controls include a feature flag trigger that records only the users who have a linked flag enabled. On the flag side, percentage rollouts are available for all flags, with up to two decimal places, down to 0.01%.
A sensible pattern, and this is a recommendation, not a PostHog requirement: put a risky billing or auth change behind a flag, roll it out to a small percentage, and record only that group. The free tier covers 1M flag requests and 5K recordings a month, which is enough to try the pattern before paying anything. If a flagged group produces a burst of recordings you didn't expect, lower the rollout percentage or the sampling on the recording trigger, since the same page lists sampling and minimum duration as separate controls.
How do you run session replay without leaking personal data?
Treat masking as something you configure deliberately, because PostHog's defaults cover inputs but not all text. The session replay privacy docs say input elements are masked by default since they're likely to hold sensitive text, that passwords are always masked, and that general text isn't masked by default.
The options you'll use are maskTextSelector, which accepts CSS selectors and "*" for all text, maskTextFn and maskInputFn for conditional logic, and the ph-no-capture class to keep an element out entirely. My recommendation: start with "*", then loosen it only where a specific screen needs readable text and someone has reviewed it.
Network requests need their own attention. The same page points to the maskCapturedNetworkRequestFn callback for redacting query strings, noting that they can contain auth tokens or user identifiers, and that the callback runs in the browser so redacted values never leave the user's device.
For a sense of what a strict posture looks like in a shipped product, the Callidus case study lists Sentry in strict GDPR mode: sendDefaultPii: false, Replay masking all text, blocking all media and masking all inputs. The tool differs, but the stance is the one to copy.
Once you've settled hosting and masking, the rest of your SaaS MVP stack matters more than the analytics tool. Auth, billing and data isolation are harder to reverse than this choice.
Open your PostHog project and list your twenty most-fired events. How many would survive a rename to category:object_action without breaking a dashboard, and which ones would you fix first?



