Build customer-facing analytics

Contents

This guide shows how to build a customer-facing analytics feature where each user sees their own personalized stats. We'll track button clicks per user and query personalized counts from a PostHog endpoint.

Choose your project setup first

This guide stores all customer data in one project. If you identify users, make each distinct ID unique to the customer to prevent person profiles from merging. See project setup for embedded analytics for details.

Customer-facing analytics demo app
Prerequisites

Before starting, make sure a PostHog SDK is installed in your app.

Step 1: Create an endpoint with a user variable

Open the SQL editor and write this query:

SQL
SELECT count() as click_count
FROM events
WHERE event = 'hedgehog_clicked'
AND properties.user_id = {variables.user_id}

In the Variables tab, add a variable named user_id with type String.

Create the endpoint with the name hedgehog_clicks_by_user.

Step 2: Track events with user context

When tracking events, include a user_id property to associate them with specific users:

TSX
posthog.capture("hedgehog_clicked", {
user_id: currentUser.id,
});

Step 3: Query the endpoint from your backend

Keep API keys server-side

Never expose your PostHog API key in client-side code. Always proxy endpoint calls through your backend.

Create an API route that queries the endpoint with the user's ID:

TypeScript
// Example: Next.js API route
export async function POST(request: Request) {
const { user_id } = await request.json();
const response = await fetch(
`https://us.posthog.com/api/projects/${PROJECT_ID}/endpoints/hedgehog_clicks_by_user/run`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.POSTHOG_API_KEY}`,
},
body: JSON.stringify({
variables: { user_id },
}),
}
);
const data = await response.json();
return Response.json({ click_count: data.results?.[0]?.[0] ?? 0 });
}

Then fetch from your frontend:

TSX
const response = await fetch("/api/hedgehog-clicks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: currentUser.id }),
});
const { click_count } = await response.json();

Security considerations

  1. Never expose API keys client-side - Always proxy through your backend
  2. Variables are required - Endpoints with variables require values, preventing accidental data leaks
  3. Validate user IDs - In production, verify the user is authorized to query data for the requested user_id

Next steps

Still have questions?

Was this page useful?