> AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt

# Project setup for embedded analytics - Docs

Copy page

# Project setup for embedded analytics - Docs

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](/tutorials/embedded-analytics.md), or customer-facing analytics. You can store all customer data in one PostHog project and filter it by customer, or create a separate project for each customer. This guide compares both approaches to help you choose the right setup.

## How person profiles can merge

[Person profiles](/docs/data/persons.md) are scoped to a project. If users from different customers have the same [distinct ID](/docs/getting-started/identify-users.md), 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 AI

```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](/docs/libraries/js/persistence.md) for details.

**Our recommendation**

A project per customer is better when you plan to give customers direct PostHog access or need to fully isolate customer data for security or compliance reasons.

| Single project | Project per customer |
| --- | --- |
| Data | Store all customer data together and filter it by a customer_id property. | Store each customer's data in a separate project. |
| Best for | Dashboards displayed inside your product. | Giving customers direct access to PostHog. |
| Person profiles | Require customer-scoped distinct IDs to prevent merging. | Automatically separated by project. |
| Querying | Pass a customer identifier to an Endpoint or the Query API. | Query each customer's project. |
| Plan | Available on the free plan. | Requires the [Boost plan](/platform-packages.md) for unlimited projects. |

## 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:

-   **Recommended** – Create an [Endpoint with a variable](/docs/endpoints/guide-variables.md) and pass the customer ID when you call it.
-   Use the [Query API](/docs/api/queries.md) and filter the query by the customer ID. Keep in mind that the Query API has [project-level rate limits](/docs/api/queries.md#rate-limits).

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

## 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](/docs/api/projects.md).

Each project has its own [project token](/docs/settings/projects.md) 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](/platform-packages.md) 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:

-   Use [project access control](/docs/settings/access-control.md#2-project-level) to invite each customer to only their project.
-   [Manage access control through the API](/docs/settings/access-control.md#api-support) to automate this setup.
-   Disable [full organization member visibility](/docs/settings/organizations.md#member-list-visibility) so customers only see themselves and members of their project.

### 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.

## Further reading

-   [Set up embedded analytics with Next.js and Recharts](/tutorials/embedded-analytics.md)
-   [Build customer-facing analytics with Endpoints](/docs/endpoints/customer-facing-analytics.md)
-   [Compare Endpoints and the Query API](/docs/endpoints/endpoints-vs-query-api.md)
-   [Manage PostHog projects](/docs/settings/projects.md)

### Still have questions?

Ask PostHog AI

### Was this page useful?

HelpfulCould be better