PostHog makes it easy to get data about usage of your Hono app. Integrating PostHog into your app enables analytics, custom events capture, feature flags, and more.
This guide walks you through integrating PostHog with your Hono app running on the Node.js runtime, but has also been tested with Cloudflare Workers, Vercel, and Bun. You can hook into the same middleware and onError
for other runtimes to capture events.
Prerequisites
To follow this guide along, you need:
- A PostHog instance (either Cloud or self-hosted)
- A Hono application. We suggest trying first with a fresh Hono Node.js starter template.
Installation
Start by installing the posthog-node
package using your package manager.
npm install --save posthog-node
Then, create a middleware to capture events for your routes. Remember to export your project API key as an environment variable.
import { env } from 'hono/adapter'import { createMiddleware } from 'hono/factory'import { PostHog } from 'posthog-node'const posthogServerMiddleware = createMiddleware(async (c, next) => {const { POSTHOG_PUBLIC_KEY } = env<{ POSTHOG_PUBLIC_KEY:string }>(c)const posthog = new PostHog(POSTHOG_PUBLIC_KEY, { host: 'https://us.i.posthog.com' })posthog.capture({distinctId: 'distinct_id_of_user', // Their user id or emailevent: 'user_did_something',})await posthog.shutdown()await next()})
Make sure to always call posthog.shutdown()
after capturing events from the server-side. PostHog queues events into larger batches. This call forces all batched events to be flushed immediately.
Next, apply this middleware to your app. This middleware will be called on every request handled by Hono, denoted by the wildcard *
.
// use the middleware on all (*) routes.app.use('*', posthogServerMiddleware)
In your routes, you can pass information to be captured by your middleware using context set()
and get()
pair
Cloudflare Pages uses its own middleware system that is different from Hono's middleware. Follow the Hono documentation on Cloudflare Pages to handle middleware.
Error tracking
Hono uses app.onError
for root-level error handling. You can take advantage of this for Error tracking.
import { env } from 'hono/adapter'import { PostHog } from 'posthog-node'app.onError((err, c) => {const { POSTHOG_PUBLIC_KEY } = env<{ POSTHOG_PUBLIC_KEY:string }>(c)const posthog = new PostHog(POSTHOG_PUBLIC_KEY, { host: 'https://us.i.posthog.com' })posthog.captureException(new Error(err.message, { cause: err }), 'user_distinct_id_with_err_rethrow', {path: c.req.path,method: c.req.method,url: c.req.url,headers: c.req.header(),// ... other properties})posthog.shutdown()// other error handling logicreturn c.text('Internal Server Error', 500)})
Next steps
To read more about how to integrate specific PostHog features into Hono, have a look at our Node SDK docs for concepts such as: