910 words. Estimated reading time: 5 min.
Onboarding docs
Onboarding docs, or product installation docs, are special because these instructions are shared between the in-app onboarding flow and the getting started pages on the PostHog website.
These are some of the first pieces of docs a new user will see. They show users how to quickly set up and install a product, so they need to be up to date and accurate.
To help keep in-app and website onboarding docs in sync, there is a single source of truth for the onboarding docs in the posthog/posthog repository under the docs/onboarding directory. This means you only need to update the in-app onboarding docs in the PostHog monorepo, and the website docs will be updated automatically.
<ProductVideo videoLight= "https://res.cloudinary.com/dmukukwp6/video/upload/posthog_onboarding_docs_13eddf168e.mp4" alt="How shared onboarding docs work" classes="rounded" autoPlay={false} muted={false} />
Video explainer of how onboarding docs and shared rendering work
Which products have shared onboarding docs
This is a relatively new feature, so we're still migrating old onboarding docs to the new system. As of February 2026:
| Product | Status | |---------|--------| | LLM analytics | ✅ Migrated | | Product Analytics | ✅ Migrated | | Web Analytics | ✅ Migrated | | Session Replay | ✅ Migrated | | Feature Flags | ✅ Migrated | | Experiments | ✅ Migrated | | Error Tracking | ✅ Migrated | | Surveys | ✅ Migrated | | Data Pipelines | ⏳ Not yet migrated | | Data Warehouse | ⏳ Not yet migrated | | Revenue Analytics | ⏳ Not yet migrated | | PostHog AI | ⏳ Not yet migrated | | Workflows | ✅ Migrated | | Logs | ⏳ Not yet migrated | | Endpoints | ⏳ Not yet migrated |
How it all works
Onboarding content is written once as React components in the posthog/posthog repo, then rendered in two places:
- PostHog monorepo: For in-app onboarding, the PostHog app imports these docs components directly and wraps them with
OnboardingDocsContentWrapper, which provides UI components likeSteps,CodeBlock, etc. - PostHog.com repo: The website pulls the docs components from the monorepo via
gatsby-source-git, a Gatsby plugin, and then renders them through MDX stub files that use a similar but differentOnboardingContentWrapperto provide compatible UI components.
Both wrappers provide the same component names (Steps, CodeBlock, CalloutBox, etc.) so the shared content renders correctly in either place. When you merge changes to master in posthog/posthog, the website automatically pulls the updated content on its next build.
flowchart LR
subgraph website["<strong>posthog.com repo</strong>"]
gatsby["gatsby-source-git<br/>(pulls on build)"]
mdx["MDX stub files"]
wrapper2["OnboardingContentWrapper"]
ui2["Docs pages"]
gatsby --> mdx --> wrapper2 --> ui2
end
subgraph monorepo["<strong>posthog/posthog repo</strong>"]
docs["docs/onboarding/*.tsx<br/>product installation docs"]
wrapper1["OnboardingDocsContentWrapper"]
ui1["In-app onboarding flow"]
docs --> wrapper1 --> ui1
end
docs -.->|"auto-sync"| gatsby
If you need some help with structuring your files, this is the architecture for each repo:
posthog/posthog
├── docs/onboarding/
│ └── your-product/
│ ├── index.ts # Barrel file re-exports all Installation components + snippets
│ ├── sdk-name.tsx # getSteps + createInstallation
│ └── _snippets/
│ └── reusable-snippet.tsx
│
└── frontend/src/scenes/onboarding/
└── sdks/your-product/
└── YourProductSDKInstructions.tsx # withOnboardingDocsWrapper
posthog/posthog.com
└── contents/docs/your-product/
└── installation/
├── sdk-name.mdx # MDX stub
└── _snippets/
├── prefix-installation-wrapper.tsx # Single file with ALL wrappers
└── shared-helpers.tsx # modifySteps helpers
For a complete working example, see the Session Replay implementation:
| Repo | File | |------|------| | posthog/posthog | docs/onboarding/session-replay/ | | posthog.com | react.mdx | | posthog.com | sr-installation-wrapper.tsx (single file with all wrappers) |
How to create/migrate new onboarding docs
Step 1: Create the shared component in posthog/posthog
- Navigate to the product directory in
docs/onboarding/. If it doesn't exist, create it:docs/onboarding/your-product/ - Create a new
.tsxfile:docs/onboarding/your-product/filename.tsx - Export a step function and Installation component. Use
createInstallationto automatically handle the rendering:
// Step function receives a single context object with all components
export const getPythonSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => {
const { CodeBlock, Markdown, dedent, snippets } = ctx
// Reuse installation steps from product-analytics
const installationSteps = getPythonStepsPA(ctx)
// Add feature-flag-specific steps
const flagSteps: StepDefinition[] = [
{
title: 'Evaluate feature flags',
badge: 'required',
content: (
<>
Check if a feature flag is enabled:
{snippets?.BooleanFlagSnippet && <snippets.BooleanFlagSnippet />}
</>
),
},
]
return [...installationSteps, ...flagSteps]
}
// createInstallation wraps your step function into a ready-to-use component
export const PythonInstallation = createInstallation(getPythonSteps)
- You can reuse installation steps from product analytics by calling their step function with the same context.
- Step badges include
required,optional, orrecommended.
- For reusable snippets, create them in
docs/onboarding/<product>/_snippets/and export a named component. - Create the in-app wrapper in
frontend/src/scenes/onboarding/sdks/your-product/. Use thewithOnboardingDocsWrapperhelper:
const PYTHON_SNIPPETS = {
PythonEventCapture,
BooleanFlagSnippet,
MultivariateFlagSnippet,
}
const FeatureFlagsPythonInstructionsWrapper = withOnboardingDocsWrapper({
Installation: PythonInstallation,
snippets: PYTHON_SNIPPETS,
})
export const FeatureFlagsSDKInstructions: SDKInstructionsMap = {
[SDKKey.PYTHON]: FeatureFlagsPythonInstructionsWrapper,
// ... other SDKs
}
- Test in the app by running the monorepo locally and navigate to
localhost:8010/onboarding. From this page, you can select your product and test.
Step 2: Create the website stub in posthog/posthog.com
- To test your changes locally, use the
GATSBY_POSTHOG_BRANCHenvironment variable to point to your branch:
GATSBY_POSTHOG_BRANCH=your-branch-name pnpm start
This tells gatsby-source-git to pull from your branch instead of master.
- Create a single TSX wrapper file at
contents/docs/<product>/installation/_snippets/<prefix>-installation-wrapper.tsxthat exports all SDK wrappers:
JSWebInstallation,
ReactInstallation,
NextJSInstallation,
// ... import all SDK installations
SessionReplayFinalSteps,
} from 'onboarding/session-replay'
const SNIPPETS = {
SessionReplayFinalSteps,
}
// Export a wrapper for each SDK
export const SRJSWebInstallationWrapper = () => (
)
export const SRReactInstallationWrapper = () => (
)
export const SRNextJSInstallationWrapper = () => (
)
// ... repeat for all SDKs
The modifySteps prop lets you add website-specific steps (like "Next steps") that aren't needed in-app.
- Create an MDX stub file for each SDK at
contents/docs/<product>/installation/<name>.mdx:
---
title: React session replay installation
platformLogo: react
showStepsToc: true
---
<!--
This page imports shared onboarding content from the main PostHog repo.
Source: https://github.com/PostHog/posthog/blob/master/docs/onboarding/session-replay/react.tsx
-->
- Test locally: Run
pnpm startand verify the page renders correctly at the expected URL. - Commit and merge both the
posthog/posthogandposthog/posthog.comPRs.
Exceptions to the standard pattern
The architecture described above works well for products that have their own SDK installation steps – but not every product fits this mold. Some products are exceptions, and that's fine. The shared onboarding pattern should only be used when it makes sense.
Workflows
Installing an SDK for Workflows is optional. Because of this, Workflows doesn't define its own shared doc components. There are no files in docs/onboarding/workflows/.
Instead, Workflows reuses the Product Analytics Installation components directly and transforms them with a modifySteps function at the in-app level:
// Filter out product-analytics-specific steps and add a workflows-specific final step
function workflowsModifySteps(steps: StepDefinition[]): StepDefinition[] {
const installationSteps = steps.filter(
(step) => !['Send events', 'Send an event', 'Send events via the API'].includes(step.title)
)
return [
...installationSteps,
{
title: 'Set up workflows',
badge: 'recommended',
content: ,
},
]
}
const WorkflowsReactWrapper = withOnboardingDocsWrapper({
Installation: ReactInstallation,
modifySteps: workflowsModifySteps,
})
This pattern works because Workflows only needs a PostHog SDK installed (the same installation steps as Product Analytics), then swaps the final "send events" step for a "set up Workflows" step. Everything lives in a single WorkflowsSDKInstructions.tsx file – no shared docs directory, no website stubs.
If your product's onboarding is essentially "install the PostHog SDK + do one product-specific thing," consider reusing existing Installation components with modifySteps instead of creating a full set of shared doc files. This avoids unnecessary duplication.