If you're building a modern web application with Remix and deploying it on Cloudflare Pages, incorporating analytics can be invaluable. PostHog is a powerful product analytics tool that provides insights into user behavior, feature usage, and more, helping you make informed decisions to improve your application. In this article, I will walk you through integrating PostHog into a Remix app, specifically focusing on how to use it in loaders and actions while ensuring compatibility with Cloudflare Pages.
While building TailoredCV.ai on Cloudflare Pages and Workers using Remix, I faced the challenge of setting up PostHog for server-side analytics. This experience gave me a deep understanding of the complexities involved in integrating analytics in a serverless environment, and I'm excited to share those insights here.
Why Use PostHog?
PostHog is more than just analytics. It provides session recordings, feature flagging, A/B testing, and event tracking—all while being open-source and easy to integrate. This makes it an excellent choice for getting deep insights into how users interact with your product.
Challenges on Cloudflare Pages
When deploying on Cloudflare Pages, accessing environment variables is slightly different compared to traditional Node.js environments. Remix's loaders and actions run in a serverless environment, so process.env
is unavailable. Instead, you need to pass environment variables explicitly in your loader
and action
context.
Setting Up PostHog
1. Enable Node Compatibility on Cloudflare Pages
Make sure to enable Node compatibility by referring to Cloudflare Node.js Runtime API.
2. Install PostHog Node.js Library
To get started, add the PostHog Node.js library to your project:
npm install posthog-node
3. Environment Variables
Ensure your Cloudflare Pages project has the following environment variables set:
-
POSTHOG_API_KEY
: Your PostHog project API key. -
POSTHOG_HOST
: The PostHog instance URL (e.g.,https://app.posthog.com
or your self-hosted domain).
Adding PostHog to Remix
1. Initialize PostHog in a Utility File
Create a utility file (posthog.server.ts
) for initializing PostHog (refer to PostHog Node.js Documentation for more details):
Note: When using PostHog in an AWS Lambda function or a similar serverless function environment, make sure you set
flushAt
to 1 andflushInterval
to 0. Also, remember to always callawait posthog.shutdown()
at the end to flush and send all pending events.
import { PostHog } from 'posthog-node';
let posthog: PostHog | null = null;
export function getPostHog(apiKey: string, host: string) {
if (!posthog) {
const posthog = new PostHog(apiKey, {
host,
flushAt: 1, // Setting flushAt to 1 ensures events are sent immediately in serverless environments.
flushInterval: 0, // Setting flushInterval to 0 ensures no delay in sending events.
});
}
return posthog;
}
2. Use PostHog in Loaders and Actions
In your loaders and actions, you can initialize PostHog using the environment variables passed through the context. It's important to call await posthog.shutdown()
before returning anything from the loader or action. This ensures that all events are properly flushed and sent to PostHog, avoiding any data loss.
import { json } from '@remix-run/cloudflare';
import type { LoaderFunction, ActionFunction } from '@remix-run/cloudflare';
import { getPostHog } from '~/utils/posthog.server';
export const loader: LoaderFunction = async ({ context }) => {
const { POSTHOG_API_KEY, POSTHOG_HOST } = context.cloudflare.env;
const posthog = getPostHog(POSTHOG_API_KEY, POSTHOG_HOST);
// Track a page view event
posthog.capture({
distinctId: 'user-123', // Replace with a unique identifier for your user
event: 'page_view',
properties: { path: '/example' },
});
await posthog.shutdown(); // VERY IMPORTANT: Ensure all events are sent to PostHog before returning
return json({ message: 'Page view tracked' });
};
export const action: ActionFunction = async ({ request, context }) => {
const { POSTHOG_API_KEY, POSTHOG_HOST } = context.cloudflare.env;
const posthog = getPostHog(POSTHOG_API_KEY, POSTHOG_HOST);
// Parse form data and track a custom event
const formData = await request.formData();
const email = formData.get('email');
posthog.capture({
distinctId: 'user-123', // Replace with a unique identifier for your user
event: 'form_submission',
properties: { email },
});
await posthog.shutdown(); // VERY IMPORTANT: Ensure all events are sent to PostHog before returning
return json({ success: true });
};
3. Pass Environment Variables in Cloudflare Context
Update your Cloudflare Pages wrangler.toml
configuration to include environment variables:
[vars]
POSTHOG_API_KEY = "your-posthog-api-key"
POSTHOG_HOST = "https://app.posthog.com"
Testing the Integration
- Deploy your Remix app to Cloudflare Pages.
- Trigger the loader or action by visiting the corresponding route or submitting a form.
- Check your PostHog dashboard for the captured events.
Best Practices
- Use Distinct IDs: Use a unique identifier (e.g., user ID) to track user-specific events effectively.
- Environment-Specific Events: Avoid sending events from non-production environments to maintain clean data.
-
Server-Side Only Tracking: Since loaders and actions run server-side, consider tracking events that don’t rely on client-side behavior. For client-side, use
posthog-js
normally.
Conclusion
Integrating PostHog into your Remix app deployed on Cloudflare Pages is straightforward with the right setup. By leveraging PostHog’s powerful analytics capabilities, you can gain valuable insights into user behavior and improve your application.
Give it a try, and I'd love to hear how you use PostHog in your Remix projects!
Top comments (0)