
Mastering Analytics with PostHog in AstroJS
Embark on a data-driven journey with your AstroJS website by seamlessly integrating PostHog. This guide ensures you capture every interaction, server-side operation, and client-side event with precision. Ready to turn interactions into actionable insights?
Setting Up PostHog
Begin integrating PostHog to unlock comprehensive analytics capabilities.
Installation
Server (For server-side tracking):
npm install posthog-node
Client (For client-side tracking):
npm install posthog-js
Initialization
Proper initialization ensures accurate data capture.
Server
In your server-side TypeScript code:
import PostHog from 'posthog-node';
const posthog = new PostHog('YOUR_API_KEY', { apiHost: 'YOUR_POSTHOG_INSTANCE'});
Client-Side in AstroJS
Initialize PostHog in your Astro components using client:load
:
Create a PostHog Astro component with the client:load
directive to configure PostHog on any of your pages. Example:
------
<!-- HTML and component logic -->
<script type="module" client:load> import { posthog } from "../../node_modules/posthog-js";
posthog.init('YOUR_API_KEY', { api_host: 'YOUR_POSTHOG_INSTANCE', });</script>
You can now add this component to any page or layout that you’d like to have PostHog configured on. Here’s an example using an Astro layout.
---import PostHog from "@/components/analytics/PostHog.astro";---
<!doctype html><html lang="en"> <head> </head> <body> <PostHog /> <slot name="main" /> </body></html>
Key Concept: distinctId
Throughout the rest of this article we’re going to be referring to a value called a distinctId
.
The distinctId in the PostHog API is a unique identifier that represents an individual user or entity within your application or website. It allows you to track and analyze user behavior and interactions, enabling you to understand how users engage with your product. This identifier is crucial for identifying and attributing actions and events to specific users or entities, helping you gain insights into user behavior and improve your product’s user experience.
Basic Usage: Capturing Events
Here we’ll show the most basic implementation of posthog event capture, both a server and a client side example. In these examples there is no link between the user’s client events and server events, as the distinctId
on the client is not shared with the one used on the server.
Server-Side Events
Capture server-side events with a distinctId
:
posthog.capture({ distinctId: 'unique-user-id', event: 'server-event-name', properties: { key: 'value' }});
Client-Side Events
Capture client-side events, in the most basic implementation posthog client side library will create and manage the distinctId
on its own.
posthog.capture('client-event-name', { property1: 'value1', property2: 'value2'});
Advanced Usage: Linking Client and Server Events Using Cookies in AstroJS
Maintain a consistent distinctId
across client and server using cookies, simplifying the linking of events.
-
Generate a
distinctId
server-side and pass it to the client using adistinct_id
cookie, thedistinctId
allows the client and server to share an id, used for tracking user analytics.- On the server, generate a
distinctId
and store it in a cookie.- If the user is authenticated, using the authenticated user’s id is a great option
- If the user is not logged in we can generate any uuid and use that as the
distinctId
- For this example we’re going to be using AstroJS middleware, to create and set the
distinct_id
cookie.
~/src/middleware/distinct-id.ts import type { APIContext, MiddlewareNext } from "astro";import { defineMiddleware } from "astro/middleware";import { v4 as uuidv4 } from 'uuid';export const distinctIdMiddleware = defineMiddleware((context: APIContext, next: MiddlewareNext) => {// If there is an existint distinctId lets use it.let distinctId = context.cookies.get('distinct_id')?.value;// If this is the first request we'll generate a new distinctIdif (!distinctId) {distinctId = uuidv4();}// Store the distinctId in the Astro.locals for use throught the request lifecycle// as well as having a shared distinctId betwen the server and the clientcontext.locals.distinctId = distinctId;// Set the distinctId on the cookie for use on the client.context.cookies.set('distinct_id', distinctId, {maxAge: 60 * 60 * 24 * 365,path: '/'});next();}); - On the server, generate a
-
Register the
distinctIdMiddleware
with AstroJS, this will allow for access to thedistinctId
for the rest of the request, including page renders and api handlers.~/src/middleware/index.ts // sequence will accept middleware functions and will execute them in the order they are passedimport { sequence } from "astro/middleware";// Import the middlewareimport { distinctIdMiddleware } from "./distinct-id";// export onRequest. Invoke "sequence" with the middlewareexport const onRequest = sequence(distinctIdMiddleware); -
Utilize
Astro.locals
to access thedistinctId
and capture events with PostHog in your API handlers.- This is useful if your application is going to be logging server events as well as client side events.
- Example:
src/pages/api/your-api-endpoint.ts import PostHog from 'posthog-node';export async function post({ Astro }) {const posthog = new PostHog('YOUR_API_KEY', {apiHost: 'YOUR_POSTHOG_INSTANCE'});// Access the distinctId added by our distinctIdMiddlewareconst distinctId = Astro.locals.distinctId;// Capture and event and send it to posthogposthog.capture({distinctId,event: 'api-event-name',});return new Response('Event tracked', { status: 200 });} -
Read the shared
distinctId
Cookie from a PostHog AstroJS component Client side:- Update the PostHog.astro component to initialize the client side posthog instance, with the shared
distinctId
previously set in the cookie.
~/src/components/PostHog.astro ------<!-- HTML and component logic --><script type="module" client:load>import { posthog } from "../../node_modules/posthog-js";const cookies = document.cookie.split('; ').reduce((prev, current) => {const [name, value] = current.split('=');prev[name] = value;return prev;}, {});const distinctId = cookies['distinct_id'];// Initialize the posthog client instance with the `distinctId` from the serverposthog.init('YOUR_API_KEY', {api_host: 'YOUR_POSTHOG_INSTANCE',bootstrap: {distinctID: distinctId,},});</script> - Update the PostHog.astro component to initialize the client side posthog instance, with the shared
-
Linking the
distinctId
to the authenticated user.- Now that your app is able to share a
distinctId
between the client and the server, you can go one step further and actually associate this id with an authenticated user’s metadata, we’ll use their email as an example. - This is a very simple process and can happen immediately after a user has authenticated.
~/pages/api/signin.ts import PostHog from 'posthog-node';export const POST: APIRoute = async ({ url, request, cookies, redirect, locals }) => {// Sign in pseudocodeconst formData = await request.formData();const email = formData.get("email");const password =formData.get("password");const signInResult = await signIn(email, password)if (signInResult.success) {// Here is where we'll identify aka associate our generated `distinctId`// with the authenticated user.const posthog = new PostHog('YOUR_API_KEY', {apiHost: 'YOUR_POSTHOG_INSTANCE'});posthog.identify({distinctId: locals.distinctId,properties: {email: email,},});return new Response('Sign in success', { status: 200 });} else {throw new Error("Unable to sign in")}}; - Now that your app is able to share a
Conclusion
Replace 'YOUR_API_KEY'
and 'YOUR_POSTHOG_INSTANCE'
with your actual PostHog details. Ensure proper initialization before capturing any events. Customize your tracking strategy to the nature of your events and AstroJS’s capabilities.
Your AstroJS website is now a beacon of analytics, crafting a unified narrative of user interactions and system performance. Steer through your PostHog dashboard with the clarity of data-driven insights, propelling your decisions to unparalleled success. Here’s to a future where every interaction is a gateway to profound insights! 🚀