Open-source project
PostHog/posthog.com avatar
PostHog/posthog.com

posthog.com: a documentation site and handbook treated as a product

Official docs, website, and handbook for PostHog.

1,152 stars933 forksTypeScriptNOASSERTION

At a glance

What is it?
The posthog.com repository is the Gatsby source for PostHog's website, docs, blog, tutorials, case studies and internal handbook, and the README says plainly that they treat it like a product. That shows up in the details, from an AGENTS.md for agents to a set of named test scripts, a Vale style checker for prose, and a hard requirement that every commit be cryptographically signed.
Who is it for?
Adopt this repository as a reference if you maintain a documentation site that also has to be a marketing site and an internal handbook, because the separation between content, site and product features is done explicitly here. Do not adopt it as a Gatsby starter, since it is one company's site with its own integrations, its own Squeak and Ashby dependencies and its own conventions.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One repository for the site, the docs and the handbook

The repository is described as containing all of PostHog's written content and visuals, including product features, manuals, docs, blogs, case studies, tutorials and the handbook, and it also contains features such as questions and answers, which use Squeak, job listings, which use Ashby, a pricing calculator, the roadmap, the API docs and more. The README puts it plainly, that they treat it like a product, and that it contains all the components, templates, logic and styling to make this work, look pretty and spark joy. That framing explains the shape of the tree, with a `contents/` directory holding the written material, `src/` holding the site, `api/` and `functions/` for the serverless edges, `gatsby/` for the build-time machinery and `plugins/` for the Gatsby plugins the site needs. The docs at `posthog.com/handbook` are therefore not a separate wiki but a section of the same site, which is why a change to a handbook page and a change to a product page travel through the same review path.

Local development, and the tooling it assumes

The quick start is short and presumes a specific toolchain. You install Node version 22, and the README notes that if you installed Node with nvm you can run `nvm use` to switch automatically. You install pnpm, and the easiest way is `corepack use pnpm@latest-10`. Then you clone the repository, install the dependencies and start the site.

bash
git clone [email protected]:PostHog/posthog.com.git && cd posthog.com/
pnpm install
pnpm start

There is one machine specific instruction, and it is worth not missing. On an Apple Silicon Mac you need to remove the existing `node_modules` directory and install vips with `brew install vips`. The site then runs at `http://localhost:8001`, and a second link appears at `http://localhost:8001/___graphql`, which the README describes as a tool for experimenting with queries against your data, pointing at the Gatsby tutorial on GraphiQL. There is also a tip for chasing discrepancies between local development and staging, which is to build and serve the production output locally with `gatsby build && gatsby serve`, and an `AGENTS.md` at the root with instructions for the most fundamental parts of running the app.

Environment variables, and which features they switch on

The advanced setup section is really a list of integrations and the variables that make them work. The API documentation at `/docs/api` loads its schema from the US Cloud by default, and you can point it at a local PostHog instance with an environment variable.

bash
POSTHOG_OPEN_API_SPEC_URL="http://127.0.0.1:8000/api/schema/" pnpm start

The job listings from Ashby and the GitHub contributors list need their own credentials, and the README points at private instructions for them rather than repeating the values. The merch store needs three more, `SHOPIFY_APP_PASSWORD`, `GATSBY_MYSHOPIFY_URL` and `GATSBY_SHOPIFY_STOREFRONT_TOKEN`, and those variables are currently excluded from Vercel preview builds, which is described as a way to disable merch store node creation and to speed up build times on pull requests that have nothing to do with merchandise. There is a smaller quirk worth knowing, that to see your local version of the posts section you have to visit `/posts` directly rather than the listing, and the dynamic open graph images need both `ASHBY_API_KEY` and `GITHUB_API_KEY` set during a build, plus a temporary edit to a guard in `gatsby/onPostBuild.ts`, with the generated images landing in `public/og-images/`.

Preview builds that skip the listing pages on purpose

The Cloudflare preview deployment workflow is described in enough detail to be useful, because the trade it makes is unusual. Pull request previews build with the environment variable `GATSBY_MINIMAL=true`, the same idea as the minimal build script in the manifest. The consequence is that post listing pages such as `/tutorials`, `/blog` and `/posts` are not generated in a preview, so those URLs may break there, and the way to review your change is to open the direct URL of your doc or post, for example `/tutorials/your-slug`. Listings and search stay aligned with production after the change is merged into `master`. The reasoning behind it is a build time one, since a preview that generated every listing page would rebuild the whole content index for a one page change, and the workflow in the repository, `.github/workflows/deploy-preview.yml`, is where that decision is encoded. For a contributor, the practical rule is that if a preview looks broken at the section level, the content is fine and the listing is simply not there.

Signed commits, and what the check actually does

PostHog requires commits with signatures that GitHub can verify, including commits from forks, and the README is unusually specific about the distinction. You set up commit signing before your first commit, and then enable signing for the repository, which is a one line git configuration.

