Project setup for embedded analytics

Contents

You can use PostHog to power analytics dashboards inside your product. Capture your customers' events in PostHog, query the data, and display the results in your own UI. This is often easier than building and maintaining your own infrastructure.

This is called embedded analytics, or customer-facing analytics. You have three options: store all customer data in one PostHog project and filter it by customer, create a separate project for each customer inside your organization, or provision a separate PostHog account that each customer owns. This guide compares them to help you choose the right setup.

How person profiles can merge

Person profiles are scoped to a project. If users from different customers have the same distinct ID, PostHog treats them as the same person and combines their events in one profile.

For example, suppose you're building a vibe-coding platform where customers can publish web apps that you manage. You want to use PostHog to show each customer a dashboard with their app's pageviews, users, and conversions. If the same person signs in to two customer apps and your platform identifies them as user 123 in both, that user's events from both apps appear in one person profile. Funnels and other per-user insights would count activity across both apps as belonging to one user.

One way to prevent this is to include the customer ID in each identified user's distinct ID:

TypeScript
posthog.identify(`${customerId}:${user.id}`)

This prevents identified users from different customers from sharing a profile. Anonymous activity can still merge if those websites use the same project token and share browser storage.

By default, the web SDK persists the anonymous distinct ID in a cookie. If that cookie is available to both websites, the SDK uses the same anonymous distinct ID. See JavaScript web persistence and cookies for details.

Our recommendation

Use a single project when you render the dashboards yourself inside your product.

Separate your customers when you plan to give them direct PostHog access, or when you need to fully isolate customer data for security or compliance reasons. If you separate them, start with the provisioning API: each customer gets their own organization, so you avoid both the Boost plan requirement and the combined billing described below.

Single projectProject per customerAccount per customer
DataStore all customer data together and filter it by a customer_id property.Store each customer's data in a separate project inside your organization.Store each customer's data in a separate organization that the customer owns.
Best forDashboards displayed inside your product.Giving customers direct access to PostHog.Giving customers their own PostHog account with no signup flow.
Person profilesRequire customer-scoped distinct IDs to prevent merging.Automatically separated by project.Automatically separated by organization.
QueryingPass a customer identifier to an Endpoint or the Query API.Query each customer's project.Query each customer's project with the OAuth token they granted you.
PlanAvailable on the free plan.Requires the Boost plan for unlimited projects.Available on the free plan. Each customer's organization gets its own free tier.

Option 1: Filter customer data in one project

Add a customer identifier, such as customer_id, as an event property on every event. You can then retrieve data for a specific customer in two ways:

Run these requests from your backend. Make sure you don't accept an arbitrary ID from the client.

Option 2: Create a project for each customer

A separate project isolates each customer's events and person profiles. Use this setup when customers need to log in to PostHog or when you need a strict data boundary between customers.

Create projects with the API

Create a project when you add a customer by calling the projects API.

Each project has its own project token for event ingestion.

To query a customer's data, use that project's ID when calling Endpoints or the Query API.

With this setup, analyzing data across all customers is more difficult because PostHog queries are scoped to one project. For example, to calculate daily active users across all customer apps, you would need to query each project separately and combine the results.

Requires the Boost plan

Free organizations are limited to one project. The Boost plan includes unlimited projects.

Give customers access

If you store each customer's data in a separate project and want to give them access to PostHog:

Billing

Billing is organization-wide, so usage is combined across all projects. For example, 100 projects sending 20,000 events each count as 2 million events, not 100 separate free tiers.

Account for this combined usage when pricing your product.

Option 3: Provision an account for each customer

The provisioning API creates a complete PostHog account for a customer from your backend, so the customer never sees a signup form. You get back a project token to start sending events, plus an OAuth access token to query their data and deep link them into their own project.

The difference from option 2 is who owns the data. Each account is your customer's own organization rather than a project inside yours, which changes three things:

  • Billing. Usage bills to your customer and starts on the free tier. It doesn't roll up into your bill, and you don't need the Boost plan.
  • Access. A deep link signs the customer into their own project, so you don't send invites or hide your organization's member list. Deep linking is only enabled for partners that PostHog has onboarded.
  • Control. Your customer can revoke your access or change their plan, and you get only the scopes they consent to.

Analyzing data across customers is harder than with option 2, because each customer is a separate organization.

Further reading

Still have questions?

Was this page useful?