@posthog/brand
PostHog's brand assets, as an npm package: the logo, the brand colors, the brand
font (RoundHog), the hedgehog illustrations ("hoggies"), and the crests.
Everything ships as React components — plus raw SVGs, PNG URLs, color tokens, and woff2
font files — bundled right into the package, so there are zero runtime CDN calls.
🦔 Browse everything live at brand.posthog.com — every
logo lockup, color, hoggie, and crest, with the import you need for each one.
pnpm add @posthog/brand
⚠️ Pre-1.0: while the version is still 0.x, the public API may change — including
breaking changes (renamed or removed exports) — released as minor bumps. Pin an
exact version if you need stability, and check the changelog before upgrading. Once the
asset set and API settle we'll cut 1.0.0 and follow semver strictly.
The idea
The package is split into a handful of subpaths, one per kind of asset. You import what you
need from the matching subpath, and nothing else comes along for the ride:
import { Logo } from "@posthog/brand/logo"
import { colors } from "@posthog/brand/colors"
import { roundHogFontFaceCss } from "@posthog/brand/fonts/css"
import { HedgehogDoctorHog } from "@posthog/brand/hoggies"
import { ArrayCrest } from "@posthog/brand/crests"
The five sections below walk through each one in turn. Every illustration is a React
component that takes two friendly props:
size — the width (a number of px, or any CSS length). The height follows the
artwork's aspect ratio automatically, so you never stretch anything.
title — an accessible label. With it, the image is announced to screen readers;
without it, it's treated as decorative.
You can also pass any other <svg> prop (className, style, onClick, ref, …), and
every component carries its own metadata as a static .meta (HedgehogDoctorHog.meta.slug,
.aspectRatio, …). Hover any component in your editor and the TSDoc shows you exactly how to
use it.
1. Logo
The logo lives at @posthog/brand/logo. It's a single, parametric <Logo> component that
covers every lockup and color treatment — so it's the one PostHog logo you reach for
everywhere.
import { Logo } from "@posthog/brand/logo"
<Logo />
<Logo variant="mono" color="#fff" />
<Logo variant="mono" />
<Logo variant="print" layout="stacked" />
<Logo.Logomark />
<Logo.Wordmark />
variant | "gradient" · "print" (4-color/CMYK) · "mono" | "gradient" |
layout | "landscape" · "stacked" · "logomark" · "wordmark" | "landscape" |
color | any CSS color — used by mono only | currentColor |
Logo.Logomark and Logo.Wordmark are shorthands for layout="logomark" / "wordmark". A
mono logo (and the always-mono wordmark) draws with currentColor, so it inherits the
surrounding text color unless you pass an explicit color. As with every illustration, it
also takes size, title, className, style, and the rest of the native <svg> props.
2. Colors
The brand palette lives at @posthog/brand/colors as a plain object — no React, no markup.
import { colors } from "@posthog/brand/colors"
colors.blue.core
colors.blue.lighter
colors.blue.darker
colors["corn-blue"].gradient
Each color has core, lighter, darker, and a gradient pair.
Prefer CSS custom properties?
For stylesheets, import the ready-made CSS custom properties instead of the JS object:
import { colorsCss } from "@posthog/brand/colors/css"
Drop the string into a <style> tag (or your CSS-in-JS) and reference the variables anywhere:
color: var(--posthog-blue).
3. Fonts
RoundHog — PostHog's brand typeface — ships bundled at @posthog/brand/fonts as eight
woff2 faces (Regular / Medium / SemiBold / Bold, each upright and italic). No CDN, no
runtime fetch: the font files are emitted inside the package and their URLs are baked in
(resolved via import.meta.url, exactly like the PNGs), so any modern bundler emits them.
The quickest path is the ready-made @font-face string — drop it into a <style> tag and
then reference font-family: "RoundHog":
import { roundHogFontFaceCss } from "@posthog/brand/fonts/css"
document.head.insertAdjacentHTML("beforeend", `<style>${roundHogFontFaceCss}</style>`)
Weights map to PostHog's type scale: Regular → 400, Medium → 500, SemiBold → 700, Bold → 800.
Want the raw metadata or a single face URL?
If you register faces yourself (a custom @font-face, a <link rel="preload">, a Next.js
localFont, …), import the metadata or the individual URLs instead of the CSS string:
import { roundHog, roundHogRegularUrl } from "@posthog/brand/fonts"
roundHog.family
roundHog.faces
roundHogRegularUrl
The raw files are also reachable by subpath — @posthog/brand/fonts/RoundHog.woff2 — so a
build step can require.resolve them (e.g. to copy into a server's static dir).
4. Hoggies
The hedgehog illustrations live at @posthog/brand/hoggies. Each one is a React component
named Hedgehog<Name>:
import { HedgehogDoctorHog } from "@posthog/brand/hoggies"
export function Example() {
return <HedgehogDoctorHog size={120} title="A hedgehog doctor" />
}
That's the whole story — pick the hoggie you want, give it a size, and you're done. Browse
the full set (with the exact component name for each) at
brand.posthog.com.
5. Crests
The crests live at @posthog/brand/crests. Each crest comes in two sizes, paired together as
one component: the base is the full illustration, and .Mini is a simplified badge
that stays legible at small sizes (favicons, avatars, inline chips).
import { ArrayCrest } from "@posthog/brand/crests"
<ArrayCrest size={64} />
<ArrayCrest.Mini size={24} />
The component is named <Name>Crest. A few crests only exist in one size — for those,
.Mini simply renders the same artwork as the base.
If you'd rather pull a single tier on its own, the tier-specific subpaths expose each one
individually: ArrayCrest from @posthog/brand/crests/full, and ArrayCrestMini from
@posthog/brand/crests/mini.
Raw SVGs and PNGs
Sometimes you don't want a React component — you need the raw SVG markup (to inline into an
email or a non-React app) or a bundled PNG URL (for an <img> tag). Every asset ships as
both, so you can grab whichever fits:
import doctorHogSvg from "@posthog/brand/hoggies/svg/doctor-hog"
import doctorHogPng from "@posthog/brand/hoggies/png/doctor-hog"
All /svg and /png subpaths
Each illustration group exposes the same shapes. Replace <g> with one of hoggies,
crests/full, or crests/mini (the combined crests barrel and the logo are
React-only — use the tier subpaths for raw crest SVG/PNG):
@posthog/brand/<g> | React components |
@posthog/brand/<g>/svg | barrel of named SVG strings (hedgehogDoctorHogSvg) |
@posthog/brand/<g>/svg/<slug> | a single SVG string as the default export |
@posthog/brand/<g>/png | barrel of named PNG URLs (hedgehogDoctorHogPng) |
@posthog/brand/<g>/png/<slug> | a single PNG URL as the default export |
@posthog/brand/<g>/metadata | the group's AssetMeta[] manifest (React-free) |
import doctorHogSvg from "@posthog/brand/hoggies/svg/doctor-hog"
import arrayCrestPng from "@posthog/brand/crests/full/png/array"
import { hedgehogDoctorHogSvg, hedgehogCakeHogSvg } from "@posthog/brand/hoggies/svg"
const svg = (await import("@posthog/brand/hoggies/svg/" + slug)).default
The named export is lowerFirst(ComponentName) + "Svg" / + "Png" (e.g.
hedgehogDoctorHogSvg, arrayCrestPng). Crest minis keep a trailing Mini:
arrayCrestMiniSvg, arrayCrestMiniPng.
Both formats are optimized before they're committed — SVGs minified with
SVGO, PNGs palette-quantized with
pngquant and recompressed with
oxipng — so every asset stays small and renders anywhere.
Metadata and search
The root @posthog/brand export is React-free and image-free — just types, the
cross-namespace manifest, and helpers for building a picker or looking an asset up by slug:
import { allAssets, findAssets, getAsset, getComponentName } from "@posthog/brand"
findAssets({ namespace: "crests", tier: "mini", text: "array" })
findAssets({ namespace: "hoggies", text: "doctor" })
getAsset("hoggies", "doctor-hog")
getAsset("crests", "array", "mini")
getComponentName("hoggies", "doctor-hog")
getComponentName("crests", "array", "mini")
Per-namespace manifests are also available without the cross-namespace pull — e.g.
@posthog/brand/hoggies/metadata.
How assets get here
Brand assets live in PostHog's brand-book Figma file.
A daily GitHub Action renders every component to SVG + PNG via the Figma API, syncs the
result into this repo (assets/), and commits the changes — plus a
changeset — straight to main (no PR). That
triggers the release workflow, which bumps the version, commits it back to main, and
publishes to npm with trusted publishing (OIDC) — gated behind Slack approval, per the
PostHog SDK release process.
The color palette is not synced — it's a fixed, hand-maintained list in
static/colors.ts. The <Logo> component is likewise
hand-maintained: its geometry is inlined in src/logo/ (not Figma-synced),
since the logo is small and rarely changes.
Demo site
The live showcase at brand.posthog.com is built from
site/ — a Vite + React app that imports @posthog/brand as a workspace
dependency, so it renders the real built components, not copies. To run it locally:
pnpm dev:site
pnpm build:site
It deploys to Cloudflare Pages via the dashboard's Git integration.
Contributing
This package is maintained by the PostHog team and mirrors a Figma file — we don't accept
external contributions. See CONTRIBUTING.md for the details.
License
Source-available under the PolyForm Strict License 1.0.0 — you may view
the source, but commercial use, use in your own projects, redistribution, and derivative
works are not licensed. PostHog's illustrations, logos, and crests are PostHog trademarks and
brand assets. For licensing inquiries, contact hey@posthog.com.