bash
git config --local commit.gpgsign true

Then comes the sentence that saves people a wasted afternoon, that a `Signed-off-by` line from `git commit -s` does not meet the requirement, and that cryptographic signing uses `git commit -S`. Enabling signing only affects future commits, so any existing unsigned commits also have to be signed. The check itself runs when you open a pull request, after each push and after pull request edits, including base branch changes and draft pull requests, and fork pull request workflows require approval from a maintainer. The check reports the affected commits and repair instructions in the workflow summary, it does not post pull request comments, and the organisation rule enforces the signature requirement independently of the workflow. The result is a repository where the history is attributable, which matters for a project whose handbook documents internal engineering practice.

Tests are named individually, because the default test script is a placeholder

The package manifest has a `test` script that reads `echo "Error: no test specified" && exit 1`, which looks like a leftover but is really a signal, because the real tests are exposed as individually named scripts. There is `test:redirects` running jest against the scripts directory, `test:bundle` running the Node test runner over a script that checks the eager graph, `test:markdown` over a turndown service test, `test:middleware` and `test:gatsby-utils` over their own test files, and `test:navs`. Alongside them sit `typegen` for kea-typegen, `format` for prettier, `clean` for gatsby clean, and a `check:source-release-callouts` script that verifies callouts in the source. The quality tooling around the content is just as deliberate, with a Vale configuration and directory for prose linting, markdownlint, a Storybook directory, a visual regression directory, a Greptile configuration, an imgbot configuration and a husky setup. The repository also keeps an `AGENTS.md`, a `CLAUDE.md`, a `WARP.md`, a `STYLEGUIDE.md` and a `SECURITY.md`, which tells you how much of this project is instructions for tools rather than code.

How the site is assembled and what is worth copying

The build is Gatsby with a `gatsby-config.js`, a `gatsby-node.ts` for page creation, `gatsby-browser.tsx` and `gatsby-ssr.js` for the client and server hooks, and a `kea.js` for the state layer, with `middleware.ts` and its own test sitting at the repository root. Styling is Tailwind with a `tailwind.config.js` and a `postcss.config.js`, and there is a `patches/` directory and a `safelist.txt` for the production CSS. Deployment is on Vercel, with a `vercel.json` and a check of the Vercel deployments page when you are chasing a start up failure. There is a `pnpm-workspace.yaml`, an `.nvmrc` and a `.devcontainer/`, plus per-environment `.env.development` and `.env.production` files. What is worth copying from this repository is less the Gatsby setup and more the discipline. Content, site and product integrations live in one place with one review path, every pull request preview is cheap by design, the prose has a linter, and the commit history is signed. A documentation site that is treated as a product has a different maintenance cost profile from a documentation site that is a folder of markdown files.

Editorial conclusion

Adopt this repository as a reference if you maintain a documentation site that also has to be a marketing site and an internal handbook, because the separation between content, site and product features is done explicitly here. Do not adopt it as a Gatsby starter, since it is one company's site with its own integrations, its own Squeak and Ashby dependencies and its own conventions. Before you run it, install Node 22 and pnpm through corepack, and on Apple Silicon install vips, since the README calls that out specifically. If you intend to contribute rather than read, note the signing requirement, because a `Signed-off-by` line does not satisfy it and only `git commit -S` does. The licence is MIT, the last push was on 2026-10-15, and the repository publishes no GitHub releases.

Frequently asked questions

How do I run the PostHog website locally?

Install Node version 22 and pnpm, the easiest way being `corepack use pnpm@latest-10`, then clone the repository, run `pnpm install` and `pnpm start`. The site is served at `http://localhost:8001`, with a GraphiQL tool at `http://localhost:8001/___graphql`. On Apple Silicon you also need to install vips with brew.

Why does a pull request preview not show listing pages?

Preview deployments build with `GATSBY_MINIMAL=true`, so post listing pages such as `/tutorials`, `/blog` and `/posts` are not generated and those URLs may break in the preview. You review your change by opening the direct URL of your doc or post, for example `/tutorials/your-slug`.

What are the commit signing requirements?

Commits must be signed in a way GitHub can verify, including commits from forks, and the README is explicit that a `Signed-off-by` line does not meet the requirement, only `git commit -S` does. You enable it with `git config --local commit.gpgsign true`, and the check runs on pull request open, push and edits, with fork pull requests needing maintainer approval.

How do I point the API docs at a local PostHog instance?

Set `POSTHOG_OPEN_API_SPEC_URL` to the local schema endpoint, for example `http://127.0.0.1:8000/api/schema/`, when starting the site. By default the docs at `/docs/api` load the schema from the US Cloud.

Official sources

  1. Issues
  2. PostHog/posthog.com on GitHub
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/posthog-posthog-com.svg)](https://hysenlabs.com/projects/posthog-posthog-com)

Was this useful?