DEV Community

Cover image for Using PostHog in Remix Loaders and Actions on Cloudflare Pages
Stefan Petrushevski
Stefan Petrushevski

Posted on

Using PostHog in Remix Loaders and Actions on Cloudflare Pages

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
Enter fullscreen mode Exit fullscreen mode

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 and flushInterval to 0. Also, remember to always call await 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;
}
Enter fullscreen mode Exit fullscreen mode

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 });
};
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Testing the Integration

  1. Deploy your Remix app to Cloudflare Pages.
  2. Trigger the loader or action by visiting the corresponding route or submitting a form.
  3. Check your PostHog dashboard for the captured events.

Best Practices

  1. Use Distinct IDs: Use a unique identifier (e.g., user ID) to track user-specific events effectively.
  2. Environment-Specific Events: Avoid sending events from non-production environments to maintain clean data.
  3. 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)