This is a living document — we'll keep adding tactics as we learn what works. If you've found something effective, add it here!
Engineers, our ICP, are very self-serve and happy to implement PostHog themselves. They often read the docs without ever interacting with someone unless they have support queries. But unengaged customers churn, and "just checking in" rarely works. This page details how to craft outreach, and some great examples.
The common thread across everything below: do your homework first, then lead with something specific and valuable. Generic outreach will not work.
Why is it helpful for someone to talk to you?
The reasons have to be _genuinely helpful_ ones - just 'having a point of contact' is not enough. Reasons include:
You can save them money:
They've implemented PostHog in a silly way and are consuming stuff they don't need
They can pre-commit and get a discount on credit
You can help them get more out of PostHog for the same amount of money, e.g. if they're ingesting loads of events but not using features to their fullest
You can train their team on how to use PostHog, so they don't have to
You can make them aware of upcoming or new products that are specifically useful for their use case
You can be a shortcut to premium support, if they are in your book of business
If you go down the 'saving money' route, bear in mind two things:
Prepaid credit never works as an opener - 'save money by fixing implementation' >>> 'save money by committing to credit at a discount'
Buying a bunch of credits at a nice discount is much nicer to hear than 'please commit to a scary annual plan' - they can commit for a year, 6 months, whatever so long as they buy >$20k up front
Do your homework first
Before reaching out, spend some time understanding where the customer is at. This makes all the difference between a generic check-in and a genuinely helpful conversation. The amount of time spent should be carefully prioritized. The more specific, the more likely you'll get a response, but don't let research become the blocker. For a first touch, a simple email that points at their use case with a specific suggestion is enough; you don't need to design a bespoke Loom for everyone. Some ways to research are:
1. Review their engagement metrics
Use the customer's PostHog usage data to understand what they're actually doing before you reach out. Look at:
What features they're using — insights, dashboards, recordings, etc.
Insight titles they've created — these reveal what business questions they care about
Recent activity — are they creating new things or just passively viewing?
For example, if a customer is creating and viewing insights with titles around "funnel conversions," they almost certainly care about improving funnel conversion rates. Lead with that.
Where to look: Customer engagement dashboard in PostHog — filter by the customer's org/team and check insight creation and viewing activity. Use PostHog AI or the PostHog MCP (with CS Skills like User Deep Dive) to pull additional details and summaries.
2. Walk through their site with debug mode
Visit the customer's website and inspect their PostHog implementation firsthand:
Open the browser console and run posthog.debug() to enable debug mode
Check the config to see how PostHog is configured
Walk through key flows (login, onboarding, core product actions)
Watch what events fire — are they capturing meaningful actions?
Look for issues: missing events, misconfigured properties, no identify calls, etc.
This gives you a firsthand view of what the customer is (or isn't) capturing. You can come to the conversation with specific, concrete observations — "I noticed you're not capturing any events after sign-up" — rather than asking them to self-report.
Framing matters: Position it as a proactive health check, not a criticism. Something like: "I took a look at your implementation and spotted a couple of things that might be worth addressing..."
3. Dig into frustration signals with MCP
MCP is great for finding silent frustration — and the specific person worth reaching out to about it:
Lost insights — ask how many insights were started versus saved, and by who. 130 started and 6 saved is someone struggling to build what they want.
Rage clicks — find pages or insights where a user is unusually frustrated, then pair it with session replay to see what they were trying to do.
Query failures — Vitally surfaces that they happen; MCP will often name the failing query, so you can investigate (and ideally fix it) before reaching out.
Client request failures — separate from query failures, and usually means data isn't loading for them. Resolve it, or file a bug on their behalf.
Product engagement — AI often measures PostHog UI engagement only, so ask about MCP engagement too. Vitally's low "dashboard activity" is frequently a false positive because it counts dashboard views, not insights.
Event changes — ask for an analysis at the _organization_ level (it defaults to user engagement) on a daily/weekly/monthly basis to catch implementation changes and product drops. If volume moved, ask who was using that product beforehand.
Product adoption — MCP will surface customers testing a product, sending sample events, or quietly winding usage down. E.g. "I see you recently tested our data warehouse briefly but have discontinued sending data. Was there anything specific you were looking to do that I could help with?"
Priority summary — once you've looked at all the signals, ask for a prioritized list of users to contact, each with their specific issue and a draft message you can tweak.
Apply the rules of thumb to whichever you pick. If you have other examples, add them here!
SDK health — flag outdated SDKs
Use the SDK health check to see if the customer is running outdated SDKs. This is one of the easiest, most concrete reasons to reach out. We recommend customers update monthly so they don't miss bug fixes and improvements.
Suggested cadence: Run the SDK health check on each of your accounts quarterly, or whenever a customer is ramping up usage of a specific SDK.
Suggested wording:
BTW our SDK health check is warning that you are using a three year old version of our Python SDK. I promise we've improved it since then! Also your iOS and Android SDKs are really out of date. Any chance of updating these?
Why it works: Specific, helpful, and low-effort for both sides. The tone is light and friendly, not alarming.
Spot new product interest and reach out proactively
Watch customer activity for signs they're exploring a product they haven't adopted — docs page views, product-page activity, exploratory events. Use that as a natural conversation starter (credit to Tyler). Same goes in reverse: tell them about new or upcoming features they may not be aware of which you know could be a great fit, and let them try them out for free.
Suggested cadence: Weekly scan of doc-page views and product-page activity for your accounts.
Suggested wording:
Hey @[contact], saw you checking out AI observability and wanted to share a few things. It occurred to me that our LLM observability suite might be really helpful for your team.
Not only do you get evals/traces/generations to track model performance, token usage, etc, you can then also connect those things back to PostHog session/user data. Which means you can actually easily run A/B and multivariate tests on things like prompts, models, and so on, while ALSO seeing how the LLM performance/quality have an impact on conversion and funnel.
You may already have something like that in place but thought it was worth mentioning!
Steady drumbeat of usage-specific tips
For customers who rarely reply, keep sending value anyway. Session replays will tell you whether your advice is landing — quiet customers often act on tips without ever responding (credit to Anna-Marie, who used this pattern on a customer that hadn't replied in months; replays showed they were quietly acting on every tip and eventually adopted multiple new features).
Suggested cadence: Every 1-2 weeks. Rotate value types so it doesn't feel like a stream of asks.
Value types to rotate through:
Cost optimization — e.g. "you have a couple of flags tied to completed experiments still enabled"
Alerts or monitoring opportunities you spot in their data
Data quality observations — e.g. "your group analytics has many groups being created with a UUID as the group key"
Workflow templates based on insights or dashboards they've drafted but not saved
Heads-ups on upcoming products in their space — especially competitive ones — so they don't get blindsided
New beta features that tie back to what they're already doing
OOO heads-ups with a fallback contact
Suggested wording (transparency about a competing product launch):
Hey @[contact], :wave: just wanted to give you a heads-up and be super transparent: as you might already know our engineers have been working on [new product]. I've just heard that the ballpark timeline is ~end of [month] for going into beta. I know this might be a sore point given your space, and didn't want you to feel blindsided.
I'd love to address any questions or concerns you may have, and as always — make sure that you continue getting value from our product analytics, feature flags and experiments you've been running.
Sometimes you'll get a customer in your book who was previously working with someone else on the PostHog team. A pre-existing relationship can help, but it's not guaranteed they'll want to talk to you. We've found a message like this in Slack/email works well after the intro.
Suggested cadence: At the beginning of your engagement,
Suggested wording:
Thanks [PostHog team mate who introed you]
Hey [customer] :blob-wave: Excited to be working with you! As I take over, it would be a big help if we could schedule a quick 15–20 minutes intro call [link to your Calendly]. Just a chance for me to learn more and figure out how I can best support you going forward. Let me know if you'd be open to that.
1:1 individualized outreach to revive a dead channel
When a customer channel goes completely silent, don't mass-ping — it gets ignored. Instead, DM team members individually over a couple of weeks until you've rebuilt the channel one person at a time, then get them on a call together. Seb used this on a dead channel and eventually got the whole team back on a call.
Suggested cadence: Spread individual DMs over 2-3 weeks. Convene the group on a call once you have a critical mass.
Bonus — same-day call follow-up with a custom touch: A custom-branded merch discount code (set up in the Shopify admin — see the merch store handbook page) is a small detail with outsized goodwill impact. Sending it same-day rides the momentum, well before the "proper follow-up."
Suggested wording (same-day follow-up):
hey team! thanks for the productive chat earlier today.
i owe you a proper follow up on everything we discussed, but couldn't wait to share this discount code ([CUSTOM-CODE]) with ya'll so you can get your save posthog t shirt on the (hog)house :hog-party-wave:
lovely meeting you all - excited to keep working together :hog-offers-heart:
cc @[people who showed interest on the call] - tagging you since you were esp excited about the merch :slightly_smiling_face:
After events (Stripe Sessions, conferences, meetups), sweep through post-event outbound — including customers who already have a CSM/TAM relationship that's gone cold (credit to Lorena). Event context resets the conversation: it's not "checking in," it's "I just saw you at X." A different sender or different framing can revive a stalled thread that relationship-based follow-ups couldn't.
Suggested cadence: After every event your customers attended, do a post-event outbound sweep — don't filter out accounts with existing relationships.
Why it works: Event-tied context lowers the social bar to engage. The customer doesn't have to explain the silence — they just have to reply to "great to see you at X."
Use a competitor pricing change (or market news) as a value-based reason
When something happens in the wider market that could cost the customer money — e.g. a competitor's pricing change — that's a real reason to reach out. Will used this when LaunchDarkly's pricing changes started getting bad press: tagged specific engineers and offered to do the heavy lifting on a PostHog vs LD comparison.
Suggested cadence: Opportunistic — keep an eye on competitor news so you're not the last to know.
Suggested wording:
Hey @engineer1 and @engineer2,
i know you're using [competitor] for feature flags — we heard at [event] that the pricing changes are causing bill shocks, so if you're doing any sort of internal review, lemme know and i'll do the heavy lifting of the comparison from our side.
p.s. please lemme know if i should tag anyone specific
Follow-up pattern that worked:
If they engage, drop a deep, honest technical breakdown. Don't oversell — call out gaps in our product where they exist.
If they push back on a gap, close the loop publicly: "Let's put a pin in it for now. I'll keep an eye on this from our side, and if we can support [X] cleanly sooner, I'll come back with something then!"
Loop in engineering in the customer channel when relevant — turns the conversation into a product input loop and shows the feedback is being taken seriously.
Getting the reason right is only half of it — most failed outreach dies because it went to the wrong place or the wrong person.
Use multiple channels. Email is usually the worst way to reach our ICP. Slack, in-app surveys or even Telegram are all usually better. But try email first anyway.
Message people individually, never as a group. Channel-wide pings get ignored; named tags lower the social cost of replying. Start with the most active users, then the newest. Invite a redirect when you're not sure who's right: "lemme know if i should tag anyone specific."
Loom videos sharing your observations about their usage/account provide a personalized and human touch which can go a long way to building lasting relationships. Ask Simon for an invitation to our company account if you don't have access.
LinkedIn. Adding the contact and sending a very human video or audio message can work really well - even for technical people (use the LinkedIn mobile app).
Non-technical people. Figure out what the non-technical people in their team need and then go out and talk to them - get someone who isn't an engineer to talk to us given engineers don't want to.
Escalate to senior stakeholders. If you can't get hold of anyone, email more senior team members even if they don't use PostHog (credit to Steven). They can help you find the right person.
"New users." If you're not succeeding getting through with your champions, engage with colleagues recently invited into PostHog. Monitor for them via the "new user" segment in Vitally. Once they start engaging with features, reach out with an email and Slack invite offering to help get them started quickly.
Their language. If the customer's main language isn't English, that alone can make them hesitant to engage over Slack or email. Try writing your message in their language – but AI translation can read as unnatural depending on the language, so use it with discretion, ideally where you can spot-check the result. Better still, pull in a teammate who speaks the language (credit to Steven) – they don't need to own the account, just to remove the friction. (Slack discussion)
Ask the wider team for help - we have to get creative here! You'd be surprised how often somebody knows someone...
Ideally you want to get multiple people into a shared Slack channel, as we've found this enables the best communication and allows us to provide them with great support. Just adding a bunch people to the Slack channel is also a legit tactic - forgiveness, not permission.
Crafting the message
Despite the organization using PostHog, they may not recognize you/PostHog, or may not even be the correct person to talk to about PostHog, which means your message needs to be well crafted.
Your initial outreach isn't about you, it is about them. Lead with customer-centered comms. Avoid leading with being attached to their account or telling them how you are there to help them. Tim has some great thoughts on this subject.
Open with a specific observation pulled from their actual PostHog usage, and pair it with a direct link to the relevant view in their project so they can act in one click.
Avoid fluff. "I'm just reaching out to", "I just wanted to" etc. are empty phrases that take longer to get to the point. Before you hit send, reread and see if there is anything you can cut out.
Lead with value within the first sentence. If it takes a paragraph to get there, you won't get responses.
Keep it human. Lowercase subject lines, minimal formatting, casual hooks.
Ask yourself, if I got this email to the sales@ email box, would I engage it? Would I even give it a second look?
Some examples of good emails that have worked:
Hello [name],
It looks like your Product Analytics usage has increased over the past month and I wanted to ensure that the increase was expected.
Here are some tools you can use to ensure you are collecting the correct events and getting valuable insights from them. We have a whole host of tutorials and guides to help you get the most out of PostHog.
If you have any questions, don't hesitate to ask.
[First],
Wanted to reach out direct since I noticed the [Company] team ramp up usage in PostHog recently.
We'll typically reach out to help with optimizing event capture and make recommendations with regards to instrumentation + querying in PostHog.
Up for a chat? Here's my calendar, feel free to grab a time that works best for you.
Cheers,
Pattern breakers are worth a test, too — unusual openers, intentional mistakes, personal or pop culture hooks. Don't do clickbaity things or trick people into talking to you - it'll just annoy them. And definitely don't just offer a generic checkin 'to see how things are going'!
Asking for introductions
If you feel like you have done a good job with a customer, and have genuinely been helpful, it's ok to ask for a favor back. You can be specific and ask for a direct introduction to a person you want to talk to, or try go a bit more broad and ask the person if they know anyone who would benefit from some help with PostHog. Either way, a warm introduction from a colleague is always going to be better than reaching out on your own.
Something like "Hey Leon, our session last week seemed to have landed well. I'm glad you found it useful. I was wondering if you could help me out. Your team is growing really quickly, and there's a bunch of new folks starting to use PostHog. I imagine not all of them are super comfortable with the platform yet and could use a helping hand. Could you introduce me to Simon, Charles and Scott?"
When they go quiet
Put time on the calendar instead of waiting for a reply
Rather than asking for a meeting and waiting, drop one on their calendar a couple of weeks out and give them the option to move or decline (credit to Phil). Worst case they decline, which is still a response.
Ask directly whether they're churning
Sometimes the best move is candidly asking where things stand. Seb and Jake have both broken through this way after months of silence — an email to the founder saying "is [company] planning to churn from PostHog? Or is your team primarily self-serve and happy with how things are going?" got a same-week reply and a warm intro to the actual PostHog owner, who then joined the Slack channel and booked a call. The question is easy to answer, and either answer tells you what to do next. (Slack discussion)
Rebuild a dead channel one person at a time
When a customer channel goes completely silent, don't mass-ping — it gets ignored. Instead, DM team members individually over a couple of weeks until you've rebuilt the channel one person at a time, then get them on a call together. Seb used this on a dead channel and eventually got the whole team back on a call.
Bonus — same-day call follow-up with a custom touch: A custom-branded merch discount code (set up in the Shopify admin — see the merch store handbook page) is a small detail with outsized goodwill impact. Sending it same-day rides the momentum, well before the "proper follow-up."
Suggested wording (same-day follow-up):
hey team! thanks for the productive chat earlier today.
i owe you a proper follow up on everything we discussed, but couldn't wait to share this discount code ([CUSTOM-CODE]) with ya'll so you can get your save posthog t shirt on the (hog)house :hog-party-wave:
lovely meeting you all - excited to keep working together :hog-offers-heart:
cc @[people who showed interest on the call] - tagging you since you were esp excited about the merch :slightly_smiling_face:
If you've had a conversation with someone, there was interest on their side and then they suddenly go dark, using the John Barrows Ghosting Sequence can revivify them.
After 2 weeks of valuable follow-up and you've not heard back, reply-all to the latest email thread.
Change the subject to: "Still interested?"
And put in the body:
[Name]
Still looking at options like PostHog to solve [business problem they previously acknowledged]?
Let me know either way.
That last line is very important because it gives them a safe option to say "no". About half will respond.
If there's no response again after another week, change the subject again to "Did I lose you?"
Leave the body empty. This will pick up about 80% of people who go dark. If not, close out the opportunity 3 days after this final message.
Additional Resources
Outreach rules of thumb
Try stuff. Got a quiet account? Test something unusual on it — there's very little downside, and it's how everything on this page got found.
Mix value types, not all asks. If every message is an ask, you train them to ignore you. Build trust before the ask.
Low-pressure framing."thought it was worth mentioning", "lmk if interesting", "if it's a bad fit, I'll say that and leave it there", "you may already have something like that in place". Don't push when they push back — close the loop with a clean "let's put a pin in this" so the door stays open.
Strike while energy is high. Same-day follow-ups after calls beat polished follow-ups sent a week later.
Timing matters. Consensus is that early in the week and in the morning beats Friday afternoon.
Additional creative ways to engage customers
If they submit a support request outside of Slack, jump in and respond yourself to try and build a relationship.
Create a lightweight survey across your book to gather the basics: how they're using PostHog, whether they're happy, what they need help with, and how they'd prefer to hear from you. The answers then give you a specific reason for the follow-up. Example here (credit to Luke).
Subscribe to your customers' newsletters, set up Google Alerts or Watch Tower, use their products and follow their X or Reddit communities. This lets you time your outreach for when they've just shipped something - making it about them, not you. For example, if they just launched an AI feature, you can reach out the next day to the PM or engineer and congratulate them whilst they are energized and then connect it to a PostHog product they might not be using yet that helps them make their new product better.
Find your customer's GitHub – company open source repos or individual engineers' personal projects. Review any open bugs, issues, etc. and submit a real pull request. Extra points if you fix an open bug on their company repo. The customer will see your name somewhere other than their inbox and engage. For important customers, ask our engineering team for help with more complex fixes.
Guest-list your customer to a cool event – a PostHog event, industry meetup, hackathon, etc. – where they can meet potential customers, partners, or peers in their space. You're putting them in front of people who can help their business – and that's a reason to talk to you.
If the customer has a distinct style or brand, try and match it! If you're reaching out to a CMO who primarily markets through TikTok, maybe create a TikTok explaining your point instead of an email and send it their way.
Why limit yourself just to PostHog users? Stakeholders and leadership are still invested in PostHog. If you're struggling to get a hold of someone, try going up the org chain and asking if they know the right person.
LinkedIn Sales Nav
To get notified about new hires and other changes to the accounts you manage, you can set up lists of accounts to track in LinkedIn Sales Nav.
Search for an account you want and click on their profile.
Click the star icon on the left, and then choose a list to add them to.
Optional, tailor the notifications you get in LinkedIn
You will now be notified any time a senior hire joins your account, which will be helpful for tracking folks to reach out to and give advanced signals around potential data science hires.
Every person who ever writes anything, ships anything, or talks to anyone is doing brand work. Here's how different roles can be deliberate about it.
For engineers
You might write more words than the marketing team does. PRs, commit messages, GitHub issues, Slack threads, changelogs, error messages, tooltips, empty states, documentation.
All of it is brand.
Quick guidelines:
Write clear commit messages. Other developers read them. How you describe a change reflects on you and on PostHog. Be transparent when co-authoring with AI tools.
Reply to GitHub issues like a human. If someone filed a bug, they're frustrated. Use empathy and be liberal with giving away merch.
Changelog entries are marketing. When you ship something, write a one-liner that would make a developer excited, not confused.
Don't use robotic error messages. If you're writing an error message, explain what went wrong and what to do. "An unexpected error occurred" is a cop-out.
Every UI string matters. Before shipping a feature, read every label, placeholder, tooltip, and error message out loud. If it sounds robotic, fix it. If this isn't your strong suit, ask for a second opinion – otherwise #group-marketing-and-content are happy to help!
For support & customer success
Someone who's frustrated or confused forms an opinion about PostHog based entirely on how you respond. We talk about this more in our support playbook.
For sales
Sales conversations are brand experiences. How you show up on a call, what you emphasize, how you describe competitors – all of it reflects on PostHog. We talk about this more in our sales playbook.
For everyone on social media
When you're talking about PostHog on your personal accounts, you're not officially representing PostHog, but you're still associated with it.
Feel free to:
Share your genuine opinions about PostHog and the industry
Engage authentically in conversations where PostHog is mentioned
Share things you've built or learned at PostHog
Be proud of working here without sounding like a corporate shill
Avoid:
Sharing confidential information (upcoming features not announced, customer details, financial information)
Starting Twitter wars with competitors, even if you're provoked
It's okay to be helpful or respond to posts from frustrated users, but be mindful of your tone and determine if your personal channel is the best response or if a situation should be escalated.
The simplest test: would you be comfortable with a screenshot of that tweet being shared in the #general Slack channel? If yes, go for it!
Our users are brand ambassadors too
Our brand is ultimately owned by the people who use us, talk about us, and advocate for us. We can shape it, but never fully control it.
By building a transparent, weird, and irreverent brand, we've won over a legion of hedgehog fans, some of whom pay us. They're fans, not customers – and they shape our brand as much as we do.
The better informed a user – the better user they'll be. That's why we share mistakes and lessons freely through content.
Use brand to shorten the distance. Big companies feel far away. As we grow, everything we post and every room we show up in is a chance to stay close to who we're building for.
A two-way dialog means listening, not always agreeing. We give our users a voice, and we respect what that voice says. Sometimes they'll tell us they don't agree with our choices.
Brand attracts talent. People with cool ideas want to work at companies where they see cool ideas actually come to life.
Giving someone the brand ambassador experience
The best way to create brand ambassadors isn't to ask people to be them, it's to give them an experience so good they can't help but talk about it.
Things that create brand ambassadors:
Surprising someone with merch when they post something nice or submit a helpful, detailed bug report
Responding to a GitHub issue in 10 minutes with a real answer
Shipping a feature someone asked for and tagging them in the PR
Writing documentation so good it gets shared on its own merits
Making someone laugh with a genuinely clever turn of phrase
We don't want to be a place where everything has to funnel through a single person or group, but it's also important we maintain consistency as we grow. We try to make this easy with the #design-review channel.
What needs designer approval
Not everything needs sign-off. Here's a rough guide:
| Asset type | Approval needed? | | ------------------------------------------------------------ | --------------------------------------------------------- | | New illustration or hedgehog | Yes – submit a request | | Conference booth design | Yes | | Print materials (going to a vendor) | Yes, before print | | Merch design | Handled by Team Graphics | | Partnerships or third-party co-branding | Yes | | Major website changes outside of the handbook, docs, or articles | Yes | | Social media graphics (simple) | Recommended if it's a significant post, otherwise no | | Blog post, changelog, tweet | No – but self-check against this guide | | Product UI copy, tooltips, empty states | No – but read out loud before shipping |
When in doubt, ask in the #design-review Slack channel. Lottie is, for now, the only person who can approve work or otherwise.
Who owns what
– Website, copy, major design decisions, motion work for web.
– Graphics, artwork, merch, anything illustrated, motion work for video.
– Blog, email copy, messaging guidelines, social presence.
– Email copy, external partnerships.
– Video production, editing.
– In-person events, PostHog speaking engagements, meetups, the forum, and Discord.
– Docs, obviously.
Everyone – Handbook updates.
Graphics team responsibilities
This is who owns what on #team-graphics:
Illustration (Heidi) – Newsletter and blog images, email artwork, hedgehog illustrations (used across the website, events, etc.), animating hogs, team crests, and merch design.
Graphic design (Lottie) – Website art (e.g. icons, backgrounds), paid ads, billboards and OOH, event graphics, and doing more weird. Also owns YouTube thumbnails and video assets temporarily, until the rebrand is done (then → Daniel).
Production design (Daniel) – Design ops (cleaning up and componentizing Figma), social media (repurposing existing assets only, no net new), merch file formatting, event flyers (soon to be self-serve on the web), and moving off Pitch and into Figma Slides.
🎨 Need artwork or merch? Please request it using the request templates in the PostHog/marketing repo — this is the only place art and brand request issues should be opened. Do not open them in the posthog.com repo, and do not request art or merch over Slack or email.
All artwork and merch requests are handled by Lottie Coxon, Heidi Berton, and Daniel Hawkins on the Graphics team.
They can help you with things like:
Custom visuals for paid ad campaigns
Blog and social media artwork
New themed hedgehogs
Custom CTAs and banners
Branded merch
Animated UI elements
💡 You might not need a request at all.brand.posthog.com has ready-made brand assets — logos, colors, hedgehogs, and crests — that any team can use without filing an issue. The hedgehog library below covers approved hogs too.
They get a lot of work requests, so they use two separate project boards to organize work – one for merch and one for other art projects. This reflects that merch projects often have much longer timelines and need to be handled differently.
Whenever you want to request a new merch design or other artwork, you should use the relevant design request templates in the marketing repo – one template for merch, one for other art requests. The templates assign the right people and apply the right labels, but they do not add the issue to a project board – see below for how issues get onto the board.
Art board automations
The Art & Brand Planning board uses automations to keep work moving. Each behavior below names the thing that controls it, so you know where to look when something misbehaves. Everything except the first item is a GitHub Actions workflow living in the marketing repo; the board is org-level, so the workflows act on board issues wherever those issues live.
Getting on the board — controlled by the board itself, not by the Actions workflows or the issue templates. Items are added via the board's built-in auto-add workflow (board → ⋯ → Workflows → "Auto-add to project") or by hand, and land in the No Status column by default. Every automation below only applies to issues that are on the board – an issue that never gets added is invisible to all of them.
Done → closed — controlled by art-board-status-change.yml. It polls the board every 30 minutes and closes (as completed) any issue whose Status is Done, so expect up to ~30 minutes' delay after moving a card.
Assignee sync — also art-board-status-change.yml. When an issue is moved to "Assigned: Daniel", "Assigned: Lottie", or "Assigned: Heidi", the other default assignees are removed so only the owner remains. It only ever removes assignees, never adds them, and it is driven by the board column – not the labels. Requests filed by the Graphics team themselves keep all assignees, and other columns (like "Assigned: Cleo") are untouched, as Cleo has a different workload.
Artist labels — controlled by sync-artist-labels.yml. Every 30 minutes, open issues in an "Assigned: ..." column get the matching Lottie / Heidi / Daniel label (and lose it when moved elsewhere), so work can be filtered per person. The label mirrors the column, never the other way around.
Reminders — controlled by art-board-reminders.yml (via the reusable art-board-reminder.yml). Daily at 9 AM UTC it posts a comment on issues stuck in...
Feedback/Review for 10+ days: asks if any feedback is needed to move the task forward.
No Status for 7+ days: asks someone to pick it up or assign it to a column.
Each issue only ever gets one reminder of each type, and snoozed items are skipped.
Credentials — the workflows authenticate as the Art Board Bot GitHub App. Its credentials are org-level Actions secrets scoped to the marketing repo, and the app installation needs access to every repo that holds board issues. If all the workflows suddenly start failing at the "Get app token" step, one of those two things is the cause.
To establish a clear connection between the task and the working file, designers will create a frame containing a link to the task. They should then add a link to that frame within the task for easy reference.
Please give two weeks notice for new briefs — this is the preferred minimum, and more time is always better. For reference, the team receives roughly 25-30 new art requests a month, so new briefs are rarely picked up the day they land. A one-week turnaround is only possible for actual emergencies. If your request is a genuine emergency, please share your request issue in #team-graphics channel and mention Lottie, Heidi and/or Daniel.
If you need to chase for an update on a request, the best place to do it is a comment on the issue itself, not a Slack DM. Comments keep the context with the brief, notify the assigned artist, and the team triages from the project board.
Hedgehog library
For team members we keep all our currently approved hedgehogs in this Figma file. This enables us to look through the library of approved hogs, and to export them at required sizes without relying on the design team.
Here's how:
Open the Figma file. You can manually browse, or use Cmd + F to search based on keywords such as 'happy', 'sad', or 'will smith'.
Select the hog you want. If needed, adjust the size using the 'Frame' menu in the top of the right-hand sidebar.
At the bottom of the right-hand sidebar, select the file type you need in the 'Export' menu, choose @2x, then select 'Export [filename]' to download the image.
Want to use our hedgehogs for your community event or article? We have a huge library of them you can use. Can't see what you need? Let us know! Please don't use AI art though. We're quite particular about our illustrations and AI just doesn't get it right.
Logo and brand usage for third-parties
We’re really happy people want to build on top of PostHog, but we want to keep it clear when something is made by us or made by someone else. If you've built a third-party app on top of PostHog or want to partner with us in some way, here is some high-level guidance for you to bear in mind.
We're _generally OK_ with people using the PostHog name to describe compatibility. For example, you can say your product "works with PostHog," is "built for PostHog" or "built on PostHog".
We're _not OK_ with people using the PostHog name to make it look like your project is made by, endorsed by, or is officially partnered with PostHog if it isn't. So for example, while "Desktop Studio for PostHog" would be fine, "Official PostHog Desktop Studio" or "PostHog Desktop Studio" would not be.
You can use our logo or brand assets only in unmodified form, and not as the main branding for your own project. However, you may not use our hedgehog mascot or other illustrative brand assets in any commercial or marketing materials without explicit permission, as this can imply endorsement and confuse people. You cannot make it seem like your product is an official PostHog product, or that we've endorsed your product or partnered with you if we haven't. Please make sure that logo, brand asset and name usage are consistent with the rules we've laid out in this page.
We don't like doing it, but if we spot some name, brand asset or logo usage that are inconsistent with our guidelines or brand, we will reach out to try to get that sorted out, so please try to be thoughtful about branding and try to be consistent with the guidelines we've set out here. If you have questions, please reach out to us at marketing@posthog.com for clarification.
Briefing external vendors
When you bring in an external party to produce brand work – a print vendor, a video production company, a hotel, a conference AV team – send them this guide. Key things to brief them on:
Typography (provide font files or specify licensed fonts)
Illustration style (share examples from posthog.com and Figma)
What "not on-brand" looks like (blobs, stock art, generic SaaS layouts)
Avoid pairing the logomark with the "PostHog" wordmark in regular text that isn't part of the logo itself.
Logo
If you're looking for the PostHog logo, you came to the right place. Please keep the logo intact. SVG is always preferred as it will infinitely scale with no quality loss.
Each logo below is rendered live from our @posthog/brand library — the single source of truth for the mark — so it always matches the current logo. Click any format to download it (logos are transparent; the previews sit on a solid background color). If you're building a PostHog UI, import the parametric <Logo> component from @posthog/brand directly rather than downloading a file. A flat 4-color/CMYK (print) variant is also available from the library for print vendors.
When to use each logo
The standard logo — the full-color one, with gradients — is the primary logo. Use it by default.
On dark backgrounds, always use the light logo (the white version) — never the standard/full-color one.
On light backgrounds, prefer the standard logo, and only reach for the dark logo (solid black) when a single-color mark is required.
Use the print (4-color) version only for print or other limited-palette contexts where the gradients can't be reproduced.
Use the logomark on its own only at small sizes — favicons, app icons — where the full lockup won't fit and the overlapping gradients would get too busy.
Use a square logomark for avatars and integrations that require a square image. Its transparent square canvas keeps the logomark's proportions intact — never stretch the standard logomark to fill a square. Use the standard gradient version on light backgrounds, or the light solid-white version on dark backgrounds.
Use the stacked logo for portrait or square placements where the standard (landscape) lockup is too wide.
_Never_ modify the colors in the logomark (for example, don't recolor the hedgehog's face white on a dark background — use the light logo instead).
The padded PNGs help when uploading to a third-party service with no control over margin around the logo, and the @2x versions are for hi-dpi (or "Retina") screens — include them when a service accepts both.
Using an older version? These logos come straight from the @posthog/brand library, so this page always reflects the current mark. If you have an older PostHog logo saved locally (e.g. a square font or sharp-edged logomark), please replace it with the current version from this page.
Squeak
Squeak is used in informal settings, generally accompanied by hedgehog artwork.
Usage guidelines
When used for headlines or at larger sizes, use the Bold variant
Only for small (description) text, use the Normal variant in regular casing. Never use for more than a couple lines of text in a row.
Always use uppercase letters
Letter spacing: -2%
Line height: 100% (generally)
Examples
Image: Squeak font example
Image: Squeak font example
Image: Squeak font example
Loud Noises
Loud Noises is used for quotes in hedgehog artwork.
Usage guidelines
Only use for quotes in hedgehog artwork or where hedgehogs are otherwise communicating something
Only use uppercase
Example
Loud Noises is used in the sign the hedgehog is holding:
When possible, use opacity to modify colors. This allows us to use fewer colors in our palette, which is light years easier when working with two color schemes.
We use Pitch for polished presentations (like when giving a talk). Read more about this in our communication guidelines.
Illustration guide
Our hedgehog mascot is called Max and we're quite particular about how he (or any of his hoggy pals) are illustrated. We're exploring AI tools for internal use, but currently ask that you don't use AI tools to create your own hedgehog art. Instead, you can follow the guidelines below, or create a new art request.
Image: How to draw a hedgehog
If Max is drawn in color he should always have a beige body with brown spines, arms, and legs. His arms should only bend once in the middle and he doesn't have fingers unless swearing or pointing. His feet are stubby by design and his snout lines should be visible unless obscured by a mask or beard. His expression comes mainly from his eyebrows.
Image: Draw the rest of the hedgehog
He should be outlined with a strong, black monoline with consistent thickness. He should always face left, right, or straight-on but shouldn't be drawn with a side profile or from behind as he's self-conscious.
A more detailed version of this guide is available on Figma for team members.
Hedgehog library
For team members we keep all our currently approved hedgehogs in this Figma file. This enables us to look through the library of approved hogs, and to export them at required sizes without relying on the design team.
Here's how:
Open the Figma file. You can manually browse, or use Cmd + F to search based on keywords such as 'happy', 'sad', or 'will smith'.
Select the hog you want. If needed, adjust the size using the 'Frame' menu in the top of the right-hand sidebar.
At the bottom of the right-hand sidebar, select the file type you need in the 'Export' menu, choose @2x, then select 'Export [filename]' to download the image.
The is responsible for everything you see on posthog.com. We treat our website & docs as a product, which means we're constantly iterating on it and improving it.
Because our website has a well-defined aesthetic, we often skip the hifi design process and jump straight from wireframes into code. Having a designer who can code means we can reach the desired level of polish without _always_ having to produce hifi designs, thus leading to huge time savings.
Step 1: Wireframes [Balsamiq]
We often produce hi-fidelity wireframes because this allows us to closely envision a design which in turn helps us skip the hi-fi Figma process.
_Note: Balsamiq uses its own Comic Sans-style font. Don't get hung up on this!_
If there are multiple iterations of a single page, we typically work left to right.
Any mocks in pages that appear to be faded out are considered _old_ and _out of date_ and can be ignored, as there is a better replacement nearby. (We sometimes want to keep them around for easy reference (and to leave a comment trail), but they're easily identifiable because their artboards are set to 50% opacity.)
Even with this loosely-documented process, things move quickly and we don't always follow this process. If you're looking for something in particular, it's worth pinging in the #team-brand channel.
We're also working on creating a singular place for product screenshots, which are exported in light and dark mode using html.to.design.
If you work at PostHog, you are a brand ambassador. This brandbook outlines how to extend our brand to your personal responsibilities at PostHog.
What is brand?
PostHog's brand is the total sum of how people experience us – from a first visit to posthog.com to an onboarding email, from how quickly we ship a bug fix someone complained about on X to billboards, merch, event collateral, ads, and more.
Every person who encounters PostHog forms an opinion. Brand is the accumulated weight of all those opinions.
This matters for two reasons:
Brand is a growth driver. It's one of the four main reasons PostHog gets recommended. People who trust a brand talk about it. Developers who find us authentic fight for us in comment sections.
Trust is slow to build and fast to lose. A generic headline, a forced joke, a bad sticker, a robotic support reply – each of these chips away at the trust we've earned.
Our mindset
Everything flows from two ideas:
"Yes and…" We expand ideas instead of shutting them down. When someone proposes something, the instinct is to find what's interesting about it and build on it – not critique it to death. This shapes how we design, how we write, and how we talk to each other.
"We can do this better ourselves." The best things get made by people who genuinely care about what they're making. When we ship something, it should feel like someone made this on purpose – not like it was generated, templated, or outsourced.
Taste
Taste is the most important principle PostHog has. "Polish" is surface-level – smooth gradients, perfect shadows, trendy layouts – the visual equivalent of buzzwords. "Taste" is deeper: making decisions that reflect a real point of view, caring about whether something is right and not just done, going the extra mile even if only one person notices.
Something made with taste looks like someone made this on purpose, especially in a world where more people are shipping AI slop.
What taste looks like in practice:
Caring about details. Typography, spacing, alignment, whitespace – or the exact wording of an error message – these are felt even when not consciously noticed.
Intentionality. Every element has a reason to be there.
Going the extra mile. Especially for things most people won't notice (you'd be surprised how many actually do).
Enjoying the work. When you enjoy making something, it shows.
Knowing when trends are played out. Our visual identity is nostalgic and distinctive because we deliberately avoided what everyone else was chasing.
Brand personality
PostHog should feel:
| Feel like this | Not like this | | -------------- | ----------------------------------------- | | Opinionated | Diplomatic to the point of saying nothing | | Human | Corporate robot | | Slightly weird | Trying to be funny in a try-hard way | | Thoughtful | Random | | Direct | Fluffy | | Honest | Corporate fluff | | Playful | Childish or unprofessional | | Approachable | Arrogant |
Who we're talking to
Our primary audience is AI-pilled builders – product-minded, full-stack engineers with a slight bias toward the frontend – and product-minded builders more broadly. Many of them are technical founders or assume the role. It's incredibly important that we don't alienate them, as they're a driver of word-of-mouth growth.
We should assume our audience either has to do technical work or wants to, regardless of whether they can code. Most of them are developers, and for the rest, we're the bridge, giving everyone direct access to data and the power to ship.
This shapes everything. Developers...
distrust marketing by default. They've been burned by overpromising before.
prefer specificity over benefits language. "It does X" beats "It empowers you to unlock X."
can tell within seconds if something is authentic or corporate. They view source code for fun.
react well to honesty, including honesty about limitations and tradeoffs.
respond to wit, but are allergic to forced humor.
The right model: you're talking to a smart, skeptical friend who happens to be a product builder. Not an enterprise buyer. Not an executive. A person.
When we are working on content (like blogs, docs, and tutorials) for a specific product, we should write it for the persona of that product, which might be different from our primary persona.
Before you ship anything – copy, design, a campaign, a policy – ask: how would this be received on Hacker News?
Hacker News is intensely logical and skeptical. They'll call out corporate spin, vague claims, and try-hard humor in seconds. If you think your thing would get roasted, change it. If it would hold up to scrutiny, ship it.
How we describe PostHog
Nothing has changed about our overall positioning: PostHog makes _your_ product self-driving. This is the frame everyone at PostHog should use, across the product, website, marketing, content, and support. Product marketers can find the granular vocabulary rules and the per-product playbooks in Positioning and selling.
Self-driving is the story
Self-driving is the narrative everything sits under. PostHog makes your product development self-driving – a better version of you, with your product and all its context in one place. It isn't an app or a product you can point at. It's what PostHog is and enables. Don't write "PostHog is a self-driving product" or "the self-driving app" – keep the customer's product as the subject.
Because it describes what PostHog enables, not something we ship, always write it lowercase and hyphenated: it's not "Self-Driving" or "self driving", it's "self-driving".
The elevator pitch
Use this when you are telling someone what PostHog does, e.g. at an event.
PostHog makes your product self-driving. It automatically diagnoses problems, fixes bugs, and generates pull requests – all without you having to prompt it.
The standard description
Use this whenever you need a longer standard description of PostHog, e.g. for a newsletter or press. We also embed this in all our blog posts.
The four layers
Everything we offer is one of four things. Use these words exactly:
Apps – the surfaces a customer adopts; how you access self-driving. Today that's PostHog Web (app.posthog.com, where Inbox and PostHog AI live), PostHog Slack, PostHog MCP, PostHog CLI, and PostHog Desktop. PostHog Mobile is coming. The context warehouse has its own PM/PMM and pricing, but on posthog.com we present it as the platform everything is built on, not as another item in this list.
Products – the functional capabilities accessed through the apps: product analytics, session replay, feature flags, experiments, error tracking, surveys, web analytics, and so on (as granular as annotations or comments).
Context – the data that feeds the self-driving loop: events, recordings, errors, and logs from PostHog, plus other business data (Slack, code, Notion, support tickets, and so on). This is the fuel.
Context warehouse – the data warehouse plus the full context-ingestion pipeline (modelling, data pipelines, batch exports, and so on). Don't say "PostHog Data Stack" – the warehouse, modelling, pipelines, and exports are all part of the broader context warehouse, and "Data Stack" isn't something we talk about externally.
In one line: self-driving is the story, apps are how you access it, products are the supporting capabilities, context is the fuel, and the context warehouse is the platform where context lives.
There is a lot of hard-earned knowledge in the startup and product space that builders don't know yet because it's not written for them. We've also learned a lot from building PostHog and from our customers. We want to share all this with them.
We provide all the tools developers need to build successful products. All of them are powerful, but require expertise to use effectively. Some don't even know these tools exist. We help build this expertise by providing world-class docs, tutorials, and technical content.
Anyone can build successful products. Developers don't need product managers or data analysts to tell them what to build. Formerly "non-technical" people don't need developers to write code for them. With the right tools and knowledge, anyone is capable of making product decisions themselves.
Talking to users, shipping what they want fast, debugging and fixing issues, measuring impact, and iterating is the core loop of building successful products.
PostHog aims to do "the right thing" for our users. We're self-serve with usage-based pricing. We don't have loss leaders and are in it for the long haul. We don't do sleazy marketing or sales tactics. We're open source and transparent. We don't want to be another boring B2B SaaS company, even if that is "optimal for the creation of shareholder value."
Why people pick PostHog
We help people debug and ship their product faster.
PostHog already has all the data about how people use your product and how your product performs, like usage analytics, error tracking, session replays, logs, traces, and more. This lets them discover and understand issues and their context, but also feeds our self-driving loop.
This loop turns that data into signals, feeds those signals to an agent running in a sandbox, and automatically opens PRs that improve your product. Both our agents and the user can then use feature flags to roll out new features, experiments to measure impact, surveys to get feedback, and evals as checks.
We have all the products and context in one. This means less time spent patching separate services together and paying for them all separately. When builders (and their agents) need a new capability, they can just use PostHog.
Our team is technical and speaks the language of developers. Our engineers talk with customers to figure out what to build. Our support team are all former engineers and get into the nitty-gritty of issues. Our sales and CS teams are very technical too. They focus more on your use cases and implementation than steak dinners.
We want engineers to self-serve. They can sign up and use all of the features of PostHog for free.
PostHog could be a lot of things, and we have a lot of terms for the same things. This creates cognitive load and confusion, and we'd rather our audience use their energy elsewhere.
A few things to avoid when describing PostHog:
Not "an analytics platform." PostHog has grown well beyond analytics. Lead with what we actually are: a platform that makes your product self-driving, with products — product analytics, session replay, feature flags, and more — that help people build successful products.
Not a single product. We're a platform that makes _your_ product self-driving — you (and your AI agents) ship improvements from your product's own context.
Not a "product improvement platform." This is vague and buzzwordy.
Not enterprise-first. We build for people who self-serve. We get in early and grow with our customers. We don't go out of our way to build niche features just to chase a large contract. Don't let copy, design, or tone drift toward enterprise-speak.
Not a "dev tool platform." This makes it seem like we are just dev tools to use.
Not a collection, group, set, bunch or any other collective noun of products or apps. We are not "product and data tools" as this isn't developer-focused enough. Product and data should refer to our customer's products and data.
Not a "product analytics product." The doubled word reads badly – say "product analytics" on its own whenever possible.
Messaging framework
This is our shared messaging framework. For the full context behind it, see the repositioning RFC.
Product name and one line description
PostHog makes your product self-driving. Hand off issues, the analysis, and the grunt work, and put your time where it counts - figuring out what customers want and shipping it.
Market category
Self-driving software product platforms.
Competitive alternatives
Anthropic (with very thin product context via MCP)
Snowflake (without the coding)
Amplitude Wave (without the business context or engineer focus)
Anyone shipping 'self-healing' or 'self-improving' software
Unique attributes -> value
Agents that act unprompted, off your data -> your product improves without you driving every step, so your time goes to the creative work only you can do
Your product and business context, unified in one context warehouse -> PRs grounded in how your product actually behaves, not generic slop -- and near-impossible to match without the data you already give us
We train our own models -> lower cost to you, with open source models tuned for finding and fixing product bugs rather than general-purpose coding
Open source and transparent -> no black box and no lock-in: you can read it, fork it, and see exactly what's running inside your product
Who cares a lot?
Engineers building products in AI-pilled software teams at any scale.
This section covers how the brand should appear across every surface where PostHog shows up.
Website (posthog.com)
The website is our primary brand expression. It gets the most scrutiny and sets the expectation for everything else.
Design principles for web
Art accentuates content; it doesn't distract from it. Content always comes first.
Smooth drop shadows on cards and contained elements. Pops of color where appropriate.
Typography hierarchy is deliberate and readable at every viewport.
Copy principles for web
Lead with the specific. Don't open pages with a mission statement.
Short paragraphs. Developers scan.
No walls of text. Break with subheads, illustrations, or white space. Ideally a paragraph doesn't contain more lines than the number of fingers on your hand.
Every page should have one clear next action.
Product UI
Product UI has a different purpose than the website or other surfaces. The design should get out of the way and let them do it, but should still nod to being part of PostHog in tasteful ways.
Principles
Clarity > cleverness. Clear empty states, error messages, and loading states.
Typography: RoundHog for titles and buttons; system font for body in product.
Icons: Central Icon System (outlined vector icons, 1.5px border).
Don't use Squeak in product UI – it's a marketing/hedgehog-context font only.
Use our icon and color systems consistently; don't introduce new visual elements without design review.
Product writing
Every label, button, tooltip, placeholder, and error message is brand. Write them like a human being, not a system log.
Empty states: tell users what to do next, not just that there's no data.
Error messages: explain what happened and what the user can do about it.
Confirmation dialogs: be specific about what will be deleted/changed.
Documentation
Docs are often the first deep experience someone has with PostHog. They need to be accurate and clear above all else, but that doesn't mean they have to be cold.
Principles
Use second person ("you").
Write for someone trying to accomplish a task, not trying to understand a concept in the abstract. Making something tangible helps the reader understand how it applies to their use case.
Code examples should be real, and should be context-aware. For example, if the visitor changed the language of a code snippet, we should infer that's the language they're interested in on other pages.
When something is limited or has a gotcha, say so. Developers will find it anyway. Don't downplay flaws or product gaps. It creates trust when we're honest. This is why each product page has a section that covers reasons a user might not be a good fit to use a PostHog product.
Small personality touches are welcome in introductions and notes – not in the middle of an instruction.
Blog, newsletters & social media
Every blog post should make an argument. Not "here are some thoughts about X." An actual point of view.
Social media channels can be more casual and reactive than the website, but they should never feel like a corporate account posting congratulatory content or generic "tips."
PostHog uses Figma Slides for polished presentations. See the communication guidelines for more.
When designing a deck
Fewer words per slide. One idea per slide.
Don't use slide templates that look like every other B2B SaaS deck.
Use the templates supplied by the Graphics Team. Use of the Squeak font is fine for punchy visual moments.
PostHog color palette throughout.
Hedgehogs can appear – use the art library.
Informal decks (internal, demos)
These have more flexibility. Speed > perfection. Use the existing templates and don't spend hours on formatting.
Our board meeting deck still uses a title slide with branding circa 2021, but it (sort of) intentionally shows we put our focus in the right places, not in making pretty decks for people who already believe in us.
Events & conference booths
Events are a high-density brand moment where first impressions form in seconds. Booth design, event-specific assets, and staffing guidance live in the Marketing events handbook.
Print materials
Print requires additional consideration because you can't iterate after it's shipped.
General rules for print
Export at 300 DPI minimum for anything that will be physically produced.
CMYK color profile for print. (Note: our brand colors are defined in RGB/hex. Confirm CMYK equivalents with the design team before going to print.)
Bleed and safe zones: Use standard 3mm bleed. Keep critical content at least 5mm inside the trim line.
SVG logos always preferred as source; export as PDF for print vendor.
Materials that commonly need to be produced
Posters: Think billboard-first. One message. One big visual.
Brochures: Rare. If needed, follow the website's editorial style and make it look handcrafted, not template-y.
We've traditionally avoided sell sheets or business cards, but work with the Graphics Team if you need something specific.
Approval:
All print materials should be reviewed in #design-review before going to print. Mistakes in print are expensive. Submit a request early.
Merch & swag
Merch is brand in the physical world. It's also one of PostHog's most effective developer marketing tools. That means merch has to be genuinely good. We put a lot of effort into our merch.
The bar for merch
Would someone who doesn't work at PostHog actually want this? If the honest answer is "probably not," it's not good enough.
Bad merch: cheap pen with a logo, generic t-shirt with a logo on the left chest, tri-blend, etc. If you can order it from a website where all you have to do is upload your logo and submit payment, it's not the right approach for us.
Good merch: great hoodie people actually wear, thoughtful sticker set, item that's interesting in its own right and happens to be branded.
The hedgehog earns his spot on merch – he's one of the most recognizable things we have.
Hard drop shadow aesthetic on graphic elements.
Limited palette. Don't print 8 colors when 3 work.
Quality over quantity. One great item beats five mediocre ones.
Logo placement on merch
Embroidered chest logo: use the logomark only (not full wordmark) for embroidery. The hedgehog logomark embroiders cleanly; the wordmark can get muddy at small sizes.
Screen printing: full logo or logomark work. Use high-contrast colorways.
Sublimation/all-over print: can use full illustrations. Requires design team involvement.
Giving away merch
PostHog has a deliberate strategy of giving merch to people who say nice things about us publicly. This creates genuine brand advocates. See our merch guidelines for how to do this well.
YouTube & video
Video is a growing PostHog channel. While the video handbook covers our overall approach, we also have specific guidance on thumbnails, which are easy to overlook and do an average job at:
It's one of the four major reasons people get recommended PostHog so directly helps us grow. Everyone else is largely terrible at it so it's a massive opportunity to build a long term advantage as a company, and frankly it's fun. It's every interaction we have with our users and comes from how the company itself is designed. It's more than hedgehogs:
When it comes to attention on the internet, you are competing with cat videos and TikTok, _not_ B2B SaaS competitors. Be realistic - if it's not actually funny (and it's "corporate try hard") then it's not good enough. At one point we realized we were getting cutesy - "ooh a hedgehog". That's not interesting enough for people outside PostHog, even if we think it's cool.
It is thus encouraged to be rogue / sarcastic / meme-y / unhinged / weird.
Our competitors are (i) more defensive and self-interested in their approach (focused on optimizing revenue growth), and (ii) more boring. Let's keep it that way. If we have fun, we'll stick it out longer and will win in the long term.
Brand first
We should always optimize to not piss users off unless they're being totally, extremely unreasonable, in which case figure out how to be the bigger person. Even when that costs us revenue.
For example, we should refund customers when they screw up their tracking and get a shock bill.
Pavlovian merch response
Give it out to people who say nice things about us. That'll create an army of developer warriors fighting for PostHog on the internet!
Breaking bad news
Sometimes you may need to tell customers something they don't want to hear - e.g. "we don't have X planned in our roadmap". Instead of a vague "I'll share this feedback" type response, be specific and give context like "Hey we don't have that planned because we're focused on X, Y, Z at the moment. If you want to suggest it to the wider team, you can do so by X".
Karma
Be helpful to other companies. We are here to increase the number of successful companies in the world – especially those with high potential that are putting in the work, like YC current batch ones. For example, if a YC company reaches out, take them seriously and buy their product (if it's genuinely valuable and safe to do so) or give direct feedback if not.
Write the way you'd explain something to a smart friend, not a business associate you're trying to impress or a prospect you're trying to close.
That means:
Clear and simple. If a simpler word works, use it.
Specific. Concrete nouns and real examples beat abstract claims every time.
Direct. State what the thing is. Don't make the reader infer. Don't use filler words.
Honest. Including about limitations. Developers trust honesty more than polish.
Conversational. Contractions are fine. Starting a sentence with "But" or "And" is fine.
No jargon for jargon's sake. Technical precision when it helps. No buzzwords.
No emojis. Emojis come off as try-hard and cringe. Avoid them, and prioritize using plain English.
If there's an industry-standard phrase, question if it's actually the best way to describe something – or if somebody came up with it once and then everyone else followed suit. Maybe it makes sense to stick with it, but we also have the unique opportunity to coin a new term if the juice is worth the squeeze.
What to avoid
Hedge words and weasel phrases
These make copy feel weak and corporate. Cut them:
| Instead of this | Consider... | | ----------------------- | -------------------------------------------- | | "helps you to" | just say what it does | | "empowers teams to" | say what teams can now do | | "enables you to unlock" | say what they get | | "leverages" | uses | | "utilize" | use | | "streamline" | speed up / simplify | | "robust" | strong, solid, or just describe it | | "best-in-class" | show, don't claim | | "holistic" | comprehensive, or just describe the parts | | "seamless" | describe why it's easy | | "synergy" | C'mon, really... |
Passive voice
Active: "PostHog tracks your events." Passive: "Events are tracked by PostHog."
The active version is shorter, clearer, and more confident.
Feature-first headlines
"Introducing our new dashboard" says nothing about why anyone should care. Lead with the benefit or the specific capability.
Forced humor
A joke that has to be explained isn't funny. Humor in PostHog copy works when it's specific, unexpected, and comes from a genuine perspective. It doesn't work when it's "here's a wacky metaphor to make our SaaS product seem fun."
When in doubt, just be clear. Clear beats clever, and makes the genuine humor stand out.
For how the voice shifts across surfaces (website, product UI, docs, blog, social, support, GitHub), see Brand in practice.
Dos and don'ts with examples
Headlines
| ✅ Do | ❌ Don't | | -------------------------------------------------- | -------------------------------------------------- | | "Feature flags that don't slow you down" | "Supercharge your feature delivery workflow" | | "See exactly what your users are doing" | "Unlock actionable user insights" | | "Built for engineers who ship fast" | "The all-in-one platform for modern product teams" | | "Ship, measure and iterate – all on one platform." | "Streamline your product development lifecycle" | | "Make your product self-driving" | "PostHog is self-driving software" |
On that last one: PostHog makes _your_ product self-driving. Keep the customer's product as the subject — they get a product that improves itself; PostHog is how. See how we describe PostHog for the full nuance.
Body copy
| ✅ Do | ❌ Don't | | ------------------------------------------------------------ | ------------------------------------------------------------ | | "PostHog stores your data in your own cloud." | "With PostHog, you can leverage our advanced data sovereignty capabilities." | | "There's no separate pricing for each product. Pay for usage across all of them." | "Our holistic pricing model enables teams to seamlessly utilize all of our integrated products." | | "We wrote this ourselves because existing solutions weren't good enough." | "Drawing on our extensive expertise, we've developed a best-in-class solution." |
Error messages
| ✅ Do | ❌ Don't | | ------------------------------------------------------------ | ------------------------------------------------ | | "Can't connect. Check your API key and try again." | "An error has occurred. Please contact support." | | "This experiment needs at least 100 events before we can calculate significance." | "Insufficient data for statistical analysis." |
Emails
| ✅ Do | ❌ Don't | | ------------------------------------------------- | ------------------------------------------------------------ | | "You've been quiet for a bit. Here's what's new." | "We noticed you haven't engaged with our platform recently and wanted to reach out." |
Social Media
<th>✅ Do</th> <th>❌ Don't</th>
<td>"We have a million products and never talk about most of them, so here's a full list"</td> <td>"PostHog has more than two dozen varied products for your needs. They are:"</td>
<td>"Introducing PostHog Desktop, the product editor that:<br/>• Understands your product<br/>• Identifies usage patterns<br/>• Triages bugs and errors for you<br/>• Creates PRs to fix them<br/>• Continuously monitors and improves your product"</td> <td>"PostHog Desktop is the product editor that understands your product, identifies usage patterns, triages bugs and errors for you, creates PRs to fix them, and continuously monitors and improves your product."</td>
<td>"Fable 5's in PostHog Desktop (again)"</td> <td>"We're proud to announce that Fable 5 is now available in PostHog Desktop. Happy coding!"</td>
<td>(reply) "this is incredible"</td> <td>(reply) "Nice work! We love it!" 😁</td>
PostHog's visual identity is intentionally distinctive. It should feel handcrafted, slightly weird, thoughtful, and recognizable. If a design element could belong to any SaaS company, it probably isn't PostHog enough.
The test: remove the logo. Does it still feel like PostHog? It should.
This identity is also un-copyable – because it's a reflection of the people who made it, and it keeps evolving as they do. No design system doc can quite define it, because it's constantly evolving and is subject to the taste of the people creating it.
There's a version of PostHog that could use AI to produce all of its illustrations, icons, and copy. It would be faster and cheaper. It would also be instantly identifiable as not made by humans, and that trust signal would erode. Handcrafted beats generated.
| Variant | When to use | | ------------------------------------------------- | ------------------------------------------------------------ | | Standard logo (horizontal, colored with gradient) | Default for the web. Use this most of the time. NEVER use on dark backgrounds. | | Dark logo (black wordmark) | Light backgrounds where full-color feels off. | | Light logo (white wordmark) | Dark backgrounds. | | Logomark only | Small contexts (favicons, app icons, social avatars). Use only when the full logo won't fit. | | Stacked logo | When horizontal space is limited but the full name is important. | | 4-color logo | Print version, when gradients can't be printed. Only use the 4-color logo for this case. |
Download all variants from brand assets. SVG is always preferred.
Rules
Never modify the logomark colors. Don't turn the hedgehog face white on a dark background. Use the white-logo variant instead.
Never stretch, skew, rotate, or add effects to the logo.
Never use the old logos. We updated it in 2021 (rounded the edges, rounded font) and then again in 2026 (gradient, no space between the body elements of the hedgehog). If you see the old versions anywhere, replace it or let us know in #design.
Maintain clear space. Leave at least the height of the "P" in PostHog as clear space around all sides of the logo.
Minimum size. Don't use the full logo below 80px wide. Use the logomark instead.
On colored backgrounds. Use the light (white) version on dark/colored backgrounds. Never use the standard logo on a background that makes it unreadable.
What not to do
Don't place the logo on a busy photographic background without a clear container or sufficient contrast.
Don't use the logo as a watermark at reduced opacity.
Don't surround the logo with other logos of similar size – it should have room to breathe.
Don't animate the logo (spin, bounce, glitch) without explicit approval.
Color system
PostHog uses a deliberately limited palette. Fewer colors, used consistently, create a stronger visual identity than a sprawling palette used inconsistently. For hex values, see brand assets.
How to use color
Color guides attention – it doesn't decorate. In practice:
Backgrounds should be solid, not gradient-heavy.
Illustration is where color lives. Illustrations should be more saturated than the surrounding layout to draw the eye.
The more color you use, the less any single color means. Use restraint.
Use opacity to modify colors rather than adding new ones: paragraph text at 90%, links at 95%, links on hover at 100%.
Gradients. PostHog uses no gradient backgrounds by default. Gradients are a cliché of generic SaaS design. When in doubt, solid.
What to avoid:
Rainbow palettes or too many simultaneous accent colors
Dark-on-dark combinations with insufficient contrast
Using red (#F54E00) for warnings or errors (it's a brand color, not a status indicator – use separate status colors in product UI)
Typography
PostHog uses three typefaces, each with a specific role. Using them correctly is one of the fastest ways to make something feel on-brand.
RoundHog
Our primary typeface. Used for all text on posthog.com and in most contexts.
Cuts used:
Bold – Titles and section headers
Semibold – Paragraphs with large headers, paragraph links
Regular & Regular Italic – Body text
Italic variants are available for Regular, Medium, Semibold, and Bold.
Squeak
Used for marketing headlines and informal settings, generally accompanied by hedgehog artwork. This is our expressive, personality-forward display font, _not_ used for copy or descriptions.
Usage rules:
Always uppercase. No exceptions.
Use the bold variant. No exceptions.
Never use Squeak without hedgehog art or a deliberate informal context (event signage, stickers, merchandise, splash screens)
Never use Squeak for body text, subtitles, or descriptions.
Loud Noises
Used exclusively for quotes in hedgehog artwork – the signs, speech bubbles, and text the hedgehogs are holding or saying.
Usage rules:
Uppercase only
Only in hedgehog artwork contexts
Do not use for any other purpose
General typography rules
Hierarchy is everything. A page with three levels of size that mean nothing teaches readers nothing. Every size choice should communicate something about importance.
Sentence case for headings. "Documentation style guide" not "Documentation Style Guide."
No decorative fonts beyond the three listed here.
Left-align body text by default. Center-align is fine for short marketing headlines and call-outs.
Line height. The most obvious way for a design to feel not _quite_ right is for the line height to not be dialed in. Take special note of the line height for individual elements where text wraps, as well as the space between associated elements like a title and description. If you have questions, ask in #design-review.
Illustration & hedgehogs
Our mascot: Max
Max is our hedgehog mascot. He's a core part of the PostHog visual identity. He's a creative vehicle for translating our personality into something expressive and alive. Use him thoughtfully, not just to fill space. For how to draw him, see the illustration guide in brand assets.
Do not:
Use AI-generated hedgehog art. PostHog is very particular about how Max looks, and AI doesn't get it right. If you need a new hog, request one.
Modify existing hedgehog illustrations without approval.
Use competitor hedgehog styles or derivative designs.
Use our artwork on a personal website or for anything that isn't PostHog-related. While our code is open source, our brand assets are property of PostHog. (The exception is for assets explicitly intended for community use like desktop or mobile background images.)
Artwork library: Team members can find all hedgehogs under the Account menu -> Art library.
Illustration style (general)
Beyond Max, PostHog illustration has a consistent aesthetic:
Custom, not stock. Stock illustrations are instantly recognizable and forgettable. We draw our own.
Simple and expressive. Complex doesn't mean good. Usually the simpler illustration works better.
Bold and graphic. Thick outlines, strong shapes, limited color palette.
Bringing external elements into our world. We sometimes re-draw external things (competitor logos/mascots, cultural references) in our style.
Team crests are bold, punchy graphic badges used to represent PostHog's internal small teams. They're an extension of the brand's slightly irreverent, self-aware personality.
Bold, punchy designs
PostHog's color palette
Can appear on stickers, slide decks, team merch
Stickers
Stickers are a significant part of PostHog's culture and brand ambassador strategy. People actually use them. Rules:
Small team crests can work well as stickers
Die-cut is preferred over square/rectangle stickers
White border with hard drop shadow is the PostHog sticker aesthetic
Portraits
When we need portraits of real people, we use hand-drawn realism style rather than photography alone. This keeps a human, handcrafted feel that's consistent with the broader illustration identity. Every employee has received a hand-drawn illustration based on a photo of them since the inception of when Lottie was hired as Graphic Designer.
Icons
PostHog uses three icon styles for different purposes:
We care a little too much about icon glyphs. Icons should be intentional.
When an icon is accompanies by a label, the icon should be complimentary.
When an icon is used without text, they should be clear enough to stand on their own.
Use restraint when selecting an icon, and rather than sourcing your own, ask in #design.
Interaction
User interfaces should feel...
snappy, thus we don't use animation when hovering onto a button. It's okay to use an animation when leaving a button.
interactive, thus a slight zoom effect on hover and a "pressing down" feel when clicking a button is a subtle way to spark joy.
Animation
When animation is used, it should feel deliberately understated – not flashy or attention-grabbing. Animation is one of the most challenging things to get right. Without extreme attention to detail (like easing, for example), icons can feel cheap. It's better to _avoid_ animation than implement something that feels even a little bit off.
PostHog animation characteristics:
Puppet rigging for character animation (Max and other hedgehogs)
Shadows animate with the character
Animate in rather than looping constantly (team crests, blog art) and ease out to a still final frame
Use animation to add delight and bring characters to life – not to distract from content.
Photography
When photography is used:
Prefer candid, authentic shots over staged, stock-style photography
Real team members > stock people
Real situations > constructed scenarios
If using desktop/screen mockups, keep them honest (don't fake impressive-looking data)
Product screenshots
Show, don't tell. A screenshot of PostHog in use tells a developer more about the product than any amount of words.
Capture process
Use html2design to capture real webpages and import them directly into Figma. This makes sanitizing data much easier than working from flat image exports.
All screenshots are stored in a private Figma file (private because source data may contain PII).
Using synthetic data
Replace real customer data with synthetic data before publishing. This isn't just about privacy; it's an opportunity. The data in a screenshot gets more attention than most copy. Use it to tell a story, reinforce a use case, or leave an easter egg for the developer who looks closely. A screenshot of a session replay showing a user clicking "Upgrade" 47 times, or a funnel named "Cory's Haircut Funnel" – these land with people who actually read the interface.
Make it specific enough to feel real, interesting enough to make someone smile.
Where screenshots live in the codebase
Screenshots are referenced through product hooks so they can be pulled in consistently across the site without duplication. See session replay for an example of how they're structured.
Light and dark – always both
Every screenshot must be captured in light mode and dark mode – always at the same time, with the same data visible. The two versions are paired: the website swaps between them automatically based on the visitor's color mode preference. If you update data in one version, update the other to match. A user should be able to switch color modes and see the screenshot change color while the content stays identical.
Export everything at @2x so text is crisp.
Responsive variants
For high-traffic placements like blog posts getting heavy social promotion or articles with paid traffic – produce up to four versions of each asset where relevant:
Landscape, light mode
Landscape, dark mode
Portrait, light mode
Portrait, dark mode
The website serves the appropriate version based on screen size and color mode. Desktop visitors typically see landscape; mobile visitors see portrait. This matters because a landscape screenshot with small UI details is often unreadable at mobile sizes.
Data visualization
Charts and graphs show up throughout posthog.com – in blog posts, feature pages, and as product screenshots. They follow the same principles as everything else: clarity first, PostHog palette, no decoration that doesn't earn its place.
Design principles for charts
Less is more. Remove chart junk – unnecessary gridlines, tick marks, legends that explain what the axis already says. Every element should help someone read the chart faster.
Label directly where possible. A label on the line beats a legend the reader has to cross-reference.
One chart, one point. If a chart needs a paragraph of explanation to make sense, simplify it. If it's showing two different things, split it.
Color in charts
Use the PostHog color palette. Don't introduce new colors just for a chart. If a chart needs more colors than the core palette provides, use opacity or pattern fills before reaching for new hues. Using HSL color space ((hue, saturation, lightness)) over hex makes it easy to adjust the lightness without inadvertently adjusting the tone.
The same light/dark rule applies: if a visualization appears on posthog.com, it needs to work in both modes. This generally means using CSS variables or producing paired versions the same way you would a screenshot.
Annotations and context
A chart without context can mislead. When publishing a chart – especially in a blog post – annotate significant moments: a feature launch, a spike, a known data anomaly. Readers should understand why something happened, not just that it happened.
We run more than one community channel, and they are not interchangeable. Each one has a job. When a channel tries to do every job, it does none of them well.
Two channels, two jobs
Discord and the forum are our two homes. They work differently on purpose.
Discord is for real-time chat. Conversational and hands-on. It's where people show what they're building, react to each other, and where superfans hang out. The value is in the conversation happening at all – not in it being findable six months later.
The forum is for lasting answers. Asynchronous and searchable. A question, discussion, or article posted there keeps paying out to everyone who finds it afterwards. It should be _owned by builders_, not staffed by PostHog.
The behavior we see in each channel is channel-shaped, not user-shaped. The same person banters in Discord and writes a careful question in the forum, because that's what each space invites.
Channels we maintain but don't grow (for now)
GitHub. The public workbench – claimed and routed, not staffed. Issues get triaged to an owning team. We don't try to turn it into a discussion venue, and we're not driving community members to contribute PRs or issues right now.
Reddit. A reputation surface, not a home. We show up and reply when needed, but we don't try to move our community there.
Pull support out
Neither Discord nor the forum is a support channel, and the single most valuable thing we can do for both is stop letting support define them.
Being blocked is a support problem. It deserves a support response, and it should be routed as one rather than absorbed into whichever channel it landed in:
| What came in | Where it goes | | ------------------------------------ | --------------------------------------------- | | A bug, or something broken | Support | | A feature request | The roadmap | | Product feedback | The owning team | | A genuine question, or a discussion | Stays where it is |
This isn't about being unhelpful. It's that a space defined by blocked users never becomes a space where unblocked ones want to hang out. It's also the slowest way to get help because it's not set up for that.
Change the container, not the behavior
We don't get the community we want by asking people to behave differently. We get it by changing what the space invites. Pull, don't push.
If a page invites people to write in, they'll write in. If it invites them to search first, most of them will.
If the only thing a channel is good at is troubleshooting, troubleshooting is what it fills up with.
Prompts beat rules. A weekly "what are you working on?" thread does more than a posting guideline ever will.
Bans and grievances
Send anything community-side – a Discord ban, a moderation decision, or a complaint about how we ran a space – to community@posthog.com. It's a Gmail alias that goes to the Builder Relations and Developer Marketing teams. Anyone else who wants in can add themselves.
Don't route these to support. Support handles product and account problems, and mail to support@posthog.com gets an automated reply that tells the sender to open an in-app ticket, which a banned Discord user may not be able to do.
The standard we're enforcing is the code of conduct. Say which part of it was broken when you act on something – it makes the decision reviewable, and it's much easier to defend an appeal when the reason was written down at the time.
When you ban someone, always tell them why and how to appeal. Posting the reason in the channel before you swing the hammer is not enough – they can miss it, and then they file a support ticket or sign up again. Both of our ban flows have a place to say it:
Discord: use the reason field in the ban dialog. Choose "Other" to write a freeform reason, and include community@posthog.com for appeals. The person sees it if they try to rejoin.
A PostHog organization: the suspension reason and an appeal address show on login.
Post in #team-builder-relations so we can give you the teammate role.
Once you have the role, you'll show up as a PostHog teammate in the server.
How to show up
In Discord, be a person, not a support desk. React to things so people know they've been seen. Share what you're working on, and ask what other people are working on.
Route, don't absorb. If something belongs in support or on the roadmap, send it there rather than answering it in-channel.
What we're working on
Community channels are owned by Brittany Joiner on the . See the team's goals for what's in flight, including how we're repositioning the forum and building out triage.
We want to build a self-sustaining and scalable community of engaged users because it will enable us to own our audience in a way that third party social media platforms do not. Like brand or content, building a thriving community is a (very) long term bet, so we will need to both invest a lot of time up front and then wait to see what works and what doesn't.
Our approach to building community at PostHog differs from most devtools in two ways:
We are building our community around our _website and content_, rather than the product itself. This is because a) PostHog is a product that you add after you have already built something, and b) 90% of community activity turns into support queries, which is not what we want community to be.
We are focusing on building the community _platform_ itself - creating the tools that enable the community to interact with each other, rather than hiring a community manager whose job it is to go out and talk to everyone on other platforms/social media - this is not scalable.
We run several channels, and they each have a different job. For how we think about Discord, the forum, GitHub, and Reddit – and how to show up in them as a team member – read community channels.
Every one of those spaces is covered by our code of conduct. It applies to the PostHog team too.
Responsibility for community
The is responsible for driving our community channels and supporting community members. The built the platform and tools for our online community and reviews any changes.
Support should not be considered part of community at PostHog. Support is driven by the Customer Success team, primarily using in-app support and dedicated Slack channels. Good customer support helps build positive word of mouth, but replying to support queries is not an engaging or scalable way to build a thriving community.
Content hubs
We are in the process of building these out. We have created two hubs targeting our ICP:
Anyone can ask a question in the forums, which has become a public inbox of troubleshooting, hiring, and support posts that are better suited to contacting us.
We're working on repositioning the forum so there are more engaging discussions that anyone feels ready to jump into. Users will see these changes soon:
Nudges for posting conversational content instead of support
A layout that makes more sense as a "home" view
Better organization for discussions
Asking a question
A user can write a question, but they'll need to create a PostHog.com account before posting. (Note: This authentication system is currently separate from PostHog Cloud accounts, though we have plans to unify them.) Users can write Markdown and upload images to a question.
Once it's posted, a question permalink page is generated, and the user is automatically subscribed to reply notifications by email.
Anyone can subscribe to thread replies by clicking the bell icon in a thread (after signing in).
Answering questions
Anyone can answer, and answering community questions covers how. It's written for community members and the PostHog team alike, and includes how we expect AI to be used and where to send questions that belong somewhere else.
If you're a PostHog user, answer with your own experience. If you think something is best answered by PostHog directly, leave it and we'll take care of it.
Some community members get a moderator role on top of that, with a small set of tools for marking solutions, tagging topics, and tidying threads. See community moderator tools for what the role can do and how we hand it out.
Points & achievements
Community members can earn achievements for activities like asking questions, helping others, voting on the roadmap, and completing their profile. Each achievement awards points that can be redeemed for stickers, merch credits, and other rewards from the Points tab on their profile.
Community moderator is a role we give to a small number of trusted community members. It is not the same as the staff moderator role that PostHog team members get.
These tools work on the forum at /questions. They do not cover Discord. Discord moderation is separate and this role does not include it yet.
The job is to help uphold our code of conduct. The tools below are how you do that in practice, and the standards in that document are what you are applying when you use them.
If you are looking for how to write a good answer rather than how to moderate one, read answering community questions.
This page is the guide we send to new community moderators. owns it.
What community mods can do
| Action | Where to find it | | --- | --- | | Mark a reply as the solution, and undo it | On each reply | | Add or remove forum topics | Moderator tools panel, below the question | | Hide a reply, or make it visible again | On each reply | | Archive or restore a thread | Top of the thread | | Escalate a thread to PostHog | Moderator tools panel |
You also see things other people cannot. Hidden replies are visible to you with a note that says only moderators can see them. Treat what you find there as private.
Every action you take is recorded with your name. We review the log now and then. It is there to back you up when someone questions a decision, not to call you out.
Mark as solution
This is the most valuable thing you can do. Solutions show up in search, and they stop the next person from asking the same question.
We want the person who asked to mark their own solution. They know whether it actually solved their problem. You do not.
So the order is: nudge first, mark second. Reply and ask if that answer worked for them. Give them time to come back.
Rules for when you do mark it yourself:
Wait a few days. Do not mark a solution the same day a reply lands, and never within a few hours of it. The person who asked deserves the chance to answer first.
Only mark it if you are confident it solves the question. "Max AI said it" is not confidence. Neither is "looks good to me." If you have not read the answer closely enough to know it is right, you are not ready to mark it.
Do not mark your own reply as the solution. Ask another moderator to check it instead.
If you are unsure, ask. Post the thread in the #forum-clean-up channel in Discord, or in #team-builder-relations if you are on the PostHog team, with something like: "I think this reply answers the question and nobody has replied in a few days. Can I get a sanity check before I mark it solved?"
Forum topics
You can add and remove the topics on a thread. Use it when a thread is untagged or tagged wrong.
Tag what the question is about, not the product the person happens to use. Two or three accurate topics are better than six vague ones.
The topic list is a work in progress. We are reorganizing it, so expect it to change. If you see questions that do not fit any current topic, tell us. That feedback is more useful to us than the tagging itself.
Hide a reply
Hiding takes a reply out of public view. It does not delete it, and you can put it back.
Use it for spam, promotion, abuse, or a reply that exposes private data such as an API key or customer information.
Do not use it on a reply that is only wrong. Reply and correct it instead. A wrong answer with a correction under it helps the next reader more than a gap does.
If it is urgent, such as leaked credentials or targeted abuse, hide it first and flag it in Discord straight after.
Archive a thread
Archiving removes a thread from the forum listings and from search. It also turns off the reply box, so nobody can add to the thread again. Anyone with the original link can still read it, including the person who asked.
Archive a thread when it is spam, when it is not a real question, or when it is a duplicate.
For duplicates, reply first. Post a link to the thread that has the answer, then archive. The person who asked can still open their thread and follow your link, but they cannot reply to you once it is archived, so the link has to be there before you archive and it has to be the right one.
Only do this when you are sure. If the two threads are merely similar, or the older one is unanswered as well, leave both alone and link them in a reply instead.
Do not archive a thread because it is old or unanswered. Unanswered questions are a signal we track, not clutter.
Escalate to PostHog
This button tells PostHog to pay attention to a thread.
Use it when:
The thread looks like a real bug.
Someone needs account or billing help that only PostHog can give.
PostHog should answer directly. Things like questions about where we stand on something, or what we are doing internally. Do not speak on behalf of PostHog.
Getting the role
Ask in Discord or email community@posthog.com. We give the role to people who already answer questions well and often.
PostHog community members can earn points by completing achievements and answering questions, and redeem them for stickers, merch credits, and other rewards from the Points tab on their profile.
Image: Points tab on profile
How points work
Points come from three places: achievements, replies to questions, and one-off gifts from moderators.
Each achievement has a point value based on the time and effort we expect someone to spend earning it. For example, voting on the roadmap, updating your bio, and asking your first question are each worth a few points – enough to earn a sticker.
Moderators can also gift points for special contributions that don't fit neatly into an achievement category.
Earning points from achievements
To see available achievements and plan which to tackle next, visit the achievements page.
Every reply you post on a community question earns 1 point, up to a maximum of 5 points per day. The daily maximum keeps the reward for genuine help and prevents point farming.
Replies to your own questions don't earn points. Get a rubber duck.
Balance & transactions
Balance updates automatically when you earn achievements, post replies, or redeem rewards
Transaction history shows what you've earned, why you earned it, and any redeemed merch codes
Progress tracking shows how many points you need to reach the next reward
Redeeming points
Redemptions are completely self-serve from the Points tab on your profile.
The points store offers two types of rewards:
Products (e.g. stickers)
When you redeem a product like a sticker:
Click "Redeem" on the reward card
Confirm the redemption
A button appears letting you order it immediately
Enter your name and shipping address to complete the order
Merch credits
When you redeem a merch credit (gift card):
Click "Redeem" on the reward card
Confirm the redemption
You receive a discount code
Click "Use in store" to open the merch store with your code pre-applied
Shop for anything you'd like!
Merch codes are saved in your transaction history, so you can always find them again if needed.
---
For moderators
Gifting points
Moderators can gift points to users for contributions that don't fit into existing achievements:
Navigate to the user's profile on posthog.com
Click the gift icon (present button) in the profile header
Enter the number of points and a reason for the gift
Click "Send gift" and confirm
Monitoring redemptions
Redemptions are self-serve, but we have a Slack channel set up to monitor them while we're ironing out any kinks. This gives us visibility without requiring manual approval.
Creating achievements
See Achievements in the community profiles documentation for instructions on creating, assigning, and revoking achievements.
When a user signs up to ask a question, a community profile is created for them at /community/profiles/[id] where they can add a bio and links to social profiles.
Their profile page also aggregates any community disucssions they've participated in. (As a byproduct, this is an easy way to track down a user who primarily creates a community profile for self-promotion!)
Team members have access to special profile features, like:
a sidebar that shows which small team they're on, and their teammates
We also use data from these profiles in other areas of the site:
Company team page - automatically generated every time the website is built. (Team members need to be assigned to an internal small team in our website CMS for their profile to appear on the team page.)
Job listing pages - shows teammates you'd be working with, and the small team's verdict on whether pineapple belongs on pizza
Creating a profile for a new team member
To reduce the onboarding steps, Lottie or the can help create a profile for a new team member. To do this:
Via the PostHog website, visit the newly created profile in our website CMS
Click the newly created profile link in the right sidebar (below My profile and above Edit profile)
Click the "View in Strapi" link in the right sidebar
Now, in their profile on our website CMS, update the following, then hit Save:
companyRole *
startDate *
location * - use a string, like “London, UK”
country - use TWO-CHARACTER country code, eg: GB
avatar (can be a placeholder image until an illustration is drawn, but should be a png with a transparent background)
*This information can be found in their onboarding checklist
Update their user permissions
Under user, click their email address to be taken to their user page
Under role, change to Moderator and hit Save
Let the team member know their profile is created, and that they should add a bio!
To access their account, use the password reset option on the login form at posthog.com/questions
Uploading profile illustration (when ready)
Make sure it's uploaded on a square canvas at @2x PNG, and that the portrait fills as much of the canvas as possible. If an arm has to be clipped, set the image to be clipped on the right side so their arm on the left side of the image doesn't get cut off.
Achievements
PostHog community members can earn achievements for various activities. Each achievement awards points that can be redeemed for stickers, merch credits, and other rewards. See Points & rewards for details on the points system.
Achievements are valued based on the time we expect someone to spend earning them. For example, someone who votes on the roadmap, updates their bio, and asks their first question has earned enough points for a sticker.
Creating and editing achievements is handled in the achievement manager. Manually assigning and revoking achievements is handled in Strapi, our website CMS.
This page is for anyone answering questions on posthog.com/questions: community members, community moderators, and the PostHog team. Most of it applies to all three. The last section is internal setup that only concerns PostHog team members.
If you have the community moderator role, see community moderator tools for what those tools do and when to use them.
Who answers questions
Anyone can, and we would rather it was not always us. A forum where only PostHog employees answer is a support queue with extra steps. Answers from people who have actually run into the problem are usually better anyway.
PostHog team members should watch for questions in their product area and answer them when they can. Teams stay on top of their own areas, and can decide whether their weekly support hero handles them or whether the team watches collectively.
Answering well
Answer from your own experience. What you tried, what worked, what you would do differently. That is the thing nobody else can post.
If you do not know the answer, it is fine to say so, or to say nothing. A half-answer that sounds confident costs the next reader more time than silence.
Using AI
Use AI to find things. Do not use it to write your reply.
Searching the docs, checking the codebase, and looking something up are all fair game. Reading what you find and answering in your own words is the whole job. Pasting the output is obvious to everyone reading, and it does not help: the person asking could have done that themselves.
If you would need AI to answer it, do something else instead. Ask a follow-up question to narrow the problem down, or point them at PostHog AI in their own project. Suggest what to ask it, for example "why is this insight showing no data" or "which events is this flag matching on."
That is worth suggesting even when a thread already has an AI reply on it. The naming here is admittedly confusing: the answers that appear on threads automatically come from Inkeep, which reads our public docs, tutorials, and repos. PostHog AI in your dashboard is a different thing, connected to your project and able to look at your actual data. So an auto answer getting it wrong tells you nothing about whether PostHog AI can help, and it usually can.
Where to send people
Some questions do not belong on the forum, and saying so is more useful than answering around the edges. The full routing table is in community channels, but the two that come up most:
A feature request goes on the roadmap, where people can vote on it.
A bug, or something that might be one, goes to support. Point them at the AI assistant in their project first. It will help them work out whether it is really a bug, and if it is, it gives support the context to act on the ticket faster.
Thread resolution
We want the person who asked to mark the solution themselves, but they rarely come back to do it. and community moderators follow up when a thread has gone quiet. See mark as solution for how long to wait and when it is safe to mark it yourself.
For PostHog team members
Getting notified
Every small team should subscribe to the forum topics relevant to them, so questions get posted in your team's Slack channel.
Question alerts is where you do that. It shows which teams are subscribed to which topics, and you can add or remove your own team from any topic there. It also flags the two ways this quietly breaks: topics no team is watching, and teams subscribed to a topic without a Slack channel set. You need moderator access to open it. can help if you are stuck.
Phrasing and tone
When possible, answer as a person rather than as the company. We would rather the forum did not read as a place where only PostHog employees respond.
Instead of... _"We are launching a new feature that will solve this – here's the pull request."_
Try... _"There's a pull request out for this feature now."_
Questions worth turning into something else
If an answer belongs in the docs, you can update the docs directly, tag the question Internal: documentation for the Website & Docs team to triage, or open an issue in posthog/posthog.com with the technical documentation label. If it is worth a tutorial, tag it Internal: tutorial idea.
If a question is better off as a private support ticket, ask them to open one in the app, or create one for them and reply to say you have. Archive the thread afterwards. Note that free users may not be able to message support in-app, so check who you are talking to before pointing them there.
Extra context on the asker
Staff moderators see a panel below the question with the name and email of the person who asked, and a link to their record in PostHog Cloud. If you are not a moderator yet, create an account and ask your team lead to add you to your small team's page. You will be upgraded automatically.
Use our Trust Center powered by SafeBase to self-serve reports, policies, and certifications.
PostHog is certified as SOC 2 Type 2 compliant, following an external audit.
Our latest security report is publicly available (covering controls as of May 31, 2026). Our reporting period runs from June 1st through May 31st each year.
Policies
We have a number of policies in place to support SOC 2 compliance. All team members have been invited to Drata to review these and to complete security training and background checks as part of onboarding.
All of our policies are available for viewing and upon request via our Trust Center.
There needs to be a very significant upside to introducing a new piece of software to outweigh its cost.
This is our mechanism for making decisions where we need to assess the cost of introducing a new piece of software.
It is inspired by this post on "fad resilience" from Slack. We want to be able to introduce new tools and services, without introducing overlapping tools and unnecessary complexity.
What makes us fad resilient is that you are free (and encouraged) to try new things. But by introducing new things, you become responsible for rolling them out. And for replacing anything they make obsolete.
What is it not?
This doesn't apply to making "cheap decisions". A cheap decision is one that can be easily completed or reversed, or one that only affects your work not other people's. For those types of decisions you should continue to follow the guidance in the the software section of our spending money page. This is about the adoption of new company-wide tools, or implementation of vendors that are going to be used in the PostHog product.
How does it work?
If you find yourself saying something like:
"we should use Notion, not Google Docs"
or "(Haskell|Rust|Chicken) would be a better programming language for us"
Then you need to do the following:
1. Try the tool in a low-risk context
Use the tool in a context where it is easily replaced and does not involve sensitive data. If you have doubts about what information can be shared at this stage, check with #legal first. Similar to a spike.
The goal is to:
Check whether the tool works as well as you expect
At the same time open an issue describing why we should adopt the tool. Anyone proposing a new vendor should think about the impact on the whole company, not just their team or use case.
You should carefully be thinking about and your proposal should consider the types of things described below:
What to think about?
Problem and motivation
Why should we introduce this tool now? What problem does it solve?
How large is the benefit vs. the status quo? Is this solving a real issue or just something interesting to try?
What existing tools or processes would it replace?
Could this be solved using an existing tool or by building something directly in PostHog?
Trial/Proof of concept
Have you tested the tool in a small, reversible context (spike or sandbox)?
Can it be evaluated without sending real data?
What did you learn from the trial?
Data exposure and privacy
What type of data would be sent to the tool/vendor and does the benefit justify that risk?
From least to most sensitive:
General data – publicly accessible information
Business data – internal PostHog data without customer data
Customer data – customer PII (name, email, address, IP addresses, etc.)
Customer’s customers’ data – end-user PII
Also consider:
Where will the data be stored or processed? (significant preference toward EU/US as these jurisdictions are lower risk, well vetted, and have robust privacy frameworks)
Can we avoid sending customer or end-user PII?
Can data be aggregated, redacted or irreversibly anonymized before leaving our systems?
Vendor due diligence
Where is the company that provides the proposed tool headquartered and where do they operate?
Who are their customers? How long have they been around?
Do they demonstrate a credible security posture (SOC2, GDPR, HIPAA, etc.)?
Are they a well-established tool in the industry, or something experimental and less well known?
Alternatives and competition
Why this tool instead of competitors?
What other credible options exist and how do they compare (cost, security, reputation, risk)?
What are other companies in our space using? Checking their list of subprocessors is a good place to start.
Internal impact
Have other engineers been consulted about technical impact or prior experience?
Are relevant teams supportive of introducing this tool?
Has security/infra reviewed the vendor and given their thoughts on their security posture?
Has legal chimed in and given their thoughts on risks? Is this tool going to qualify as a subprocessor such that customers will need to be aware we’re sending them data?
Would using this tool impact how sales pitches the PostHog product to potential customers?
Does this change anything about how we need to communicate with existing customers (marketing/support)?
Customer defensibility
If a customer asked why we use this tool/vendor and send data to them, could we clearly and transparently justify the decision?
Would customers that fit our ideal customer profile view this as a standard and responsible choice?
How would enterprise-level customers react to this decision if we were selling PostHog to them?
These are guidelines, not a rigid checklist. The goal is for everyone to be thinking about the overall impact of introducing a new tool, and to allow for a holistic review of the risks against the benefits.
Many proposals will not make it past this stage – that's good. We don't want a stack that changes constantly, but we also don't want one that never improves.
After a decision is made: Review process
Once a decision has been made to adopt a tool/vendor, the person proposing the tool is responsible for coordinating the next steps.
1. Finalize business terms
Work with the vendor to negotiate the commercial and business terms, such as:
Cost
Number of licenses or usage terms and limits
Contract length
Any implementation or onboarding details
Once the business terms are mostly settled, the vendor’s documents will need to go through legal review before anything is signed.
Typically, these includes:
Master Services Agreement – the primary contract governing the relationship.
Data Processing Agreement – required if the vendor processes personal data.
Security/compliance documentation – e.g. SOC 2, ISO certifications, or similar.
As soon as it looks like we intend to move forward with the vendor, post in #legal, and give a heads-up that:
A decision has been made to use the vendor.
Business terms are being negotiated.
Contract documents will be shared for review shortly.
As much context you can provide as possible to aid in the review.
As soon as documents are available for review, send the documents to #legal (in an editable format such as .docx).
2. Plan time for legal review
Legal review usually takes a few business days depending on bandwidth, priorities, and existing obligations, and negotiations may take longer depending on the use case, the vendor’s contract terms and how quickly they review and negotiate proposed changes.
Plan accordingly and involve legal early. If you have a deadline for implementing the tool or there is another reason the standard timeline above needs to be expedited, please make sure to let legal know ahead of time.
3. Additional requirements for Subprocessors
If a vendor qualifies as a subprocessor, the review process will usually be more involved.
Generally speaking, a subprocessor is a vendor or tool that is going to be used to processes customer or end-user data as fundamental part of the PostHog product or infrastructure. For example, infrastructure providers (like cloud hosting) or services that process production data are clearly subprocessors.
Many internal tools used for productivity or operations (for example, documentation and productivity tools) are not necessarily subprocessors.
As a rule of thumb, any vendor that needs to have access to customer end-user data in order for a part of the PostHog product to function should raise alarm bells, but if you are unsure whether a tool/vendor qualifies as a subprocessor, always check with #legal early.
For new subprocessors:
Customers must receive 14 days’ notice after the agreement is finalized before the vendor can be used in production.
Because of this requirement, and because the legal and compliance documents for a subprocessor are generally going to be reviewed with careful detail, implementations involving new subprocessors will likely take additional time.
4. Using the tool
Once:
Legal review is complete.
Contract documents are finalized and signed.
Any required subprocessor notice period has passed.
With team members across many countries, it's important for us to practice clear communication in ways that help us stay connected and work more efficiently.
To accomplish this, we use asynchronous communication as a starting point and stay as open and transparent as we can by communicating on GitHub through public issues and pull requests, as well as in our PostHog User and internal Slack.
Our communication values
Assume positive intent. Always coming from a position of positivity and grace.
Form an opinion. We live in different locations and often have very different perspectives. We want to know your thoughts, opinions, and feelings on things.
Feedback is essential. Help everyone up their game in a direct but constructive way.
Discussion in GitHub issues or pull requests is preferred over everything else. If you need a response urgently, you can Slack someone with a link to your comment on an issue or pull request, asking them to respond there. However, be aware that they still may not see it straight away (and that's OK in our book). That said, casual conversations in Slack are completely normal — it’s our main space for day-to-day communication.
You are not expected to be available all the time. There is no expectation to respond to messages outside of your planned working hours.
It is 100% OK to ask as many questions as you have - please ask in public channels! If someone sends you a handbook link, that means they are proud that we have the answer documented - they don't mean that you should have found that yourself or that this is the complete answer. If the answer to a question isn't documented yet please immediately make a pull request to add it to the handbook in a place you have looked for it.
When someone asks for something, reply back with a deadline or by noting that you already did it. Answers like: 'will do', 'OK', or 'it is on my todo list' are not helpful. If it is a small task for you but will unblock someone else, consider spending a few minutes to do the task so the other person can move forward.
By default, avoid creating private groups for internal discussions.
Public by default
We make things public by default because transparency is core to our culture. The kinds of information we share falls into one of three buckets:
_Public_ - most things, including our product, roadmap, handbook and strategy.
_Shared internally_ - almost everything else, such as financial performance, security, fundraising and recruitment.
_Private internally_ - personal team information, i.e. compensation, disciplinary issues.
Information that is not publicly shared is in areas with complex signals that can impact our ability to sell, raise money or are inappropriate to share more widely for personal privacy reasons.
We have two repos to centralize and document private internal communication. These are the source of truth for any internal information, and anything that should be written down (as established in these guidelines) should live in these repos or (better) in this Handbook, not on Slack. This will make it easier when having to search for older stuff, sharing context between public and internal repos, and for newcomers to have all information they might need readily available.
Company Internal
Repository can be found in https://github.com/PostHog/company-internal
Documents any company-wide information that can't be shared publicly within People, Ops, Legal, Finance or Strategy.
Examples of information that should go here:
✅ Hiring plans and discussions _before_ we post a job ad
✅ People discussions, e.g. benefits, pensions, share options, org structure
✅ Onboarding/offboarding checklists
✅ Non-engineering team sprint planning (as these will often be a mix of public and private tasks and we don't want to restrict people)
✅ [Sometimes] Discussions about replacing or adding tools, services, and systems that we use
For company-related issues that _can_ be discussed publicly, these should go in the meta repo which can be found in https://github.com/PostHog/meta/
Examples of information that should NOT go here:
❌ Any information that should be public (see guidelines on public by default), this should go in the public repositories (posthog, posthog.com, meta, ...). Things like:
Some marketing campaigns where it doesn't matter if our competitors see it; retros after campaigns
Offsite planning and retros
Discussions about future positioning and strategy that will end up in the Handbook anyway
Discussions about tools where there isn't a security risk and it interfaces with our customers (e.g. marketing, customer support)
Generally anything that will end up in the Handbook anyway, including culture and values discussions
❌ Bug reports, security issues, or any other engineering-related discussions. These should go in the Product Internal repo.
❌ Billing issues, product or growth discussions. These should go in the Product Internal repo.
Product Internal
Repository can be found in https://github.com/PostHog/product-internal
Contains internal information related to the PostHog product. Documents any non-public information (as established in these guidelines) that specifically relates to engineering, product, growth or design.
This repository was introduced to aid maintenance and day-to-day usage of internal repositories. Having these discussions together with the company-wide information proved unwieldy. More context on this decision.
Please be sure to read the README of the repo for guidelines on how to file specific issues.
Examples of information that should go here:
✅ Vulnerabilities (security bugs) reports
✅ Bug reports where most of the context of the report depends on customer's PII. _Some bug reports require screenshots, recordings, or some other information that contains PII and as such can't be public._
✅ Post-mortems on outages, or other issues affecting a large portion of customers. The results of these should usually be made public though.
✅ Documentation of internal infrastructure, where if it was public knowledge could provide valuable information to an attacker.
✅ Experiment (A/B testing) results.
✅ Product or growth strategy discussions (unless they should be public).
✅ Interview exercises or questions for engineering, product, growth or design tasks that should not be public.
✅ Documentation of engineering or product requirements documents that can't be public (these should be quite rare).
✅ Billing or pricing-related discussions that is not yet public.
Examples of information that should NOT go here:
❌ Any information that should be public (see guidelines on public by default), this should go in the public repositories (posthog, posthog.com, meta, ...).
❌ Any internal information that does not fall under the scope of purely engineering, product, growth or design. This should go in the Company Internal repo if private or meta if public.
❌ Bug reports that don't contain any PII or where the PII only contains supporting information. In this case, file the bug under the relevant public repo and add a protected link to the additional information (e.g. a private Slack link, or a link to this repo).
Written communication
GitHub
Everything starts with a pull request
It's best practice to start a discussion where possible with a Pull Request (PR) instead of an issue. A PR is associated with a specific change that is proposed and transparent for everyone to review and openly discuss. The nature of PRs facilitate discussions around a proposed solution to a problem that is actionable. A PR is actionable, while an issue will inevitably lead to a longer period before the problem is addressed.
Always open a PR for things you are suggesting and/or proposing. Whether something is not working right or we are iterating on new internal process, it is worth opening a pull request with the minimal viable change instead of opening an issue encouraging open feedback on the problem without proposing any specific change directly. Remember, a PR also invites discussion, but it's specific to the proposed change, which facilitates focused decisions.
By default, pull requests are non-confidential. However, for things that are not public please open a confidential issue with suggestions to specific changes that you are proposing. When possible, consider not including sensitive information so the wider community can contribute.
Not every solution will solve the problem at hand. Keep discussions focused by _defining the problem first_ and _explaining your rationale_ behind the Minimal Viable Change (MVC) proposed in the PR. Have a bias for action and don't aim for consensus - some improvement is better than none.
Issues
GitHub Issues are useful when there isn't a specific code or document change that is being proposed or needed. For example, you may want to start an issue for tracking progress or for project management purposes that do not pertain to code commits. This can be particularly useful when tracking team tasks and creating issue boards.
However, it is still important to maintain focus when opening issues by defining a single specific topic of discussion as well as defining the desired outcome that would result in the resolution of the issue. The point is to not keep issues open-ended and to prevent issues from going stale due to lack of resolution. For example, a team member may open an issue to track the progress of a blog post with associated to-do items that need to be completed by a certain date (e.g. first draft, peer review, publish). Once the specific items are completed, the issue can successfully be closed.
Note: If you're new to using GitHub, check out this handy primer - it's specific to how we use GitHub at PostHog. You'll learn the key concepts and how to manage notifications. It's important, as this is where the bulk of our company-wide communication happens. (Think of GitHub notifications as a replacement for your work email.)
Keeping on top of reviews, issues and notifications
Keeping track of everything that's happening in GitHub can be daunting, but it's important to make sure your team receives reviews and feedback on a timely manner.
To keep on top of this, we suggest going through issues where you've been mentioned regularly. Some tricks which can help are:
This will send you a slack notification when someone mentions you in a PR or issue. You can also get periodic reminders for PRs that you've been requested to review.
(Highly recommended) Join the #github-rfcs channel on Slack. This is where we post all the RFCs.
To search all code, PRs and issues ever written at PostHog you can search everything in the PostHog organization on Github. To do that can go to github.com/posthog and search in the top left corner.
For extra convenience, you can also add this search as a 'search engine' in Chrome. That way you can type in ph <tab> and instantly find anything. To do that, follow these steps:
Hit command + , in your browser
Type search, find "manage search engines"
Click "add" next to "other search engines"
For "Search engine" type in github posthog organization
For "keyword" type in ph
For "url" copy in https://github.com/search?q=org%3Aposthog+%s&type=issues
You can now type ph + tab into your browser and search issues directly
Slack
Slack is used for more informal communication, or where it doesn't make sense to create an issue or pull request. Use your judgment to determine the appropriate channel, and whether you should be chatting publicly (default) or privately.
Also keep in mind that, as an open source platform, PostHog has contributors who don't have access to Slack. Having too much context in a private location can be detrimental to those who are trying to understand the rationale for a certain decision.
Slack canvasses are useful for storing information like schedules, bookmarks, personal to-do lists, scratch notes etc. However, things like quarterly goals, runbooks, sprint plans, FAQs etc. should live in the Handbook, Docs, or in a GitHub RFC or Issue by default. If you find yourself documenting something useful in Slack, it's much better to put it in GitHub instead and link to it from Slack so that PostHog AI can include it in future search results. Slack canvasses are terrible for searchability!
Slack recap is a great way to learn from others by adding channels like #ask-max and #today-i-learned to the recap. You can also use it to keep tabs on teams you may not directly work on, but still want to know what's being discussed.
Slackbot is a handy AI agent that can search across the PostHog workspace in Slack to help answer your questions. If you're looking for information or trying to find a past conversation, Slackbot is a great place to start.
Keeping up with what we ship
We recommend everyone at PostHog joins #changelog to stay current on what's shipped. It's owned by the Wizard & Docs team and updates constantly as PRs merge.
The channel is powered by agentic workflows that scan merged PRs and feature flag changes and summarize them into it. PR authors can opt in or out manually via the Publish to changelog? checkbox on the posthog/posthog PR template, or via the @posthog Slack app. See how to publish changelog for more detail.
Slack etiquette
Slack is used differently in different organizations. Here are some guidelines for how we use Slack at PostHog:
Keep #general open for company-wide announcements.
@channel or @here mentions should be reserved for urgent or time-sensitive posts that require immediate attention by everyone in the channel. (Examples: changing a meeting invite URL just before a meeting, or soliciting urgent help for a service disruption, where you're not sure who is immediately available)
Make use of threads when responding to a post. This allows informal discussion to take place without notifications being sent to everyone in the channel on every reply.
When possible, summarize multiple thoughts into a single message instead of sending multiple messages sequentially.
You don't need to tell people if you're away from your computer, especially on no-meeting days. There's no general expectation people are available to reply to messages in real time, including in Slack.
Keep your Slack profile up to date with the right information, including the appropriate name eg with surname or surname initial if you share a name with a colleauge.
Channel naming conventions so people don't get confused:
#team-[team-name] - small team channels, only as listed on the teams page
#project-[project-name] - one-off initiatives that may involve people across multiple teams, but don't fit neatly into a team channel
#posthog-[customer-name] - shared channels with _customers_ only (if you want to create a shared channel with an external partner, use #[partner-name]-posthog instead)
#alerts-[team-name] - useful to create a separate channel for your team to send alerts into, so your main channel doesn't get noisy
#support-[product-name] - similarly, useful to feed support requests in if helpful without adding clutter
#offsite-[team]-[month]-[year]-[where] - For planning and coordination of team offsite events
#onboarding-[who]-[team]-[month]-[year]-[where] - For coordinating and supporting new team member onboarding
#hiring-[team-name] - For recruiting discussions, candidate feedback, and hiring coordination for a specific team
#superday-[first-name]-[role] - For candidate interview coordination and feedback during intensive interview days
On the very rare occasions you need to create a private channel for some reason - most commonly hiring-related - then it's probably worth sticking #private-xxxxx in front so people don't accidentally add external parties who shouldn't be in there.
Google Docs and Slides
Never use a Google Doc / Slides for something non-confidential that has to end up on the website or this handbook. Work on these edits via commits to a pull request. Then link to the pull request or diff to present the change to people. This prevents a duplication of effort and/or an out of date handbook.
We mainly use Google Docs to capture internal information like meeting notes or to share company updates and metrics. We always make the doc accessible so you can comment and ask questions.
Please avoid using presentations for internal use. They are a poor substitute for a discussion on an issue. They lack the depth, and don't add enough context to enable asynchronous work.
When giving a talk which requires a presentation, use Pitch to build your slides. (It offers more control over design than Google Slides.) They also have a desktop app. We don't (yet) have templates configured, but you can draw from existing slides in other presentations - just copy/paste into your own presentation and modify accordingly. If you'd like assistance with slide design (or using Pitch), ask in the #team-graphics Slack channel.
James (H) is an admin on the Pitch account. Because Pitch charges per seat, we remove users who only need periodic access but can easily re-add when needed.
Email
Internal email should be avoided in nearly all cases. Use GitHub for feature / product discussion, use Slack if you cannot use GitHub, and use Google Docs for anything else.
The only uses we have for internal email are:
Obtaining approvals for legal things
Sending some types of more official company documents (e.g. job offers, payroll forms)
Communicating with external partners
Writing style
We use American English as the standard written language in our public-facing comms, including this handbook. This extends to date formats (September 4, 2021) and defaulting pricing to the US Dollar ($42).
Do not use acronyms when you can avoid them. Acronyms have the effect of excluding people from the conversation if they are not familiar with a particular term.
Common terms can be abbreviated without periods unless absolutely necessary, as it's more friendly to read on a screen. (Ex: _USA_ instead of _U.S.A._, or _vs_ over _vs._)
Do not create links like "here" or "click here". All links should have relevant anchor text that describes what they link to. Using meaningful links is important to both search engine crawlers (SEO) and people with accessibility issues.
We use sentence case for titles.
When writing numbers in the thousands to the billions, it's acceptable to abbreviate them (like 10M or 100B - capital letter, no space). If you write out the full number, use commas (like 15,000,000).
Requests for comment (RFCs)
We use RFCs to communicate and gather feedback on a decision. RFCs are useful because they help us stay transparent, and the process of writing them forces you to clearly articulate your thoughts in a structured way.
Here are the steps for an RFC:
Identify a problem and a decision to be made
Create an RFC as a pull request using one of the RFC templates.
Using a template isn't a requirement, though it is a helpful and recommended starting place if you haven't written many RFCs here before. You can also get inspiration from other RFCs, as many have different sections and styles depending on the type of thing being discussed.
Share the RFC:
Assign people whom this RFC will impact, or who may have good opinions on the topic, as reviews to the pull request.
Post in the relevant Slack channel (normally the teams slack channel, or #tell-posthog-anything if it's a bigger cross-team RFC)
The aim is not to get one person to mark the RFC as approved, but to get the right people involved and commenting. It's a request for _comments_ not a request for _approval_. That means you might need to chase them to make sure it happens - tag the people, present at all hands, use offsites or other sync time - it's your responsibility to nudge the relevant people for their input
If an RFC is cross-team and is causing a large amount of disagreement, it might be worth having a sync meeting to reach a decision
Once a decision is made, include the decision in the pull request, merge it in and share this in the relevant channel and #github-rfcs again.
When does it work best to write an RFC?
Writing an RFC may be helpful when any of the following is true:
You want to clarify something for yourself or it affects just one team
It is a relatively non controversial change/idea that doesn't require much extra context. In other words, it doesn't create problems for another team.
It will be a large amount of work (more than 2-3 weeks of people's time)
It's a major new feature, change to the product, or change to the company
It will have a major customer impact
When does a meeting / another approach work better than an RFC?
An RFC is likely to be unhelpful as a first step in other circumstances. Specifically, when you want to ship or suggest a change to something that significantly affects teams outside your own. In this instance, we've seen that RFCS can lead to 10 to 25+ comments, which feels antagonistic (teams having to explain all the context around their strategy down to why this decision is something they perhaps disagree with), and creates a lot of work. A single call in this instance is likely much faster than lots of frustrated people in 1/1s talking about it _and_ the energy/time needed to respond to everything in a long thread.
_However_ please write notes on such a call - to ensure everyone _is_ on the same page. This could then be copy pasted into an RFC for transparency's sake / future reference.
How should I use AI when writing RFCs?
RFCs are the place where we do concentrated, original thinking. This thinking should not be outsourced to AI. Even when given context, AI writes content that is average and unoriginal, difficult to read (adjective-stuffing, anyone?), and places emphasis on the wrong things. RFCs should be largely hand-written, especially sections that define the problem, potential solutions, and question/answer.
AI is still useful in the RFC process, however. Feel free to use AI for research and final draft polish (but please don't have it rewrite the whole thing for you). Analysis and research done by AI can be included in the RFC at the bottom as appendixes.
Top tips for RFCs
RFCs can be very short and are often better than making decisions by Slack threads.
You don't need to have a long decision-making time - 2 days is fine for smaller changes if you receive the relevant input and are confident in your decision.
You don't need to reach full agreement to decide, particularly if the decision is reversible. Instead, it should be when the decision maker has considered the feedback and is confident in their decision.
Double-check whether your input will be useful or add noise. Or wait for the people closest to first discuss the problem. At PostHog, we don't make decisions by committee - instead we have great people divide and conquer. This particularly applies to the controversial areas such as pricing.
As the decision maker, you should use your judgment as to which comments you want to respond fully to. It's fine to politely decline a question if you think it's not required for the decision being made.
If you're introducing new technologies, you'll likely want to tag someone from Team Infrastructure.
You don't need to wait until the date you've said to make the decision if you've already consulted with the key people.
Make it easy for others to give feedback, e.g. if you only need input from someone on the Infra team about adding websockets then say that, rather than leaving it for them to work out
Write your RFC with the busy reader in mind. For example, if there is a lot of technical context to give, write a summary that people can read through quickly to get a high level overview of the proposed changes, then go deeper below, or in appendices.
It's fine to nudge people on slack if they are being slow to give feedback
Internal meetings
PostHog uses Google Meet for video communications. For large meetings, use CMD + minus key to zoom out and see everyone - you'll usually need to do this in All Hands.
Use video calls if you find yourself going back and forth in an issue/via email or over chat. Sometimes it is still more valuable to have a 40+ message conversation via chat as it improves transparency, is easy to refer back to, and is friendlier to newcomers getting up to speed.
Most scheduled meetings should have a Google Doc linked or a relevant GitHub issue. This contains an agenda, including any preparation materials.
Please click 'Guests can modify event' so people can update the time in the calendar instead of having to reach out via other channels. You can configure this to be checked by default under Event Settings.
Try to have your video on at all times because it's much more engaging for participants. Having pets, children, significant others, friends, and family visible during video chats is encouraged - please introduce them!
As a remote company we are always striving to have the highest fidelity, collaborative conversations. Use of a headset with a microphone, is strongly recommended - use your company card if you need.
Always advise participants to mute their mics if there is unnecessary background noise to ensure the speaker is able to be heard by all attendees.
You should take notes of the points and to-dos during the meeting. Being able to structure conclusions and follow-up actions in real time makes a video call more effective than an in-person meeting. If it is important enough to schedule a meeting, it is important enough to have taken notes.
We start on time and do not wait for people. People are expected to join no later than the scheduled minute of the meeting, and we don't spend time bringing latecomers up to speed.
It can feel rude in video calls to interrupt people. This is because the latency causes you to talk over the speaker for longer than during an in-person meeting. You should not be discouraged by this, as the questions and context provided by interruptions are valuable.
We end on the scheduled time. Again, it might feel rude to end a meeting, but you're actually allowing all attendees to be on time for their next meeting.
It is unusual to smoke or vape in an open office, and the same goes for video calls - please don't do this out of respect for others on the call.
For external meetings, the above is also helpful.
Indicating availability
Put your planned away time including holidays, vacation, travel time, and other leave in your own calendar.
Set your working hours in your Google Calendar - you can do this under _Settings_ > _Working Hours_. This is helpful as we work across different timezones.
Google Calendar
We recommend you set your Google Calendar access permissions to 'Make available for PostHog - See all event details'. Consider marking the following appointments as 'Private':
Personal appointments
Particularly confidential & sensitive meetings with third-parties outside of PostHog
1-1 performance or evaluation meetings
Meetings on organizational changes
Calendly
We use Calendly for scheduling external meetings, such as demos or product feedback calls. If you need an account, ask Simon in #sales to invite you to the PostHog team account.
Communication Methods
PostHog employees are frequent targets of scams and phishing. Expect all communication to occur over Slack. Phone calls, SMS, and WhatsApp are never used for initiating requests, approvals, or asking for sensitive info. With few exceptions, email is never used for this either.
If someone contacts you outside of Slack, treat it as untrusted until verified. Message them on Slack to confirm, and only continue the conversation over Slack. Other communication methods are susceptible to phishing, but our Slack instance is locked down and generally well protected from phishing and impersonation.
Best practices
James, Tim, and other execs will never ask for wire transfers, gift cards, MFA codes, or access changes over email/SMS/WhatsApp/phone. Treat such requests as phishing and report them to #phishing-attempts.
By email: Only trust @posthog.com senders. Verify via the company directory. Be cautious of look-alike domains (e.g., posthog.co vs posthog.com), unexpected attachments, and “urgent” requests.
Phone/SMS/WhatsApp: Never used for initiating requests, approvals, or asking for sensitive info.
If something feels off, it probably is. When in doubt, slow down and verify in Slack.
It encourages thoughtful, and intentional, written communication
It creates space for lots of uninterrupted work.
We judge performance based on real outcomes, not hours spent in an office.
In addition to all the equipment you'll need, your monthly User Limit covers things like coworking space or coffee shop expenses. There's no fixed travel budget either - you can use the same limit for ad-hoc meetups.
As the builders of an open-source product, we believe it is only right that we be as transparent as possible as a company.
This isn't just a meaningless corporate statement. Most of our communication happens publicly on GitHub, our roadmap is open for anyone to see, and our open-source handbook explains everything from how we hire and pay team members to how we email investors!
Almost everything we do is open for anyone else to edit. This includes things like the contents of this very Handbook. Anyone can give direct feedback on work they think could be improved, which helps increase our responsiveness to the community.
We're committed to much more than just public code.
We write everything down
We're an all-remote company that allows people to work from almost anywhere in the world. With team members across many countries, it's important for us to practice clear communication in ways that help us stay connected and work more efficiently.
It creates clear and deep thought.
We have an open core business model. This helps the community understand our decision-making.
It is usually clearer than a conversation, so everyone can row in the same direction.
It is very leveraged as we grow a large community and look to hire people around the world.
To accomplish this, we use asynchronous communication as a starting point and stay as open and transparent as we can by communicating through public issues, pull requests, and (minimally) Slack.
Putting things in writing helps us clarify our own ideas, as well as allow others to provide better feedback. It has been key to our development and growth.
We give direct feedback early and often
Everyone should help everyone else raise their game. After completing difficult work, fatigue tends to set in. It is challenging to maintain objective views of the quality of your own work when you are fatigued. It's easier for outsiders with fresh eyes and energy to raise the level of others around them.
We are direct about the quality of work. That doesn't always mean work needs to be completely polished, as it depends on the speed and impact of a task. Being great at giving and receiving feedback is a key part of our culture.
We bias for action
If given a choice, go live. If you can't go live, reduce the task size so you can.
We are small, and can only win based on speed and agility.
Going live forces a level of completion, on which you can build.
Default to _not_ asking for permission to do something if you are acting in the best interests of PostHog. It is ok to ask for more context though.
We're on the maker's schedule
We're big believers in the importance of the maker's schedule. If we have meetings at all, we'll cluster them around any stand-ups, so our day doesn't get split up.
Image: Screenshot of an engineer's calendar at PostHog
On Tuesdays and Thursdays, we don't have internal meetings at all. Occasionally an external meeting will slip in on those days, such as interviews, but we try to keep those to an absolute minimum.
We're structured for speed and autonomy
Hiring high-performing and self-sufficient team members means we don't need the typical corporate processes that are designed to slow teams down. Instead, we're organized into small teams, which prioritize speed by delegating decision-making autonomy as much as possible.
Our management approach is super simple – small teams report to their team leader, and each of the team leaders reports to one of our execs. We don't want to create a fancy hierarchy of titles, as we believe this can lead, whether consciously or not, to people feeling less empowered to make changes and step on toes, especially if they are not in a 'senior' role.
It's up to you how to get things done. If you want to make a change, feel free to just create the pull request. If you want to discuss something more widely for a bigger piece of work, it might make sense to use an RFC for a change inside your team.
If your RFC could significantly impact other teams as well, it usually works best to book a call with them as well as it usually saves time – "fewer meetings" doesn't mean "no meetings", just that they should be meaningful and intentional, not routine.
Read How you can help to understand how you can contribute to this culture.
For some (all?) at PostHog, do more weird isn't just a benign corporate value - it's a way of life. A craft, to be honed. This page will help you navigate do more weird at PostHog so that you too may do... weird things.
What do more weird is
PostHog's competition for attention is not with other boring B2B SaaS companies - it's with the internet as a whole. Memes. TikTok. HackerNews. We bring a consumer mindset to a B2B context.
Things to bear in mind:
It's a numbers game. Expect 95% ideas to go nowhere. And if you try them, only some will really take off. That's ok!
We're trying to drive overall awareness of PostHog as a brand with the people we care about, aka _product engineers at high growth companies_. We are not trying to get people to sign up to PostHog.
Be genuinely entertaining - create something that you would enthusiastically share with friends.
Weird ideas are fragile, so the most important feedback you can give if you see a weird idea is 'do I think this is a good idea' not 'can we do it'.
Weirdness isn't _purely_ vibes based - it has to be good and vaguely relevant to our users.
Some of the pitfalls we've learned to avoid:
_Corporate try hard_ - aka 'how do you do fellow kids' energy. We know it when we see it. If you wouldn't genuinely enjoy and enthusiastically recommend it to your friends, our audience won't either.
_"Marketing/Website team do some work"_ - it's fine if you have an idea that you want someone else to execute, but others teams are busy (and have a bunch of weird ideas of their own).
_In jokes_ - the thing has to be weird/entertaining/funny to people who don't work at PostHog. Describe the thing to a friend/partner/stranger - do they chuckle?
_Spending money for the sake of it_ - we are willing to spend money on weird, but just spending money and then doing nothing doesn't work. There needs to be follow through.
Weirdness is relative
Sometimes the thing just isn't _that_ weird, but that may still be ok depending on the context. For example, transparent pricing is weird in the context of how we bill customers, but it wouldn't make sense to do something truly weird like bartering grain for PostHog credit or something.
On the other hand, the bar for weirdness in a marketing campaign is extremely high, because the world is full of marketing teams trying to do the same thing. A wry smile in response to the idea will not cut it.
Got a weird idea?
Depending on the idea, you have a couple of options:
Just do it. Usually best for things you can ship yourself - you're the driver after all. We have a budget
Post it in #do-more-weird and see if others want to get involved.
Whether it goes well or not, post the results in #do-more-weird so we can learn from it.
Making bigger weird happen
Sometimes weird ideas take a lot of money and/or people's time. We have a monthly do more weird marketing budget that we can put towards such things. Lottie and Charles, together with the Council of Weird, meet monthly to pull from the frozen locker of weird things to see what we want to invest in next.
As we continue to grow, it can be hard to figure out who is the owner of something at PostHog. This is especially difficult if you are new to the team and don’t have a lot of historic context.
There are also some things that don’t have an owner at all, so we've created a simple process to deal with these that you might find helpful. Ideally, we want the default assumption to be to _not_ a) hire a new person, or b) escalate to James/Tim.
Figuring out who owns a thing at PostHog
An owner can be a single person, or a small team - either is fine. There are several places you can figure out who owns something at PostHog:
If you spot anything out of date or not obviously clear, please raise a PR!
Figuring out a new owner for a thing we’ve identified
First, raise that it doesn’t have an owner however you want. For example, you might add ‘Settings page’ to the Feature Ownership table but without an owner, then flag the PR in Slack.
Ideally someone just puts their hand up and says ‘I’ll do it’. This can be for a fixed period, until something happens (e.g. new hire joins, X months elapse), or indefinitely.
If no one puts their hand up because it’s tricky/not obvious/everyone is super busy, the relevant people that touch the thing should decide between them. These may be team leads, but not necessarily.
To make it feel less like ‘this is your job forever now’ you could say ‘X will be the owner of this thing for Y period, after which Z should happen.’
If you can’t work it out between team members/leads, ask a relevant person in Exec who can help be tiebreaker.
If you/your team becomes the owner in a _temporary_ way, part of your job as owner is to figure out the long term plan for the thing.
If you’re struggling to figure out how to prioritize the new thing vs. other work, ask your team/manager for advice.
Generally, we will keep hiring people who have an ownership mentality and are willing to put their hand up when they see a thing with no clear owner. This is better than PostHog asking people to do it, which should be a last resort.
We plan objectives every quarter. The set the direction and overall objectives for PostHog, and then small teams set their own objectives that feed into these. Longer-term planning that the Blitzscale team does is covered separately in the annual planning guide.
How quarterly planning works
~3 weeks before the end of each quarter, the Blitzscale team meets to come up with larger goals for the company, which sometimes (but not always) trickle down to individual teams.
~2 weeks before the end of the quarter, team leads should schedule planning meetings to go through these - these will be run by the team lead and include the relevant Blitzscale team member, following the template below. Each small team can change or propose alternate objectives, goals, and/or key results (we are not prescriptive about the exact terms used here - use these as a starting point).
After the planning meeting, the team lead creates a PR on their small team page with the new goals. Make sure you tag the relevant member of the Blitzscale team for review at a minimum.
Goal PRs need to be merged before the next quarter starts. We usually then run through the objectives in the first all hands of the next quarter.
In terms of accountability, Scott Lewis will notify all the small teams and make sure that the quarterly meetings happen (and that each small team has a PR), but he will not schedule the meetings for you.
If you prep properly (see below), planning meetings should take 1 hour max. The meeting is not the end of the process - you may still have some back and forth on the PR, but the meeting should give the team lead enough info to write a good PR.
Planning template
Teams should fill in the previous quarter reflection async in the doc before the meeting starts. HOGS should be written privately and independently, in your own notes rather than the shared doc, then pasted in at the start of the session. Doing them privately first stops people from being skewed by each other's thinking before they've formed their own view. The meeting itself should be 20% reviewing the past, and 80% talking about goals for next quarter. Don't fall into the trap of spending most of your time reviewing and then rushing the goals right at the end.
## Last quarter objectives reflection (5 mins - do as a team)
[Paste in previous quarter objectives from the team page]
For each objective, write up a reflection - usually the person who was the lead on the objective should do this, but some might be shared.
What else did we get done? List items from the changelog or PRs merged if they were significant items that deviated from the original goals (changing goals mid-quarter is okay!)
You may also want to write some overall thoughts about how the quarter generally went.
## HOGS (10 minutes, written privately beforehand and pasted in at the **start** of the session)
Everyone should write their HOGS **privately and independently** before the meeting, in your own notes rather than this doc, then paste them in at the start of the session. Keeping them private until then means people don't anchor on each other's thinking. Spend 10 minutes in the meeting silently reading through everyone’s HOGS during the meeting. Add any common themes or otherwise important items to the section below as you read, then only discuss the themes (there generally isn't time to discuss every line of the HOGS).
Add entries under each question with your initials/name like: "- (your name): My comment"
- Hope
- What are you most excited about this quarter?
- What exploration do you want to do?
- For Error Tracking/Session Replay/Experiments/Conversations/Experiments/Conversations/Product Analytics/AI Observability:
We want to make PostHog proactive. How do we programmatically emit signals - i.e. research prompts for an agent with code access & PostHog MCP – that will result in quality concrete code changes?
- Obstruction
- Is there anything embarrassing about your product?
- What’s stopping you from shipping 2x what you’re shipping now?
- Can your product be used by agents (Claude Code/Cursor/etc.) via our MCP server? What MCP tools or skills are missing right now?
- Growth
- What single thing would move the needle the most this quarter?
- _If it’s more people, please expand on how many and exactly what type of hire you’d be looking for._
- What are users asking for? Which of these are we ignoring?
- _Check Vitally for feature requests (if applicable for your team/product)_
- How will users interact with your product in 1 year's time and what can we do now to get this ready?
- Sneak attack
- Say a competitor beats your team’s product, what would that product do differently?
- What are we not talking about enough?
## Themes (20 minutes - do as a team)
What themes can we distill from the above HOGS list? What are categories of things we should consider working on? What are other things we might want to consider?
### Other things to consider
- For engineering teams - did you do anything cool last quarter that other engineers could learn from? Consider adding a goal to [write about those things on our company blog](/handbook/engineering/writing-blogs)!
- Have you done a pricing review for this product in the last year? If not, follow our [RFC template](https://github.com/PostHog/requests-for-comments-internal/blob/main/_TEMPLATES/request-for-comments-pricing-review.md) to do a pricing review this quarter.
## New goals (15 minutes - do as a team)
This is an example - feel free to adapt as you need. **Each objective must have a single named owner, and so must each thing you'll ship.** Write the name next to the item. Other people can help, but only one person is accountable. Do not leave a goal with no name or with a team name - shared goals usually result in less getting shipped.
Objective 1: PostHog in the EU (Owner Name)
Motivation: Unblock 1,000s of customers [link to data] who need to keep data in the EU but are not capable of self hosting.
What we'll ship:
- This thing (Name)
- Another thing (Name)
- Maybe another thing (Name)
If you aren't on a product team, replace 'product' with the equivalent 'thing' on your team - e.g. if you do recruitment, your 'product' is how we do recruitment at PostHog and your users are job applicants.
Publishing and viewing goals
When a team has set their quarterly goals it is the responsibility of the team lead to document the goals on their team page, publicly. This enables teams to see what each other are working on, helps us hold teams accountable to their goals, and creates a shared sense of urgency and direction.
You can easily see what goals teams have set on the WIP page, which pulls all goals from the respective team pages.
Teams can choose to document their goals publicly in a number of formats, but below is a useful template for getting started. Always include the owner's name with the goal, as the template shows. Individuals may also choose to create planning issues to track their work in greater detail.
<details>
<summary>Write the goal here (owner)</summary>
- **Rationale:** Why is this important?
- **What we'll ship:** Keep this brief
- **We'll know we're successful when:** Metric or outcome
</details>
Good goal setting
Each objective has one named owner - the person who is accountable for it, even if the whole team helps
As few objectives as possible
Motivation - explains why the objective is set
Things we'll ship that show if we're en route to achieving an objective
Objectives are simple - it's really clear if you are/aren't hitting them
Objectives are ambitious - they move the needle for PostHog
Hitting an overarching objective is more important than shipping specific things
Things we'll ship are leading indicators and can be achieved quickly
If you set specific targets, they should be specific and measurable if possible
Setting anti-goals can be helpful to clarify what you are _not_ working on
Bear the following in mind:
Use metrics only if they help you. Goals should be primarily output-based - the actual things that we will do and build.
Don't fall into an existential crisis every time we do this exercise - while objectives are important, they're easy to change, so iterate if you need to mid-quarter
All objectives are bad - they have many compromises, are fallible, easy to game, or may be affected by external factors, so use the least bad ones
Use counter metrics where needed (X happens, but Y shouldn't happen)
Don't have a lot of things to ship if you can't capture everything in one - just pick the most important one or two
Don't set arbitrary targets that a team cannot achieve
Consistently hitting ambitious objectives over the long term is an important factor in the pay review process, but if you miss extremely tough objectives and still achieve great things en route, that's also fine
FAQ
What if I don't have time to do work towards my objectives because of customer support/urgent board reporting/something else?
Picking up the occasional thing that isn't technically going to help your goal is ok. This is because we're small and may not set 100% perfect goals. As ever, prioritize as you see fit. However, spending a bunch of time on a pet project is not - this means the planning process has failed.
If my team repeatedly miss objectives, what happens?
Objectives should be ambitious but achievable - you should be able to hit them by challenging yourself, but not to the point of burnout. If your team is consistently missing objectives, they are too hard or possibly the wrong objectives for PostHog/your team.
We’re very proud to have a genuinely welcoming environment where PostHog treats you, and we treat each other, like grown ups.
We’re an international bunch of weirdos, but one thing us weirdos have in common is that everyone is kind, courteous, and professional towards each other - and that’s something we’re really proud of. And we all ship, of course!
Things we do to create a welcoming environment
We have tried many different tactics over the years, and these are the things we have found _actually_ make a difference.
Asynchronous and transparent communication - so people can get the context they need to work effectively no matter what their schedule.
We offer near complete flexibility over working hours. You can do the school run, or schedule that dentist appointment you’ve been avoiding!
An anti-meeting culture. Ever had someone schedule a meeting over family time because they couldn’t find a slot in your schedule? That doesn’t happen here.
Generous parental leave (inc. up to 6 months maternity at full pay) so those raising families can do so while still working for us. We also extend our bereavement leave to cover pregnancy loss.
Transparent pay - so people get paid in line with their ability and experience, not their negotiation skills!
Proactive pay process - we review _everyone’s_ pay 3 times per year, so we don’t reward people who loudly argue over those who quietly perform.
Generous pay - so people can afford to work here and finance doesn’t prevent this. We take the 50th percentile for any given role then add 20%.
We write our policies up publicly, so we’re accountable to the world, instead of hiding them. Hence this handbook! And anyone can edit it.
A culture of transparent feedback that is constantly reinforced - this discourages gossip or playing politics, which is corrosive.
Training budget, especially for those in roles where we don’t have lots of existing experience as a company, to help people develop.
Health insurance for those from countries that do not provide this freely.
We pay people for SuperDays because we think this is the right thing to do and it enables those who could not otherwise take a day off work to participate in our recruitment process.
We discourage heavy drinking at company events - you’ll need to join another company if you’re a bro, alas.
Political issues can be more important to people than work, and they are frequently divisive and distract from our purpose. We therefore don’t stand for any political cause and don't tolerate or allow political discussions in Slack, GitHub, or any other PostHog-owned or sponsored tools or events.
We don’t care about college degrees. We care about what you’ve achieved.
We expect people to act kindly and inclusively towards each other. We take a very strict stance on people behaving inappropriately towards others.
Things we don’t do that other companies might
We care about doing what works for PostHog’s culture, rather than worrying too much about what other companies are doing or how they judge this. These are some of the things that we don’t do as a result.
We don’t track the metrics for how many people are underrepresented at PostHog or in our application process because we don’t want to optimize for these numbers when we know we offer a welcoming place to work. We used to do this and realized it wasn’t helping us.
Unconscious bias training. Our applicant data shows that under-represented groups are no more or less advantaged by our hiring process, and the effectiveness of such training is debatable.
Making PostHog’s culture the responsibility of the people or an ‘HR’ team - culture starts with the founders and executive team. Otherwise you end up with policies and actual behavior starting to diverge.
Advertise on external job boards. We used to do this (and get 1000s more applications), but found we virtually never hired anyone who didn’t apply directly to posthog.com or through referrals.
We don’t avoid doing business with certain customers except under very strictly defined exceptional circumstances. We allow the government to determine what is acceptable instead of getting into discussions about who we should deal with for each of our 500,000+ teams.
Tell grown-ups how to behave. We expect kindness and we expect direct feedback when something lands badly. Beyond that, judgment beats rules. Overly codifying conduct in the handbook substitutes rule-following for judgment and turns optional guidance into de facto policy. Stuff between people is handled between people. If not, we have a greivance process
Are you a potential candidate reading this? Excited to join a grown up company? Get in touch!
(kjuːdɒs IPA Pronunciation Guide, US kuːdoʊz IPA Pronunciation Guide)
_Kudos is admiration or recognition that someone or something gets as a result of a particular action or achievement._
As an all-remote team, we need to put extra effort into celebrating each others' achievements, as not being in the same physical location can often make good work less visible.
We use Monday All-Hands as an opportunity to acknowledge cool things that people have done in the previous week. Can be _anything_ - shipping a new feature, a great piece of content, fixing an issue, or just generally doing something nice for someone else.
How to give kudos
You can use /kudos @person for [reason] to give someone kudos in Slack whenever you want. The kudos gift won't be visible in the chat for anyone else, but the gifted person will probably enjoy seeing themselves in All-Hands on Monday.
To list all kudos from the last week, use /kudos show 7. This shows the previous 7 days of submissions.
Alternatively, you can just write directly into the All-Hands doc, though this relies on you remembering things that happened the previous week.
A beginner's guide to some of our custom Slack emojis and various anecdotes you'll see and hear about.
bad-internet Yakko always had bad internet when demoing. <em>Always.</em>
James Greenhill wore a skin tight green all-body suit for months to improve his Zoom background game without us realizing.
ben-peace Ben White has the same pose in 90% of PostHog photos. It's a reference to a meme.
hype-X where X is a team member. Used in times of extremely impressive performance, unless used sarcastically.
Mr Blobby. We once changed how we ingest session recording data, to use S3 blob storage. We called it Mr Blobby. Mr Blobby is a creepy '90s TV character from the UK. This project was nightmarishly hard, which is why this character was fitting.
Paul D'Ambra will make you eat gelato at every offsite.
Sometimes people screenshot each other's faces and Zoom screens and use them as their backgrounds. Usually when an all-hands is too dry.
Charles Cook wore a suit to his performance review. He is the only person in history to wear a suit to anything PostHog-related. Unsure if he was making a point, we later abandoned the practice of performance reviews regardless.
We took lots of buses at an offsite in Portugal. The roads were incredibly twisty, the driver was in a bad mood, drove too quickly, and people threw up. It was bad.
sparksjoy / does_not_spark_joy A reference to <a href="https://konmari.com/marie-kondo-rules-of-tidying-sparks-joy/">Marie Kondo's book</a> on tidying your house, generally used to describe things that are particularly good or bad from a user's perspective
eu-thumbsup / thumbs-down-eu We once made <a href="https://www.isgoogleanalyticsillegal.com">isgoogleanalyticsillegal.com</a> when there were privacy rulings about Google Analytics. We put it on Hacker News, got the top of the front page, and it was our biggest <em>ever</em> day of signups at the time. The website was supposed to be tongue in cheek, but the internet took it seriously. The person in the emoji is Ursula von der Leyen, who introduced the GDPR legislation.
IPO promises. There is a list of these that is brought out at certain moments. You may see.
Marius Andra will train you on Post-it notes if you go to an offsite with him. Success of a good Post-it note posting is in the lift away from the surface – the most important thing is to peel off the Post-it note, as opposed to pulling.
Three finger rule - another Marius invention, if someone holds up three fingers while you're talking, it means you aren't being concise enough. We don't actually use this much as it's predictably awkward and distracting, so ruins any meeting it could have otherwise helped.
When we hit 10,000 GitHub stars, Ian Vanagas read every username on a live stream that took over six hours.
We like to nail things. It's not uncommon to see a GitHub issue titled "Nail [feature name]". Sometimes we'll even assign an absurd version number like "3000". (The codename for the next generation UI of the PostHog app is referred to as PostHog 3000, and other projects have also adopted this naming convention as well.)
James Hawkins once decided to go off piste in a new starters intro of all hands and asked the question “Do you moisturize?”
James Hawkins has also gone viral <a href="https://x.com/james406/status/1824083929860583858?s=20">multiple</a> <a href="https://x.com/james406/status/2005715590372020669">times</a> for his tweets about "hopping on a quick call" and that is entirely what he is known for now.
Everyone says "thanks dylan" to Dylan Martin because he once had a really good all-hands demo. He also did a demo entirely with autotune.
Anna-Marie Doudova did a presentation at our Barbados offsite about Gen Z slang which encouraged everyone to do Gen Z slangmaxxing like an unc that's cooked 💀.
Hire movers. Whenever someone asks the team for moving or packing tips, the unanimous, handbook-sanctioned answer is: hire movers. (And, while you're at it, hire packers.) This was settled in a lengthy thread where someone moving to a second-floor apartment a four-minute drive away — with a flight of stairs and lots of heavy furniture — asked for _packing_ hacks and instead received an avalanche of "hire movers" from everyone.
Anything legal-related, e.g. someone wants to quit or thinks they did something illegal - route this to the exec team
Deciding to hire or fire people - the exec team do this
This guidance applies to all teams, irrespective of whether you manage an engineering or non-engineering team.
Part-time managers
Because of the relatively short list of tasks that managers have, management at PostHog is a part-time job. That means nearly everyone still spends the majority of their time on practising what they do best. For most managers, this isn't actually management!
As an engineer, you want the opinion of someone who can actually code. As a designer, you really want your manager to have an eye for design. As an operator, you want to be managed by someone who has scaled a business. That's why it's important for managers to keep practising their craft.
However, management tasks do come _first_, as giving context to your team tends to have a multiplying effect vs. getting one more PR out. After that though, it's back to work.
Management is intentionally spread thin at PostHog. This is a forcing function for making sure that teams and ICs continue to have high levels of autonomy. Bored managers are micromanagers. By working across several teams, people like #team-blitzscale and product managers are forced to only give their attention where it's truly needed, and give space & autonomy everywhere else.
You'll sometimes hear us use the term "team lead". A team lead is the leader of a small team. By default they also manage the individuals that are part of their team, though very occasionally they don't, such as when a new small team has just been created.
How do I set context?
At PostHog, we hire highly experienced people for 99% of roles. That means managers won't need to spend time telling their direct reports what to do.
However, for those people to make the best decisions, they need context. The things a manager can do to set context include:
Creating a roadmap that the team can work towards
Helping the team level-up their understanding of your target customer and the problem space you are working in (eg by encouraging them to talk to users, and doing so yourself)
Helping someone figure out who else to talk to within PostHog
Enabling or encouraging the team to measure their impact
Improving the process in which a team works (things like standups, reviews etc.)
Organizing a team offsite or other meetup to work in person
Pitfalls to avoid
The biggest difference between PostHog and other places is that in the end it is up to the _individual_ to make the decisions. All you can do as a manager is set context. From there, you'll have to trust that we've made the right hiring decisions and that the individual is able to execute on that. If they can't, we have a generous severance policy.
Decisions aren't just about buying a piece of software or choosing a color for a button. It's also about what to work on, what to invest time in, or where to take entire parts of our product.
As a manager, it's tempting to see yourself as the sole owner of all the information, and give it out sparingly. People will come to you often with questions (because they don't have the context) and when they do you'll get more validation that holding all the context yourself makes you an Important Person. What managers should aim for at PostHog is to make themselves obsolete. Share as much context as possible, in written form and in a public channel. That way everyone will be able to do their best work.
Ways to burn yourself out:
Become the sole point of communication between your team and others. Instead, connect the right people together directly.
Take sole responsibility for writing up the detailed plan for your team. Instead, set the vision/roadmap, then encourage your team to contribute objectives too.
Move from IC to manager and just add the management on top of your existing work. Instead, you should cut your IC work down slightly to make room.
Be the only person on your team who talks to customers. Instead, encourage everyone to do this - this starts at onboarding!
How do I make sure my direct reports are happy and productive?
First, make sure you are setting the right context. Next, the most useful thing you can do here is to schedule regular 1-1s. Typically we find that you should have higher frequency 1-1s with your reports when they join PostHog and reduced frequency over time as they settle in. There are some types that we've found useful:
When they start schedule a longer 1-1 to get to know each other and set expectations on each other
During their probation period have weekly 1-1s as a regular check in (this is an important time to be giving clear feedback about how they are doing)
After their probation have bi-weekly or monthly 1-1s to discuss how they are doing outside of the regular day-to-day context
The key thing here is to be pragmatic - 1-1s should feel useful and not like a waste of time. Everyone should see it as their own responsibility to raise important feedback or issues as they happen and not wait unnecessarily for a scheduled meeting.
Talking about long-term career goals every now and again is also important but easy to let slip when things get busy. If you can help people achieve long term goals while at the same time hitting PostHog's short term needs - whether at PostHog or not - you'll get people's best work!
We have a set of handy templates to use - feel free to adapt these for each team member. These are not to be followed strictly if you don't want to - this is to just save you having to create something from scratch.
Performance
We care about having a consistent, transparent, and fair way to handle recurring performance issues. We don’t want this to be a source of stress for you - it’s not your core responsibility as a team lead, and we want you to feel supported. The People & Ops team will prompt you to consider performance within your team at key moments to make this easy and straightforward, but you should proactively give feedback and raise concerns with your exec as they arise.
We expect you to regularly give proactive, actionable feedback to everyone on your team - it’s the most direct way to help troubleshoot issues upstream. This is particularly important at the 30-day, 60-day and 80-day check-ins after a new starter joins.
The team lead will be asked to consider the following questions that are aligned with our values:
i. Is the person a driver or a passenger? ii. Does this person get things done proactively? iii. Are they optimistic by default?
We expect you to actively raise performance issues with your exec.
Once you do, your exec will take the lead on the process. You’ll likely deliver feedback directly to the employee, but your exec will support and coach you through those conversations.
Your exec will look after the process and make any decisions required.
If it ever comes to someone leaving, your exec will work with the People team to handle it carefully, sensitively and fairly.
The keeper test
As PostHog grows, it's increasingly important that all team leads help us keep the bar for performance high - we can't centralize this with the founders. To help us scale this, each team lead will be asked to do a keeper test on their team members throughout the year, this will be sent in an automated form, by Deel, through Slack. The format is as follows:
Ask the team lead 'if X was leaving for a similar role at another company, would you try to keep them?' - the answers should be derived from our values, similar to the questions above.
Dig in where the answer is 'no' - what would it take for this to be a 'yes'? Is this just temporary, or is there a deeper issue to resolve?
Make sure the manager is sharing all of this feedback with their team to help them improve.
The keeper test is only sent for team members who have passed their probation period. New starters are covered by the 30, 60, and 80-day check-ins instead, so if you do not get a keeper test form for someone who joined recently, that is expected.
That form will be shared with the relevant team Blitzscale member, so they can help where necessary.
Feedback also flows the other way. Direct reports are periodically asked to give feedback on their manager through an automated form, rating them against what we expect managers to focus on and explaining why. This keeps the bar for managers high too, and gives them honest signal on how they're doing.
Side note: anyone can ask their manager 'how hard would you work to change my mind if I were thinking of leaving?'. It's a great way to solicit valuable feedback!
Weave
We use a tool called Weave to collect stats for engineers. Engineers can log in to see their numbers and those of other engineers.
We understand that all the work an engineer does can't be properly represented in a tool that just looks at PR output. Data in Weave is _not_ the decision-maker for whether someone is succeeding in their role at PostHog. It can be, however, a part of the conversation.
We use Weave to:
Look for outliers in the company in terms of output (both high and low - sometimes unexpected people are rising to the top!)
Watch for issues with overall team productivity to identify possible blockers
Start conversations with team leads
We don't use Weave to:
Make a decision to let someone go - if and when this happens, it only follows detailed discussion with and recommendation from the team lead
Monitor your PRs - our management layer is stretched way too thin to micromanage this
Creep on your use of AI - we don't care how or if you use AI to get a job done, as long as it gets done
Make a call on how valuable someone is - some people with low PR output are very valuable to the company, and we're 100% aware that things like heavy support load can impact output
We have compared statistics in Weave against other (imperfect!) metrics that can be used to gauge productivity, such as number of commits, number of PRs, total github activity, etc, and see similar patterns amongst them. Weave gives us more detail and a nice UI for evaluating output across all the engineers we have, which we don't have any other good interface for. In addition, it gives engineers access to the same information we have about them, so using it increases transparency.
What does being a hiring manager entail?
Two things:
You will conduct the technical interview by default. You'll also kick off the SuperDay with candidates, and be their main point of contact in Slack. Please help us keep hiring moving by giving feedback quickly!
If you think your team needs someone, make a new hire request. The exec and people team are generally on top of hiring for all teams, but this is a good approach if you think something has been missed. You'll also be asked to do one of these anyway if we're hiring for a new type of role.
See the #technical-interviewers channel for more info here.
What you can expect as a manager
Management roles at PostHog are often (but not always) temporary. That's because as the company changes, our needs for different people in different roles will change as well. Because all of our managers are also strong ICs (individual contributors), sometimes putting someone back into an IC role makes sense if that's what's best for the company. This has happened many times with people at PostHog, some who have gone back and forth between being a manager and not being a manager multiple times (hi Marius Andra!).
As such, management roles are paid on the same pay scale as other ICs. Becoming a manager does not mean you get a pay raise, and going from a manager role back to an IC role does not mean you get a pay decrease.
Management is a skill of its own, and it's not any more important than any other skills that make someone a great IC. It's possible that you may be a manager for a short time, but it becomes clear that your strengths lie primarily in the other skills that are involved with being an IC. In this case we might move you back to a pure IC position, where your skills can really shine, and move someone else from your team or from around the company into the manager / team lead role.
Additionally, managers who are excelling with their teams may have limited interaction with their own manager. This is because, as discussed above, management is intentionally spread thin. If you feel like your manager is mostly ignoring you, this isn't necessarily a bad thing and usually means you and your team are doing a fine job!
What to expect from your Blitzscale team member if they are your manager
The Blitzscale team's mission is to enable all other PostHog small teams to be successful. If you report into a Blitzscale team member here is what you can expect from them:-
They will make sure you know what our mission is and how you and your team contribute to that
They will make sure you know what our strategy is and how you and your team contribute to that
They will share context with you from outside of your team
they will be responsible for balancing people and work amongst their teams - this also involves hiring and firing decisions, although they will rely on you to gather insights into these areas
They will reinforce good cultural behaviour & our values
They will help you prioritize when time or resources are limited aka unblock you
They will re-orient you in the right direction if needed
Here is a list of things you should not expect from them
micromanaging
lots of 1-1s
a detailed plan of how to do your job or be a manager
regularly work through problems live.... it's "you're the driver" not "blitzscale team member is the driver" it's not as catchy
Recommended reading
These have been recommended by multiple managers on the team:
We have a merch store where our community can purchase high quality PostHog-branded merch. The People & Ops team is responsible for managing merch inventory, fulfillment etc. even though multiple people contribute, and Kendal is the point person.
We use Micromerch to manufacture and fulfill our merch. Anyone can suggest a product for us to sell or give away.
The Brand team ultimately decide on what items we wish to sell or give away (including how many and sizes), and Lottie provide assets to produce and order these items in to stock.
We generally try to launch new products in line with the typical fashion cycle (spring/summer and fall/winter). However, this doesn't mean we can't do fun side quests! If you are looking to do an off-cycle merch run, just make sure you keep Kendal in the loop so the admin side goes smoothly.
How to reorder merch
All of our permanent merch items are reordered via Micromerch. To do this you need to:
Request a restock quote for the item(s) in the Slack channel and enter the quantity you need
Approve the estimate that will be sent from Micromerch
Pay the invoice via Brex once it comes in (usually in 1-2 days after estimate approval)
It's really important that we do not allow stock levels to run low as restocking items can take a couple of weeks, so the Ops team will regularly check inventory levels. However, if you happen to see anything looking amiss, just let Kendal know ahead of time!
Big orders
If you want to place a big order for a customer that may affect our stock levels a lot, just let Kendal know ahead of time!
Before sending a large merch order to another country, check with Kendal and Micromerch to confirm that we have an importer of record in the destination country.
If you send merch to a hotel, use the hotel only for the address. Always name a specific person as the recipient, with their own contact details. Never name the hotel or use its contact details. If the hotel is the recipient, customs contacts the hotel, and the hotel usually will not act as the importer or claim the package. The shipment then stays at customs.
Adding new items
Micromerch is integrated with our Shopify store, so all orders are made and processed through there. To add new products to Shopify, follow these instructions..
Shipping
Shipping is also done through Micromerch (in partnership with Shiphero) - they can ship to over 200 territories worldwide:
When orders come in from our Shopify store they will automatically be shipped to the people who order them via Shiphero
If you want to ship merch for an event or as part of a giveaway, do this from the Shopify dashboard.
Merch giveaways
Customers
The quickest way is to ask JokerHog in Slack – tag @.JokerHog in any channel and ask it for a merch code (e.g. "can you make me a merch code for $50 for a contributor?"). It creates the discount code in Shopify and replies with the code, so you don't need to log in yourself.
If you'd rather do it manually, create a discount code in Shopify admin. You don't need to be invited to Shopify, instead the login details are stored in 1Password.
To log into Shopify using 1Password:
Sign in with the email from 1Password
Log in with the saved passkey when the pop-up appears — this is the preferred way to log in
You're logged in!
If you aren't prompted for the passkey, use the password and authentication code instead:
Click "Log in using a different method"
Click "Continue with password"
Use the password from 1Password and click "Log in"
On the "Use your passkey" screen, click "Use the authentication app" — you can then use 1Password to enter the authentication code
You're logged in!
When creating the discount, select "amount off products" then choose if it is a percentage off or a fixed amount - usually we do fixed amounts of $30, $50, or $100 depending on the purpose. The you can choose "specific collections" and choose "All Products".
Limit the use to one use only (_not_ one use per customer), otherwise it's unlimited free stuff for them, unlimited high cost for us!
For feedback or general rewards we typically give users $30, which is enough for a t-shirt. For code contributions we tend to do $50, which is enough for a bigger selection of things. We don't put expiration dates on the codes, typically.
If you need any help just send a message to the #merch channel and somebody will be happy to help.
If you want to send physical merch to a customer instead of a merch code, this can be done in Shopify by creating an order, selecting the chosen merch and applying a discount for the whole price of the item (don't forget to do this step otherwise it'll try and charge the customer!)
PostHog team
If you want more, here's how to get it!
As always, we expect you to use this with restraint and with your own good judgement. The merch store should not become your sole source of clothing for your wardrobe, nor where you go any time a friend has a birthday. But sure, go ahead and buy your mom (or yourself) a hat or a hoodie!
Please note that any free merch received outside of your birthday kit, work anniversary kit, or new hire kit is considered a taxable benefit in most jurisdictions and may be subject to tax. If you have questions about how this applies to you, we recommend checking with your local tax advisor. We will send the details of any free merch you have claimed to payroll once a year (usually in December) and any tax due will be deducted from that payroll (please note this is jurisdiction dependent, and also depends on your employment type at PostHog).
For select exclusive or higher-value items, a cost-price discount code will be shared at the time of launch in lieu of the complimentary allowance, this will always be clearly communicated in advance.
YC Deal
You can find instructions for this on the dedicated YC Deal page.
Troubleshooting customer orders
Sometimes customers get in touch with us because their order hasn't arrived. There are a couple of things you can do:
Check the Shopify. This will show you the status of the order, if something looks amiss, please mention this in the #merch channel immediately so Kendal can look into it.
Note: There have been some issues with fulfilling orders to Brazil due to the country's customs policies.
If for some reason their second order attempt doesn't make it through, refund their money and apologetically let them know that unfortunately our supplier is having issues shipping to their address. It's better to stop the back-and-forth at that point, rather than having a frustrated customer placing multiple orders that don't work. We aren't an e-commerce business, so ensuring a flawless merch store experience for a handful of edge case orders is not a priority!
If the customer was given a merch code to thank them for submitting a PR, you can offer to make a donation on their behalf for the equivalent amount to a company of their choice on Open Collective instead.
If you’re new to GitHub, it can be a little confusing. (Heck, I’ve been using GitHub for years and it’s _still_ confusing.) It doesn’t have the best search and notifications can get out of hand — and in general, it can be really intimidating to join a company that uses a tool you’ve never used before as its primary means of communication.
I wrote this guide to help explain how we work, and how to stay on top of the volume of information that flows through our team's organization on GitHub.
— Cory Watilo
P.S. Have questions? Feel free to file an issue on GitHub - I explain how to do this later in the article!
Key concepts
At its core, GitHub essentially hosts code that helps keep everyone in sync. Each team member can download this code, make changes, and upload their changes back into GitHub.
Code is stored in a “repository” (or “repo” for short) - it’s like a folder for code. (As of writing this, PostHog has 401 repos - like the code for posthog.com and even a repo for internal company discussions that doesn’t actually contain any code.) This is because each repo comes with a handful of collaboration tools. Here’s a list of the key concepts on GitHub:
Discussions
Issues
Projects
Pull requests
Actions
You can take any task linearly from start to finish using this set of tools, though you don’t have to use them all. (For example, PostHog doesn’t really use Discussions, and Projects are only used by certain teams.) But if you wanted to use the whole suite, here’s how it would work:
If you decide you want to change something in the product or website, you could start a _discussion_ about it. This is like a casual forum-style conversation. (Again, we don't use these.
A discussion can be converted to an _issue_, which is a formalized proposal of the discussion.) People can reply to these posts with feedback.
In my workflow, this is a good time to add the issue to a _project_, because it’s something you want to track through to completion. Project boards are a great way to stack-rank tasks (issues), because you can order them in a way that makes sense based upon the project and see everything in one place. This helps keep a team in sync.
A _pull request_ (also known as a _PR_) references the code that’s changed to solve an _issue_. It’s a way to summarize the changes in code and explain them so others can review them.
_Actions_ usually occur after you commit code. It makes sure things are working as expected (and that whoever wrote the code didn’t break anything). (Don't worry about these for now.)
You can use any of these features on their own, or use them together. Primarily, PostHog uses issues, pull requests, and actions. If you’re not super familiar with GitHub, just focus on issues and pull requests, as that’s where the bulk of the interesting work happens.
The best way to stay up-to-date with what happens on GitHub is by subscribing to (following) the areas that are most relevant to what you do. This sends updates to your GitHub notifications.
By default, you’ll receive email notifications for everything you subscribe to. There are a few ways this happens:
Creating an issue or pull request
Commenting on an issue or pull request
“Watching” a repository
As I’m not a huge fan of email, I prefer to visit a centralized place for my GitHub notifications, although many engineers prefer email notifications. Personally, I don’t like GitHub’s /notifications page, as it feels cumbersome (slow) to read through updates. Here are two much better ways to consume GitHub notifications (entirely my opinion):
GitHub’s iPad app - provides an email-like interface that feels a lot more natural to reading notifications than github.com/notifications. (If only GitHub had this UI on the web...)
octobox.io - uses the same email-like interface, but in a browser
I have octobox.io set to my homepage in Chrome, so anytime I want to see my notifications, I just click the Home button and I have one-click access to my work “inbox”.
Install the GitHub app in Slack
A great way to get realtime updates about what’s happening in GitHub is to install the GitHub Slack app and subscribe to repos. After linking with your Slack account, type /github subscribe posthog/posthog.com (org/repo-name) in Slack, for example, to get updates when things happen in the posthog.com repo.
Finding issues or pull requests
Given the volume of issues and PRs, search will be your best friend. Unfortunately GitHub’s global search leaves something to be desired, so usually the easiest way to find something is to visit a repo, then clicking either Issues or Pull requests (depending on what you're looking for) and searching from there. Type a few keywords, and if you know who authored the issue or PR, apply an author search. (You’ll see GitHub pre-populate search syntax (eg: is:open is:issue author:corywatilo), similar to how Gmail’s search works.
Filing an issue
Issue is the primary method of getting a message in front of the team. Think of it like creating a ticket in a typical project management system. (We prefer issues over Slack messages because it's public and can sync with the rest of our code workflow. You can use Slack if you’d like to bump an issue to a group of people, but link to the issue (or PR) as GitHub acts as our source of truth.)
Issue templates
Some repos have issue templates set up to make issue creation faster. However, if the issue you’re going to create doesn’t fit into one of these templates, don’t worry about these! Just create a new blank issue.
Referencing another issue
This isn’t mandatory, but if your issue is related to other (previous) issues, it’s worth cross-linking so others have full context. To cross-link in an issue or PR, type a # and either part of an issue’s/PR’s name or number and GitHub will populate a list of items that match.
You can find an issue’s or PR’s number in the URL.
Writing Markdown
It can take some getting used to if you’ve never written Markdown syntax. Fortunately GitHub makes it easy by providing WYSIWYG buttons. When you press a button like B, I, or U, GitHub will insert the Markdown code required to format your text accordingly.
Tips for faster writing
You can use keyboard shortcuts like you would in a word processor.
Quickly insert a link by copying it to your clipboard, selecting the word or phrase you’d like to link, then using Cmd + V. GitHub will automatically convert the text into a link.
Create a checklist by typing - [ ] Your text. You (and others) can check things off of this list after the issue/PR is created.
Paste an image from your clipboard directly into an issue/PR. It’s much faster than attaching from your computer. For example, if you’re screenshotting something on a Mac, use Cmd + Shift + Ctrl + 4 to select part of your screen, then Cmd + V into an issue. GitHub will upload the image automatically and add the Markdown embed code for you. Voila!
Creating a pull request
If you see something minor on posthog.com (in Handbook or Docs) that needs to be updated, you can easily propose the change by creating a pull request _without_ having to run the full codebase on your computer. (This is a great way to contribute if you're in a less-technical role.) To make a small change, find the _Edit this page_ link within the Handbook or Docs which will take you to GitHub where you’ll see the source file. From there, click the pencil icon. (Our Handbook and Docs use the same Markdown format as GitHub’s issue and PR editor, so this should look familiar!)
When you’re done making your changes, be sure to preview what the changes look like (to make sure formatting is accurate). At the bottom of the page, you’ll see a section called _Commit changes_. Here’s how to use it:
Briefly describe the change you made in the top line
Optionally add a more detailed description
Choose “Create a new branch...” and optionally give it a name (but not required)
Clicking _Propose changes_ will create a pull request!
"Closing keywords"
If you’re changing code to address an open issue, you can tell GitHub to automatically close the issue when the PR is merged by using a closing keyword. For example, in your PR description, you can write “Closes #123” (where #123 is an issue number).
Requesting a review
Now that your PR is created, you can request a review (best practice) from someone relevant so they can make sure everything looks good and that they agree the change is ready to go live. They’ll be notified of your request. (By the way, you can filter to reviews that others request from you by going to your notifications, then choosing the Review requested filter.)
Previewing changes
If you're making changes to posthog.com, you'll be able to see your changes on a "preview" version of the website. It takes 10-20 minutes for this preview to be ready.
(Remember when I said we also use GitHub Actions? It basically runs some automated tests to make sure everything is spelled correctly and that nothing else broke.)
Near the bottom of a pull request page, you'll see a box like this:
Image: Checks
(Note: This box only appears if you're a member of the PostHog GitHub org - it's not available to the public.)
You can click the _Visit Preview_ link in the Vercel bot comment to see the preview.
Merging changes
Once a team member approves your pull request, you (or they) can publish the changes by clicking the _Squash and merge_ button. It will take another 10-20 minutes for your changes to appear on the site, but they'll go live automatically. At that point, you can send a link to your friends and family and tell them you're a coder now!
Next steps
This was a primer on using GitHub for communication at PostHog. If you’re interested in making more substantial changes to the website, you can follow our instructions on how to develop the website. It can take a little work to get your computer set up to run the site from your computer, so don't hesitate to reach out for help if you get stuck – or don't even know where to begin. That's what we're here for!
While we’re async by default, there’s a very real upside to being in the same room - we’ve consistently found that a lot of our best ideas come from actually building things together in real life.
We understand organizing travel can be a challenge when you have personal/family commitments to manage, so we try to take a balanced approach to meetups:
Once a year: all-company offsite
Once a year: Small Team offsite (app and platform teams do this as a single combined offsite)
Once a year, the entire company will get together somewhere in the world for a week. Usually we'll all fly on Sunday, have an opening dinner, spend the week doing a mix of hard work, strategy, culture and fun activities and we then all fly back home on Friday. Our past offsites have been in Italy, Portugal and Iceland. We try to ensure that everyone has their own bedroom.
These are organized by the Ops & People team, and we budget up to $3,000 per person in total for these.
Typical agenda:
A couple of structured social events
Team dinners
24hr Hackathon
All-hands strategic sessions and workshops
All-hands culture exercises
A small amount of downtime so people can explore
Small team offsites
We want to try to encourage small teams to get together once each year. Ideally they are spaced appropriately through the year in relation to the all-company offsite.
We want team offsites to be social events and encourage you to optimize offsites for meeting as many colleagues as is reasonably possible, even if it means spending more money or travelling further. Hogpatch in San Francisco or the Hedge House in London should be the default choice, because:
They're places where there are already a lot of PostHog people that you can hang out with. If most teams do their offsites there, you're much more likely to run into even more people
The more we have random cross-pollination, the more ambitious ideas we'll come up with and the more successful we'll be.
These hubs are places where you can get to know people outside your current team, which means you'll be more effective at getting stuff done.
SF has the benefit of being the epicenter of everything happening in tech, and we have lots of YC founders working out of Hogpatch who you can meet and learn from. It's good to get exposure to this, especially if you don't live in SF or haven't been recently.
Traveling to new places is a perk for PostHog employees. At the same time, going to the hubs, especially for newer joiners, can be beneficial to you as an employee and to the company as a whole. We trust you to make the right decision here, balancing personal preference with what's best for the company.
If you do decide to do a small team offsite somewhere outside of these two hubs, let Kendal know why. That way we can figure out how to make going to the hubs more appealing, or perhaps open new hubs.
Planning a small team offsite? Kendal’s got you covered. Here’s how it works:
The team lead should request an offsite through slack using the '/offsite' command. They will need to input:
Team name
Location
Dates
Attendees
Number of attendees
This will automatically create a Slack channel and Brex budget for all attendees. If the offsite is happening in London or San Francisco, it will also post an announcement in those channels so people can come and say hi
Kendal will then:
Update the team’s Canvas with:
Accommodation details and a handy map
A flight tracker
A rough itinerary (Kendal will include the mandatory bits, like 360° feedback/Readme sessions, team leads can fill in the rest)
Look up dining options for a couple of group dinners (we like to keep a few nights free for “choose your own adventure” dining).
Suggest and book a whole group activity for everyone to enjoy together.
If there’s anything ad hoc you’d like Kendal to take point on, just let her know, she’s happy to help! Each team member is still responsible for booking their own flights.
Some guidelines:
We prefer AirBnBs over hotels, to give your team even more time to hang out, but this is not mandatory.
Quarterly planning is a great focal point for team offsites – it's worth scheduling your meetup for the week of planning.
Outside of your small team, you should only invite people who actually need to attend to make the offsite a success - if it would be 'nice to have' them attend, they shouldn't be going.
It can be useful to combine offsites but beware if you add too many people everything gets harder to arrange. There's no hard and fast rule here but the more people that are attending the more concrete you need to be on who is organising and why people are attending. It will be more work and you should be purposeful about it.
If the number of attendees is >10 actively consider if Kendal should be attending so there is a person attending whose only focus is making sure it goes well and everyone else can focus on the work of the offsite.
Specify offsite start and end times down to the hour, for clarity and efficient use of everyone's time.
These offsites don't happen very often and involve a lot of travel, so make sure you make the most out of it by having an agenda and an idea of what you want to achieve _before_ the start of the trip. Also, it's a good idea to have an expectation-setting session (can be async in a Figjam) to ensure everyone is on the same page about what the outcome/output of the offsite should be.
Make it very clear who is participating in each session. Sessions / activities require full participation from attendees, especially for the likes of a hackathon given it runs over multiple days. Ideally one person should be responsible for the agenda and run a kick-off at the start of the hackathon.
You should do a 360 degree feedback session. It can feel uncomfortable doing these, but almost everyone who's done one at PostHog has come out feeling better and with a whole host of things they can improve. These are best in person.
This can work better over a shared cooked meal or takeaway in the accommodation rather than a noisy restaurant, particularly for people who might be anxious about the format or the feedback.
Ideas for the agenda:
360 degree feedback session (mandatory!)
A spoken README session early in the week to share "Who am I/How I work best"
Planning session – what does the team want to achieve in the next month/quarter/year?
Dogfooding session – set PostHog up in a toy project from scratch, looking for pain points
Hackathon - try to leave 2 days for this, and most importantly avoid sessions interrupting hacking
Even some regular work on ongoing challenging projects - this is the best time for exchanging knowledge!
Don't run a hackathon during an onboarding offsite. Other offsites normally do have a hackathon. Participation should be _very_ strongly encouraged but not mandatory - if not everyone is taking part make sure that working spaces are available to accommodate the different styles of work. It is super important that people taking part are fully available and focused on participating. Given the offsite is an opportunity to work together there should be no teams of one. This extends beyond the formation of teams and into the hackathon itself in cases where there is team switching.
Here's a real-world example: Product Analytics team's Munich offsite agenda (internal Slack link). Feel free to take inspiration – though your team's needs and wants might be quite different!
The budget for these trips is up to $2,000 per person in total. We ask team members to use their best judgement for these and try to be thrifty where possible - these should be enjoyable, but not feel like a holiday. Generally it's easier to hit budget if you have people travel in on a Monday and out on a Friday - they don't need to be as long as a whole team offsite.
You should assign someone on the small team to be responsible for planning the offsite (doesn't have to be the lead), and they will be supported by the Ops & People team to ensure a successful experience.
On occasion during busy hiring peak time, we do recommend any team member involved in the interview process to dedicate at least one hour block per day during the offsites to accommodate candidate interviews so that this does not delay the hiring process on your team while you're away. Please coordinate directly with #team-talent if you have additional questions.
Hedge House
PostHog runs two Hedge Houses in the UK - a small one in Cambridge and a larger one in London. They are actual houses (yes, with a few bedrooms attached!) designed for small teams to run their offsites, host in-person onboardings, or come together for larger internal events like hackathons. Anyone at PostHog is welcome to use them as much as they like — alongside Hogpatch in San Francisco, these are where you should default to doing team offsites and in-person onboarding.
Cambridge
Message Kendal Ijeh to check availability or make a booking at the Cambridge Hedge House.
London
Our light-filled, studious office is a reliable homebase between Farringdon and Barbican. It’s entirely ours, open 24/7 and the perfect place to stay if you're visiting from abroad. Use the Hedge House London slack tool to see the full address, book a room and/or desk, plus see who else will be there during the week you visit. Ensure to read the House Manual too - you can find this in the app or pinned to the London Slack channel The app means you can easily self-serve, but ask Kendal Ijeh with any questions. We don’t allow weekend stays or Personal trips at Hedge House, the house is for co-working only, not for general stays.
London hotel recommendations
For offsites and onboardings in London, below is a list of hotels recommended in our #London Slack channel by folks who have stayed at these hotels.:
If hotel prices are above £200 per night, it is worth quickly looking for alternatives as ~£170 per night should be achievable midweek in London. If prices are high, you should optimise travel for total cost (flights & accom) so if you can get cheaper flights or hotel by moving dates +/- 1 day, then look into these options.
Other London recommendations
Visiting the Hedge House from out of town? Here are some local spots the team recommends for food, drinks, and things to do:
Fare. Good Italian food and drinks in a relaxed atmosphere, 2 minutes walk from the Hedge House.
Space Talk. A hi-fi cocktail bar with a cozy vibe, 2 minutes walk from the Hedge House.
The Slaughtered Lamb. A busy London pub suitable for large groups, next door to the Hedge House.
The Holy Tavern. One of the UK's oldest pubs and a PostHog favorite during summer, 7 minutes walk from the Hedge House.
Gazette. French restaurant inside the Marrable's Hotel, just 3 minutes walk from the Hedge House.
Whitecross Market. Lots of food options, open every day for lunch, 5 minutes walk from the Hedge House.
Flight Club. Social darts, food and drinks for large groups, many locations.
The Bill Murray. North London comedy club with regular shows, good for small groups.
West End shows. Wide variety of shows, with ticket prices much lower than in the US.
Museums. London has a wide variety of free museums, many with late-night events.
For more, check the #London Slack channel – it has a canvas with further details for visitors, including how to use the Hedge House music system.
Border Control
Quite often you will be required to travel to places where some kind of visa is required even if just a visitor visa like an ESTA. When entering places like the US, for work purposes, border control agents may ask the purpose of your trip. In these instances it's best to avoid using PostHog terms like "onboarding" as this can be confusing. It's much better to more generally describe the purpose of your trip. In nearly all circumstances this will be to hang out with your colleagues and to take part in team building exercises. It's usually good to emphasize that you'll be on a short trip and that the company is paying for everything. You should be prepared with the exact addresses of where you are staying and the details of your flight out of the country.
A successful strategy is usually to start off with a high-level purpose of your trip which is usually something like "hanging out with colleauges" or "I am here for a business meeting with colleauges", it is also usually advisable to only respond with a minimal amount, saying only what is necessary. If the agent asks for more details it's usually good to go into a bit more detail about the company structure "I work for a US tech company and I am based in [Insert your country] where I work remotely. I am here to do some in-person meetings with my colleagues for the next few days and I fly back on [insert date]". Sometimes the border patrol agent will ask more about the business, it's fine to give these details and be as honest about that as you would anybody else. If further details are required of the content of the trip, you can again give some context of how we like to lean into the benefits of in-person working and since most of your colleagues are based in the US, you are travelling their for a few days to meet in-person and will be returning home afterwards.
For all company offsites, it's best to describe this as a company gathering where you will be hanging out with colleagues for the week. Generally, it is best to avoid using the phrase "training" as this can also be confusing.
Travel insurance
Many of our company offsites involve team members traveling abroad, and although we hope that these trips are uneventful and safe for all, in the event of an accident or medical emergency, we carry travel insurance through as well as general & auto liability policies through our partner Embroker.
In the event of an emergency, please cover any related expenses (ideally on your company card) and keep receipts, and then reach out to Kendal as soon as possible. We will assist with making a claim based on our policy binders.
Flight delays
If your travel plans are affected due to a flight delay or an airline-induced missed connection and you are forced to stay somewhere unplanned overnight, push the airline to cover the cost of your accommodations (including meals). It's not uncommon for them to initially tell you they no longer offer free hotel rooms for delays that were caused by the airline, but with a little bit of polite coaxing, they will likely give in.
Partners / family joining offsites
Sometimes at PostHog you will be asked to travel to places you've never been before and it could be a good opportunity to travel with your partner / family. At PostHog, we do infrequent in-person work that we want to maximise this time in person and your focus to be on PostHog, without distraction. This is why we don't allow partners or family to join you for the dates that the offsite / onboarding takes place. If timing allows it, you are able to tack holiday onto either side and for your partner/family to join you for those dates. However, for the dates of the offsite, you should be staying alone and focusing on your time with your teammates.
How to plan an offsite in 8 weeks - a checklist
Below is a rough timeline for planning your next offsite, as well as links to templates and resources that you can repurpose and customize as needed. Here's a spreadsheet template you can use with your team to democratically vote for the meetup location, and in other tabs, include travel information (in case someone's flight gets delayed/cancelled), schedule, project ideas, team activities, etc. To use any of the templates, create a copy to your own drive and edit as you see fit.
8 weeks out
[ ] Choose dates
Try to avoid public holidays and be mindful of proximity to other offsites to minimize travel fatigue
School holidays are more difficult for people with children
Be mindful of the season of your chosen location, as this will dictate what activities you can plan
It is worth getting people to hold dates as early as possible, even before you've selected a location
[ ] Choose location
Consider choosing a location that is relatively easy for most people to attend without having to travel outrageous distances or deal with difficult visa processes.
Transportation to the offsite is usually one of the larger budget line items, so do some research on the cost of flights from team locations before finalizing a location.
Consider the cost of transportation to/from the airport, and around town, for when your team arrives at the offsite location.
Be mindful that people who take long flights won't appreciate a 2hr journey from the airport to accommodation!
[ ] Announce to team
You can have fun with this and build excitement by progressively dropping hints and having folks try to guess the location
[ ] Create an offsite Slack channel and invite team
This is super useful for making announcements and keeping the team updated throughout planning
7 weeks out
[ ] Secure accommodations
The ideal location will depend on the size of your team
We recommend booking a large Airbnb for teams under 10 people as this provides for a more casual atmosphere and can help control costs if you opt to have the team cook meals together. You can also book an Airbnb and supplement with a nearby hotel if the Airbnb doesn't have enough rooms.
For larger teams, consider a centrally located hotel that has a bookable space with configurable furniture for different activities, an onsite restaurant or bar to simplify meals and provide a location for free social time, as well as amenities like a gym for those who like to stay active while they travel
[ ] Start flight booking process
To simplify this process, we give all team members access to a company card, and we ask people to book their own flights
We strongly recommend this approach as centralizing flight booking can be a huge headache for offsite lead, and this allows team members to accurately enter their personal information including airline frequent flier and trusted traveller numbers
Encourage folks to buy flights early and with the option to refund if they are unable to attend to save on costs. Use your judgement here - 20% or so is reasonable for the flexibility, but double the price is not really worth it.
In the event that a new team member will be attending an offsite, but has not started yet, please contact the Ops team to help coordinate. In these cases, the process is:
Preemptively create the new team member a Google account
Issue them a Brex card to their work email with a sufficiently high temporary balance to cover travel costs
Add them as a guest to any planning Slack channels and/or share any necessary itinerary information such as arrival dates/times and airports
Use this form to collect important information like flight details, clothing sizes for merch, dietary restriction, and preferences for things like sharing rooms
[ ] Brainstorm merch/meeting room decorations (generally just for company-wide offsites)
Having some branded merch to commemorate the offsite upon arrival is a great way to welcome people and get them excited for their time together (generally this is for whole team offsites only for budgetary reasons)
If you are staying in a hotel, decorating a meeting room makes it feel much more personal and less corporate
In the past, we've done shirts, hats, scarves, notebooks, stickers, pens, and water bottles -- feel free to get creative with it
Using the tentative schedule, you can begin to estimate a rough budget to guide planning. Here are some benchmarks to use, however these will vary a lot based on location, size of team, and how cost-constrained you are:
Using preferences from the info gathering form regarding sharing rooms, assign accordingly
[ ] Secure visas where necessary
[ ] Review and finalize merch proofs
[ ] Finalize itinerary
[ ] Finalize budget
[ ] Assign session leads & secretaries
Decide in advance who is going to record the notes from each session - it is _really_ easy for post-offsite followup to fall through the cracks
With the schedule finalized, assign folks as session leads to design session plans
4 weeks out
[ ] Reserve restaurants for communal meals
[ ] Book any remaining activities
[ ] Order merchandise
Important to give yourself lots of lead time here, in case of production or shipping delays
Depending on how restrictive customs are for your destination, consider shipping merch to teammates and checking them as additional bags on flights to the offsite
One activity we've found quite popular is giving out superlative awards to the team during the closing ceremonies
2 Weeks Out
[ ] Review and finalize session plans/presentations
We recommend having the offsite lead connect with session leads to review their plans and offer feedback before finalizing them - you want to make the most out of your sync time together
[ ] Block your calendar and send a reminder in Slack for other team members do the same, to avoid interviews and other meetings being booked during key sessions or at times incompatible with the new timezone. The offsite calendar event needs to be marked as "busy" to prevent others from booking over it, which means changing the default for all-day events.
[ ] Designate someone to bring or organise some of the essential supplies you expect to need for the week. At a minimum have post-it notes (don't skimp on cheap ones that fall off the wall), sharpies, a HDMI cable and / or a Chrome Cast.
1 Week Out
[ ] Final plan review
The offsite lead should do a final, thorough review of the full plan and finalize any outstanding details - visually walk through the entire schedule and see if anything is missing
[ ] Unveil the final offsite guide to the team
1 day before
[ ] Add your new timezone as a secondary timezone in Google Calendar and check the 'Ask to update my primary timezone to current location' option. Don't update your primary timezone to the new one, as this causes issues for interview scheduling.
[ ] We recommend that the offsite organizer consider arriving a day early to prep for the team's arrival
[ ] Shop for any miscellaneous supplies and groceries (onsite)
[ ] Print and organize a few paper copies of the itinerary (onsite)
[ ] Create "Careless Whispers" envelopes (onsite)
This passive activity involves creating an envelope for every member of the team, posting them in a central location, and encouraging folks to write small notes to each other. These can be anything from retreat memories to compliments, and make a really nice memento to remember the offsite
Consider also making and posting envelopes for folks who cannot attend
1 week after
[ ] Collect post-mortem feedback from the team
We generally do this as an open GitHub issue, but you can also create a Google form to facilitate this
2 weeks after
[ ] Compile post-mortem feedback and share with team
[ ] Host post-mortem meeting to discuss any outstanding issues (optional)
On September 29, 2025, the PostHog Feature Flags service experienced an outage lasting 1 hour and 48 minutes, from 16:58 to 18:46 UTC. During this period, approximately 78% of flag evaluation requests in the US region failed with HTTP 504 errors.
Summary
A database connection timeout reduction from 1 second to 300 milliseconds coincided with elevated load on our writer database from person ingestion. This combination triggered cascading failures in our connection retry logic, resulting in a service-wide outage. Recovery was significantly delayed by hardcoded configuration values and procedural failures in our incident response.
Timeline
16:58 UTC – Writer database begins experiencing connection saturation from person ingestion post-deployment workload
17:02 UTC – Unrelated deployment reduces database connection timeout from 1s to 300ms
17:05 UTC – Initial pods begin failing database connections and entering crash loops
{"timestamp":"2025-09-29T16:54:16.154136Z","level":"ERROR","fields":{"message":"Failed to create database pools","error":"Database error: pool timed out while waiting for an open connection"},"target":"feature_flags::server","threadId":"ThreadId(1)"}
thread 'main' panicked at feature-flags/src/main.rs:119:5:
internal error: entered unreachable code: Server exited unexpectedly
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
17:12 UTC – Retry amplification begins overwhelming the writer database
17:25 UTC – Incident declared, rollback attempted
17:40 UTC – Rollback fails due to ArgoCD configuration issues
18:15 UTC – Manual configuration changes deployed
18:46 UTC – Service fully restored
Full service degradation timeline
Root cause analysis
The outage resulted from three compounding factors:
Configuration change timing: A connection timeout reduction deployed during a period of database stress created conditions where pods could not establish connections within the new timeout window.
Retry amplification: Our retry logic lacked circuit breakers and exponential backoff, causing failed connection attempts to multiply rapidly. This transformed a manageable database load issue into complete service unavailability.
Health check configuration: Kubernetes continued routing traffic to pods in crash loops for up to 45 minutes due to improperly configured liveness and readiness probes.
The incident duration was extended by operational failures: timeout values were hardcoded in the application rather than externalized as configuration, requiring a full deployment cycle to modify. Additionally, our standard ArgoCD rollback procedure failed due to misconfigured permissions.
Impact
78% of feature flag evaluation requests failed in the US region
All flag types were affected, including read-only flags that did not require writer database access
Customers experienced HTTP 504 errors regardless of their specific flag configurations
Remediation
Immediate actions (completed)
Database connection timeouts moved to runtime configuration
Timeout values increased to accommodate peak load scenarios
Read/write path separation: Implementing distinct connection pools and failure domains for read-only operations versus write operations. Read-only flag evaluations will continue functioning during writer database issues.
Circuit breaker implementation: Adding circuit breakers with exponential backoff to prevent retry amplification during connection failures.
Health check optimization: Configuring aggressive liveness and readiness probes to remove failing pods from rotation within seconds rather than minutes.
Rollback procedure documentation: Creating detailed runbooks for ArgoCD rollbacks with proper permission configurations and validation steps.
Long-term improvements (Q4 2025 – Q1 2026)
Development of specialized tooling for rapid pod termination during incidents
Comprehensive load testing to validate connection pool behavior under contention
Quarterly incident response drills to ensure operational readiness
Lessons learned
This incident highlighted critical gaps in our defensive architecture and operational procedures. The coupling of read and write operations created unnecessary failure domains, while our retry logic lacked basic protective mechanisms against amplification. Most significantly, our incident response was hampered by inflexible configuration management and untested rollback procedures.
The architectural improvements underway will provide proper isolation between different operational modes of the feature flags service. This separation, combined with improved circuit breaking and configuration management, will prevent similar cascading failures in the future.
On October 3, 2025, a backwards compatibility issue in the PostHog Surveys SDK (version 1.270.0) caused widespread JavaScript exceptions for customers using SDK versions older than 1.257.1. The issue lasted 5 hours and 26 minutes, affecting 305 teams and disrupting both survey functionality and error tracking metrics.
Summary
A backwards compatibility break in SDK version 1.270.0 introduced a dependency on the isDisabled function from the PostHogPersistence class, which was only added in version 1.257.1 (July 2025). The issue manifested when the asynchronously-loaded survey extension attempted to call this function on older SDK versions where it didn't exist, causing JavaScript exceptions in customer applications. The incident was initially detected through customer support tickets rather than automated monitoring, leading to a 4+ hour detection delay and extended customer impact.
Timeline
All times in UTC.
10:45 – SDK version 1.270.0 deployed to production with backwards compatibility issue
The culprit PR introduced the backwards compatibility issue.
The technical problem
The PR modified the surveys SDK to use posthog.persistence instead of accessing localStorage directly – a reasonable architectural improvement. To ensure backwards compatibility, the code needed to check whether posthog.persistence was available before attempting to use it.
The implementation used the isDisabled function from the PostHogPersistence class, adding a utility in survey-utils.ts to verify persistence availability. However, this function was only introduced in a PR merged on July 11 and first made available in SDK version 1.257.1.
Why it failed
When PR #2355 was merged, both the main SDK code (posthog-surveys.ts) and the extension code (extensions/surveys.tsx) relied on the isDisabled function.
For the main SDK bundle, this worked correctly – customers on older versions never loaded the new code containing the reference to isDisabled.
However, the survey extension creates an asymmetric loading scenario:
The customer's application loads the SDK at whatever version they have installed (potentially months or years old)
The survey extension is loaded asynchronously from our CDN and always downloads the latest version
This created a version mismatch where:
The old SDK (< 1.257.1) didn't have the isDisabled function
The new extension (1.270.0) expected it to exist
JavaScript threw TypeError: isDisabled is not a function exceptions
Why it wasn't caught
No version compatibility testing: We lack automated tests that verify new extension code works with older SDK versions
Code review gaps: We don't have a process to flag when new APIs are added to main SDK files that might be called by extensions
No static analysis: No linter rules prevent extensions from calling functions that may not exist in older SDK versions
Detection gaps: No monitoring alerted us to the spike in customer-side exceptions – we learned about it from support tickets
Impact
Severity: Major (High Impact, Service Degradation)
Affected customers: 305 teams running SDK versions < 1.257.1
User-facing impact:
All Survey functionality completely broken (surveys failed to load or display)
Increased error tracking bill for affected customers due to exception volume
JavaScript exceptions thrown in customer applications, potentially affecting their own application functionality and exception-tracking bills in other platforms
Duration: 5 hours 26 minutes of active impact
Error tracking billing impact:
Initially 305 teams saw increased exception volumes
Successfully filtered out the most common exception pattern via this PR, reducing billable impact to 90 teams
The remaining 215 teams' exceptions were successfully excluded from their bills
The 90 teams still affected experienced other related exception patterns that couldn't be automatically filtered
Remediation
We reverted the problematic changes and released SDK version 1.270.1, which restored compatibility with all SDK versions.
Immediate actions
Reverted the backwards-incompatible changes and released version 1.270.1
Issued credits / refunds to all customers affected by increased error tracking bills
Sent communications to all 305 affected teams explaining the issue and resolution
Action item: Start incidents earlier. We should declare incidents as soon as we confirm an issue (around 14:59), not almost two hours after mitigation. This enables proper coordination and customer communication. Owner: @lucasheriques
Short-term improvements
API compatibility layer: Modify the isDisabled function check in posthog-persistence.ts to be nullable and provide a safe fallback when undefined. This will prevent similar issues when extensions call potentially-unavailable functions. PR
Ignore PostHog SDK exceptions: By default we should not capture exceptions known to be caused by the PostHog SDK. Offering a config option to toggle this parameter would allow teams (especially our own) to configure this setting. [PR]
Monitor suspicious exceptions: The error tracking team should monitor the number of exceptions that look likely to be coming from our own SDK. Adding alerting to this metric would allow us to detect anomalies sooner. [PR]
Version compatibility testing: Add automated tests that run the latest extension code against the last N minor. Owner: @lucasheriques
Static analysis tooling: Implement a linter rule or TypeScript checking to flag when extension code calls SDK functions that aren't marked as "stable API" or don't have proper fallback handling. This should run in CI and block PRs. Owner: @lucasheriques
Client-side error monitoring: Set up monitoring and alerting for exception spikes in customer applications that use our SDK. This would have detected the issue within minutes instead of hours. Owner: @lucasheriques
Lessons learned
What went well
Quick mitigation once identified: From confirmation (15:25) to mitigation (16:11) was only 46 minutes
Cross-team collaboration: Support, Error Tracking, and Surveys teams all contributed to identifying and resolving the issue
Effective customer remediation: Successfully filtered out most exceptions to reduce billing impact from 305 to 90 teams
What went poorly
Detection delay: 4+ hours from deployment to detection is unacceptable for an issue affecting 305 customers. We relied on customer reports rather than proactive monitoring
Backwards compatibility blindspot: Our development and review process had no safeguards against this class of bug
Incident declaration timing: We declared the incident after it was resolved, missing the opportunity for coordinated response and timely customer communication
Testing gaps: No integration tests covering the extension/SDK version compatibility scenario
Key takeaways
This incident revealed a critical architectural weakness in how our asynchronously-loaded extensions interact with versioned SDK code. The assumption that extensions can safely call any SDK function breaks down when we have customers on old SDK versions but always serve them the latest extension code.
The 4+ hour detection delay highlights gaps in our observability for client-side errors. We lack visibility into exceptions occurring in customer applications using our SDK.
The improvements outlined above will address both the immediate technical issue and the systemic gaps in testing, monitoring, and deployment practices that allowed this to reach production and persist for over 5 hours.
Between October 21 and October 30, 2025, the PostHog Feature Flags service experienced four separate incidents, exposing systemic architectural weaknesses that required comprehensive remediation. This post-mortem documents all four incidents and our path to stability.
Summary
Over a 10-day period in October 2025, the feature flags service experienced four separate incidents totaling over 14 hours of cumulative major impact (errors or severe latency). While each incident had different surface-level symptoms, three of the four incidents shared the same root cause: improper CPU resource sizing. Our nodes were too small relative to pod resource requests, causing Kubernetes to pack too many pods per node and saturate CPU capacity. This CPU saturation led to connection pool exhaustion, excessive parallelism (too many concurrent operations), and ultimately cascading failures. The fourth incident was a rate limiting misconfiguration unrelated to resource sizing.
Incidents:
October 21 (103 minutes): Redis overload from excessive parallelism and connection pool exhaustion
October 24 (72 minutes): Rate limiting misconfiguration causing 429 errors for ~97% of requests
October 28 (123 minutes): Connection pool exhaustion and excessive parallelism (same root cause as October 21)
October 29-30 (7 hours 9 minutes): CPU-bound latency from node CPU pressure exceeding 90%
Incident timeline
October 21, 2025 – Redis overload
Duration: 21:45 to 23:28 UTC (103 minutes) Impact: ~38% of evaluation requests returning errors in US datacenter
A deployment intended to reduce timeout errors (PR #39821) incorrectly addressed symptoms rather than root causes. While rolled back within 2 minutes, it triggered excessive parallelism and connection pool exhaustion, which manifested as massive data transfer from Postgres to Redis and a surge in concurrent connections that overwhelmed our cache layer. Redis memory exhaustion followed, leading to prolonged service degradation.
What "excessive parallelism" means: Under CPU pressure, degraded requests triggered Envoy retries between the load balancer and service. Each retry spawned new concurrent requests, and each request performed multiple concurrent Redis reads. A single degraded request could fan out to dozens of concurrent Redis operations. Combined with cache misses (on cache miss, we synchronously loaded full flag and team state from Postgres and wrote it into Redis), this created bursty write storms that overwhelmed Redis.
Connection pool mechanics: Each pod maintains its own Postgres connection pool. Creating a pool involves TLS handshakes, authentication, and initial connection establishment—operations that are computationally expensive, especially when pods are CPU-bound. Under CPU pressure exceeding 90%, new pods struggled to initialize these pools within the 20-second startup timeout, leading to crash loops and reduced healthy pod capacity.
Critical issue: The Redis overload from the flags service also impacted the main PostHog application, demonstrating dangerous coupling through shared infrastructure. The flags service can operate without Redis but falls back to heavier database queries, making responses slower.
Root causes:
Primary root cause: CPU resource undersizing – Nodes were too small relative to pod resource requests, causing Kubernetes to pack too many pods per node. This led to CPU saturation exceeding 90%, which caused excessive parallelism and connection pool exhaustion
Symptom-focused fix that didn't address underlying CPU sizing issues
Unbounded cache population logic with no rate limiting (on cache miss, synchronous full state load from Postgres to Redis)
Envoy retries → more concurrent /flags requests → more pool acquisitions + Redis reads → overload
Shared Redis instance between flags service and main application (critical infrastructure coupling)
Missing CPU alerting: No alerts existed for CPU pressure, preventing early detection
Lack of monitoring for Postgres-to-Redis transfer patterns
Timeline:
21:45 UTC – Deploy timeout handling change
21:47 UTC – Automated monitoring detects increased error rates
21:49 UTC – Immediate rollback initiated and completed
21:50 UTC – Error rates remain elevated despite rollback
22:30 UTC – Redis metrics show memory exhaustion on ElastiCache
22:35 UTC – Postgres connection spike observed, overwhelming connection pool
22:45 UTC – Discovery: Massive data transfer from Postgres to Redis in progress
22:50 UTC – Root cause identified: Excessive parallelism triggering cache population overload
22:50 UTC – Status page updated with incident details
23:00 UTC – Begin throttling connections and Redis writes
23:28 UTC – Service fully recovered
October 24, 2025 – Rate limiting misconfiguration
Duration: 18:00 to 19:12 UTC (72 minutes) Impact: ~97% of evaluation requests returning 429 (rate limit) errors worldwide
Deployed IP-based rate limiting (PR #40074) as a protective measure following Tuesday's incident. The tower-governor library (our Rust rate limiting middleware) saw all traffic as coming from a single IP (our load balancer) rather than actual client IPs, immediately triggering rate limits for all legitimate traffic.
Root causes:
Rate limiting implementation didn't account for load balancer architecture
Library's secure defaults (not trusting X-Forwarded-For headers) were inappropriate for our trusted infrastructure. We terminate TLS at the load balancer and route to the service over a private network, so trusting X-Forwarded-For from our own load balancer would have been safe; the default of ignoring it was wrong for our setup
No alerting configured for 429 errors, requiring customer reports for detection (62-minute detection delay)
We validated rate limiting only in direct-to-service tests, not behind our production load balancers
Timeline:
18:00 UTC – Deploy IP-based rate limiting to /flags endpoint
18:01 UTC – Rate limiter begins returning 429 errors for most requests
18:02 UTC – All traffic appears as single IP to rate limiter
18:10 UTC – Initial customer reports of widespread failures
18:30 UTC – More customer reports escalate urgency
18:45 UTC – Engineering begins investigation into customer reports
19:00 UTC – Team identifies 429 errors in logs
19:02 UTC – Root cause identified: rate limiter sees load balancer IP only
19:05 UTC – Decision to disable rate limiting immediately
19:12 UTC – Rate limiting disabled, service fully recovered
Note: Status page was not updated during this incident due to the rapid resolution timeline post-detection (detection to resolution in ~12 minutes)
October 28, 2025 – Connection pool exhaustion and excessive parallelism
Duration: 19:28 to 21:31 UTC (123 minutes) Impact: ~34% of evaluation requests failing in US datacenter
A routine deployment with no changes directly related to the flags service triggered a rollout of feature flag pods in the US region. New pods couldn't connect to Postgres within the 20-second startup timeout, entering crash loops due to excessive parallelism and connection pool exhaustion—the same root cause as October 21. Under CPU pressure, pods couldn't initialize Postgres connection pools (TLS handshakes, authentication, connection establishment) within the timeout. Simultaneously, a massive spike in Redis writes caused key evictions, effectively making the cache unavailable. While the flags service can operate without Redis (falling back to heavier database queries), with both cache unavailable and database under pressure, a significant portion of US traffic failed.
Critical issue: The Redis overload from the flags service also impacted the main PostHog application, highlighting dangerous infrastructure coupling. Unrelated deployments shouldn't trigger feature flags rollouts.
Root causes:
Primary root cause: CPU resource undersizing – Same root cause as October 21: nodes too small relative to pod requests, causing too many pods per node and CPU saturation
Unrelated deployment triggered feature flags pod rollout
New pods failing to connect to Postgres within 20s timeout under CPU pressure (connection pool initialization too slow)
Pods entering crash loops, reducing available capacity
Redis write storm during deployment causing key evictions (cache miss → synchronous full state load from Postgres to Redis)
Shared Redis instance between flags service and main application (critical infrastructure coupling)
Startup timeout too aggressive for production conditions under CPU pressure
Missing CPU alerting: No alerts existed for CPU pressure, preventing early detection
Timeline:
19:12 UTC – Routine deployment triggers feature flags pod rollout in US (no /flags code changes)
19:15 UTC – New US pods begin failing to connect to Postgres within 20s timeout
19:18 UTC – Pods enter crash loops, reducing available capacity in US
19:20 UTC – Massive spike in Redis writes begins in US region
19:23 UTC – On-call receives high error count alert, initiates incident
19:23 UTC – Status page updated with incident details
19:26 UTC – Main PostHog app begins experiencing issues due to shared Redis overload
19:28 UTC – Service degradation begins, ~34% of US requests failing
19:35 UTC – Team identifies dual failure: pod crashes + Redis overload
19:45 UTC – Decision to halt rollout and scale US pods to zero
20:00 UTC – US pods scaled to zero, waiting for Redis to stabilize
20:30 UTC – Redis begins recovering from write storm
20:53 UTC – Partial recovery as stable US pods brought back online
21:15 UTC – Gradual pod scaling continues in US
21:31 UTC – Full service restored, US region fully operational
Note: We initially attempted the same remediation approach from October 21 before implementing other solutions to decrease parallelism.
October 29-30, 2025 – CPU-bound latency
Duration: 22:30 UTC on October 29 to 05:39 UTC on October 30 (7 hours 9 minutes) Impact: Slow queries and degraded performance due to node CPU pressure
Query performance was impacted for over 7 hours. While queries were slow to both Redis and Postgres, metrics for both dependencies confirmed they were healthy. The slow queries were due to CPU pressure on the nodes, which exceeded 90%. This impacted connections and slowed response times for the service to several times the usual.
Root causes:
CPU pressure on nodes exceeding 90% (nodes too small relative to pod requests, causing too many pods per node)
Pod resource requests not properly sized, causing unhealthy distribution of pods per node
Critical gap: CPU alerting was completely missing – No alerts existed for CPU pressure, which allowed the issue to persist undetected for over 7 hours
Insufficient observability around CPU-bound failure modes
Timeline:
22:30 UTC (Oct 29) – Incident reported, increased error rates and latency detected
22:30 UTC (Oct 29) – Status page updated with incident details
00:03 UTC (Oct 30) – Rolled back hardware changes, errors mostly subsided but latencies persist
05:39 UTC – Incident resolved, query timings returned to normal
Resolution: After identifying connectivity issues due to resource exhaustion on feature flags nodes, we applied changes that resolved this resource exhaustion. Increasing pod resource requests for the flag service resulted in a healthier distribution of pods per node, which caused per-node CPU usage to go down and the service to return to a healthy state.
Root cause analysis
While each incident had specific triggers, three of the four incidents shared the same fundamental root cause:
CPU resource undersizing (primary root cause): Our nodes were too small relative to pod resource requests, causing Kubernetes to pack too many pods per node and saturate CPU capacity (exceeding 90%). This CPU saturation was the root cause of October 21, 28, and 29-30 incidents:
October 21 & 28: CPU saturation caused excessive parallelism (Envoy retries → concurrent requests → concurrent Redis reads) and connection pool exhaustion (pods couldn't initialize Postgres pools under CPU pressure), which manifested as Redis overload and database connection failures
October 29-30: CPU saturation directly caused slow queries and degraded performance, even though Redis and Postgres metrics showed healthy dependencies
Proper CPU right-sizing (fewer pods per node, better-resourced pods) resolved the underlying issues in all three incidents
Connection pool management complexity: Each pod maintains its own Postgres connection pool. Creating a pool involves TLS handshakes, authentication, and connection establishment—operations that are computationally expensive, especially when pods are CPU-bound. This complexity, combined with CPU saturation, exacerbated connection pool exhaustion issues.
Shared Redis is a critical single point of failure: Redis overload from the flags service impacted the main PostHog application, demonstrating dangerous coupling through shared infrastructure. Isolation is critical despite implementation complexity.
Critical monitoring gap: CPU alerting was missing: CPU alerting was completely absent throughout these incidents, preventing early detection of CPU saturation that was the root cause of three outages. This was a fundamental gap in our monitoring strategy that allowed CPU pressure to escalate unnoticed.
Unbounded retries: Unbounded retries in Envoy (between load balancer and endpoint) amplified failures (now fixed with retry limits)
Rate limiting misconfiguration (October 24 only): The October 24 incident was unrelated to CPU sizing—it was caused by rate limiting configuration that didn't account for load balancer architecture
Impact
Total major impact: Over 14 hours across four incidents (errors or severe latency)
Error rates: Ranging from 34% to 97% of requests during incidents
Service degradation: All flag types affected, including read-only evaluations
Cross-service impact: Redis overload from flags service affected main PostHog application
Customer impact: HTTP 429, 504 errors and degraded performance regardless of flag configurations
Recurring issues: Connection pool exhaustion and excessive parallelism occurred twice (October 21 and 28), indicating insufficient initial remediation
Remediation
Immediate actions (completed)
Configuration externalization: Database connection timeouts and other critical settings moved to runtime configuration
Timeout adjustments: Values increased to accommodate peak load scenarios
Rate limiting fixes: Fixed rate-limiting configuration that caused October 24 incident (configured tower-governor to trust X-Forwarded-For from our load balancer)
Retry limits: Implemented retry limits in Envoy (between load balancer and endpoint) to prevent unbounded retry amplification
CPU and infrastructure right-sizing (critical fix): Increased pod resource requests and adjusted Kubernetes fleet size to reduce pods per node. This was the primary remediation for three of the four incidents (October 21, 28, and 29-30), addressing the root cause of excessive parallelism, connection pool exhaustion, and CPU-bound latency. Running smaller fleets with better-resourced pods rather than larger fleets with CPU-bound pods.
CPU alerting: Added per-node and per-pod CPU alerts with thresholds at 80% sustained for 5 minutes, paging on-call
Observability improvements: Added monitoring for previously invisible failure modes
Strike team formation: Engineers from flags, ingestion, and infrastructure teams conducting comprehensive review of application and infrastructure to identify remaining bottlenecks
Redis isolation: Investigating decoupling flags Redis instance from application Redis instance to prevent cross-service impact
To complete before re-enabling ArgoCD sync:
Evaluate current state of synced flags deployment and ensure durability against future outages
Update flags service charts config to match values currently in ArgoCD
Define deployment strategy for short-term (considering deployment vs rollout to avoid 503s)
Define and implement Redis strategy
Establish feature flags team as hard code-owners for flags-related code
Medium-term improvements
Incident response and monitoring:
Build high-level dashboard of important flag metrics with runbook links
Implement rollout/annotation controls to disable staged rollouts and enable "force-merge" for rolling changes
Update feature flag runbooks with dashboard links and deeper investigation paths
Add missing alerts against existing service/infrastructure level metrics
Update readiness checks to validate dependencies that degraded under load (e.g., ping database instead of mirroring liveness checks)
Architectural improvements:
Rate limiting for cache operations: Prevent Redis overwhelm from cache population
Connection pool monitoring: Automatic throttling when pools approach exhaustion
Load testing framework: Production-scale testing to catch load-dependent issues before deployment
Progressive rollout infrastructure: Gradual deployments to limit blast radius
Deployment strategy evolution: Re-evaluate rollout vs deployment approaches with programmatic controls
Comprehensive monitoring: Document Postgres-to-Redis data flow patterns and create runbooks for data transfer storm scenarios
Lessons learned
What went well
Rapid detection – Monitoring caught issues within 2 minutes in most cases
Quick initial response – Rollbacks executed immediately when possible
Systematic investigation – Teams methodically identified overload patterns
Cross-team collaboration – Flags, infrastructure, and ingestion teams worked together effectively
What didn't go well
Symptom-focused fixes – Multiple PRs addressed symptoms rather than root causes
Unbounded operations – No limits on retries, cache population, or connection creation
Rollback insufficiency – Data transfers and resource exhaustion persisted after code reverted
Complex failure modes – Interactions between database, cache, and application layers not well understood
Shared infrastructure – Flags service overloads impacted main application
Customer comms – While we generally did a good job of making public-facing status pages during each one of these incidents, one notable gap was that we never made an externally-facing status page update for the rate-limiting incident on October 24th.
Diagnosis delays – Took significant time to connect symptoms to root causes
Missing CPU alerting – CPU alerting was completely absent, allowing CPU pressure to escalate undetected for hours
Key takeaways
CPU right-sizing is fundamental – The biggest takeaway: nodes were too small relative to pod resource requests, causing Kubernetes to pack too many pods per node and saturate CPU capacity. This CPU saturation led to excessive parallelism (Envoy retries → concurrent requests → concurrent Redis reads), connection pool exhaustion (pods couldn't initialize Postgres pools under CPU pressure), and slow queries. Right-sizing (fewer pods per node, better-resourced pods) addressed the underlying issues that caused October 21, 28, and 29-30 incidents. This must be a primary consideration for any service deployment.
Connection pool management architecture matters – Each pod maintains its own Postgres connection pool. Creating a pool involves TLS handshakes, authentication, and connection establishment—operations that are computationally expensive, especially when pods are CPU-bound. This complexity, combined with CPU saturation, exacerbated connection pool exhaustion. Better approach: reduce concurrency and run smaller fleets with better-resourced pods rather than larger fleets with CPU-bound pods.
Shared Redis is a critical single point of failure – When flags service overloads Redis, it takes down the main app too. This was evident in October 21 and 28 incidents where Redis overload from flags service impacted the main PostHog application. Isolation is critical despite implementation complexity.
CPU alerting was completely missing – CPU alerting was absent throughout these incidents, preventing early detection of CPU saturation that was the root cause of three outages. This was a fundamental gap in our monitoring strategy. CPU metrics must be monitored and alertable from day one.
Monitor data flow patterns – Postgres-to-Redis transfer spikes should trigger alerts. Watch for unusual data movement.
Test under load – Overload patterns only appeared under production traffic. Load testing is non-negotiable.
Progressive rollouts save lives – Gradual deployments limit blast radius and enable rapid detection. We're implementing rollout/annotation controls to disable staged rollouts and enable "force-merge" for rolling changes.
Configuration must be flexible – Critical settings must be adjustable without full deployment cycles.
Unbounded retries amplify failures – Retries without bounds in Envoy (between load balancer and endpoint) can cascade failures. We've implemented retry limits to prevent this.
Moving forward
These four incidents highlighted critical gaps in our defensive architecture and operational procedures. The compounding failures demonstrated that our service needed fundamental improvements, not just quick fixes. The primary root cause—CPU resource undersizing (nodes too small relative to pod requests, causing too many pods per node)—manifested differently across three incidents (October 21, 28, and 29-30), requiring us to recognize that excessive parallelism, connection pool exhaustion, and slow queries were all symptoms of the same underlying issue. The recurrence of these symptoms between October 21 and 28 showed that we needed to address the root cause (CPU sizing) rather than the symptoms. We initially attempted the same remediation approach from October 21 before implementing CPU right-sizing, which resolved the underlying issues.
We've implemented immediate remediations and are executing a comprehensive review of the entire service architecture. Our strike team is systematically identifying and addressing remaining bottlenecks. Once we complete the short-term improvements tracked in GitHub Issue #40885, we'll have confidence that the service is durable against future outages.
The architectural improvements underway—including Redis isolation, connection pool management, and comprehensive monitoring—will prevent similar cascading failures in the future. We're committed to ensuring the feature flags service meets the reliability standards our customers expect.
Between November 11 and November 15, 2025 we hit a Postgres limit that required us to migrate our Persons database for US Cloud. This led to ingestion delays which had a knock-on effect for products relying on person data, including feature flags and experiments.
This post-mortem document examines the root cause of the issue, steps taken, and our future plans derived from the lessons learned.
Incident summary
From November 11, 4:02 PM UTC to November 14, 3:02 PM UTC the performance of PostHog's ingestion processing pipeline became severely degraded, resulting in processing delays of events of up to 2 days for all customers in the US region.
The root cause of the performance degradation was that our Postgres database responsible for storing our Person information reached a previously unseen limits in Postgres related to the JSONb field we use to store person properties. This led to a state where writes to the database kept waiting for OIDs in the TOAST table to become available, which could take multiple seconds per update, slowing down the ingestion pipeline to the point where there were no standard scaling options available. See Root Cause Analysis below for more technical details.
The root cause was not identified until November 12th 10:17pm UTC, a day and a half after the issue arose. We enlisted help from engineers on the AWS RDS team and external consultants to identify the cause. Diagnosis proved difficult even with specialist support, but we eventually found out we were left with only one option: migrate to a new partitioned table.
By November 14, 2025, 15:02 UTC, ingestion was healthy again and we shifted focus to the accumulated backlog. During this recovery phase, we hit a secondary issue with AWS MSK (Kafka): local disk usage reached 85% because tiered storage keeps the most recent 4 hours of data on disk before offloading to S3. The backlog catchup created an unusually dense last-4-hours window, driving up local disk usage. We temporarily paused ingestion, reduced the topic's local retention window, confirmed disk headroom, and then resumed ingestion.
After that, catchup progressed smoothly. We moved our backfill into Dagster to gain better visibility and stability for long-running backfill jobs, knowing remediation would take at least the weekend. By the morning of November 15, all events since the start of the incident had been processed, all systems were fully operational, and we began a background backfill of older Person data purely for housekeeping. No data was lost.
By November 15, 6:20 AM UTC we had worked through the backlog of events and fully recovered.
Incident impact
Scope
This issue only impacted US Cloud
Time window of degraded ingestion performance: Approximately November 11, 16:02 UTC – November 14, 15:02 UTC
Time to fully process backlog and complete recovery: Until November 15, 06:20 UTC
Customers experienced ingestion delays ranging from 10 minutes to up to 2 days. During this period recent events sent to PostHog did not appear, leading to the following potential per-product impact:
Analytics: Charts and queries which included recent time ranges would be inaccurate due to data from the incident period not being present. Customers were still able to analyze historical data.
Feature flags and Experiments: The flag evaluation service continued to operate, however flags that relied on person properties would have had delays in those properties being used to evaluate feature flags.
Error tracking and Session replay: Ingestion of errors and replays remained healthy. Filtering and segmentation based on Person updates was affected similarly to Analytics.
CDP & Workflows: Destinations and Workflows reliant on Persons were affected similarly to Feature Flags. Downstream actions were delayed and should have been automatically corrected as the backlog was processed.
Data integrity
No data was lost.
Once the backlog was cleared, all reporting tools indicate accurate values were processed for the delayed period.
PostgreSQL stores large column values (>2KB compressed) in a separate, out-of-line table, called the TOAST table. Posthog's Persons table has a properties column that frequently exceeds this 2KB threshold, resulting in there being many TOASTed values associated with the Persons table.
Each value that is moved "out of line" is assigned a unique OID (Object identifier) from a finite 32-bit space (~4 billion values), that the main table uses to track it in the table's associated TOAST table.
The OIDs used for this purpose are generated from a global counter that wraps around every 4 billion values, so that from time to time an already-used value will be generated again. Postgres detects that, and tries again with the next OID.
When the space of used OIDs approaches the limit, there will be longer and longer sequential runs of used OIDs. This results in the database engine having to do an incredible amount of reads (checking every used OID it is given by the counter to see if it's free or not) to make a single INSERT or UPDATE for a TOAST'ed row.
It is important to note that before the table hits the hard limit of 4 billion OIDs, write performance for TOAST'ed rows will be severely degraded, because the space of available OIDs is so sparse. If there is just a single free OID left, the database engine would, on average, have to read through billions of used OIDs and check to see if they are free, before it finds the free OID to complete the write. This OID exhaustion increased the amount of disk reads we were doing per write query from 10kb to 15MB, increasing latency for those queries by 100x and grinding the ingestion of events to a halt.
Secondary issue: AWS MSK disk pressure during catch-up
During backlog processing, we hit a separate but related operational issue:
Our AWS MSK cluster uses tiered storage, keeping the most recent 4 hours of data on local disk before offloading to S3.
As we processed the backlog, the amount of data in the "last 4 hours" window became unusually large.
This pushed local disk utilization up to ~85%, triggering alerts.
To mitigate this we paused ingestion, reduced the local retention configuration for the relevant topic, and resumed ingestion once disk usage returned to a safe level.
Appendix: OID exhaustion diagrams
Stage 1: Healthy database state
OID Space ( each block = used OID, each dash = free OID) [----------------------------------------------------] 0-1M OIDs [-----XX-----------------------XX---------------------] 1M-2M OIDs [---------XX--------------------------XX--------------] 2M-3M OIDs [----------------------------------------------------] 3M-4M OIDs ↑ Next OID Counter (finds free OID immediately)
Stage 2: OID exhaustion
OID Space (each block = used OID, each dash = free OID) [XXXXXXXXXXXXXXX--XXXXXXXXX--XXXXXXXXXXXXXX--XXXXXXX] 0-1M OIDs [XXXXXXXXXXXXXXXXXXXXXXXX----XXXXXXXXXXXXXXXXXXXXXX--XX] 1M-2M OIDs [XXXXXXXXXX--XXXXXXXXXXXXXXXXXXXXXXXXXXX--XXXXXXXXXXXXX] 2M-3M OIDs [XXXXXXXXXXXXXXXXXXXX----XXXXXXXXXXXXXXXXXXXXXXXXXXX--X] 3M-4M OIDs ↑ Next OID Counter (must skip over many used OIDs, each skip requiring disk reads)
Why was this hard to detect?
PostgreSQL's OID exhaustion behavior is rare and not commonly encountered even at large scale. Additionally, standard dashboards (CPU, memory, IOPS, lock contention) did not immediately point at OID exhaustion.
Diagnosis of the issue was also frustrated by a lack of dedicated observability on:
TOAST table size / OID usage
Disk read amplification per write on specific tables
Eventual diagnosis was only possible due to the dedicated effort of our engineers working in tandem with external experts and AWS engineers to connect:
Massive read amplification
Specific pattern of TOAST usage
A nearly exhausted global OID space
Remediation
Immediate actions (completed)
Root cause discovery and isolation
We Identified TOAST OID exhaustion as the root cause by engaging internal teams, external consultants, and AWS engineers to analyze:
Query plans
Disk read amplification
TOAST and OID behavior for the persons table
Migration to a new partitioned Persons table
Created a new partitioned table architecture for Persons with a fresh TOAST table and OID space.
Implemented database triggers to keep old and new tables in sync for live writes.
Ran a backfill script to copy existing Person data from the old table to the new table.
Modified ingestion and application logic so that:
All new writes go to the new table.
Reads go to the new table first, with fallback to the old table during the migration window.
Careful deployment of application changes
Given the risk of introducing new issues during an incident, we chose a manually controlled deploy to production for the web app rather than a fully automated rollout. Multiple engineers worked in shifts throughout the weekend and made changes across:
Feature flags API
Error tracking ingestion
Django web application
Scaling ingestion to clear backlog
Once ingestion performance was restored on the new Persons table, we scaled ingestion workers to process the accumulated backlog while monitoring:
Lag per partition
Throughput
Resource utilization
MSK disk pressure mitigation
Paused ingestion temporarily when MSK local disk hit ~85% usage.
Reduced local retention for the affected Kafka topic so less data needed to be stored on disk before offloading to S3.
Resumed ingestion after confirming sufficient headroom.
Dagster-based backfill
We moved the backfill process into Dagster to provide:
Better monitoring and visibility
More robust handling of long-running backfill jobs
Used Dagster to complete the remaining backfill and housekeeping tasks over the weekend.
Final cleanup and confirmation
Communicated final resolution and announced a small upcoming maintenance window to consolidate on the new tables. We verified that:
All event backlogs had been processed.
Services were reading correctly from the new Persons table (with safe fallback while the old table still existed).
Planned actions (planned or in-progress)
Deeper Postgres engine monitoring
We plan to add metrics and alerts around:
Heavy disk read amplification per write
TOAST table statistics
Other engine limits that may become relevant at large scale
Improved runbooks for engine-level limits
We plan to document symptoms and diagnostics for similar Postgres engine-level issues. This will include clear decision trees for when to migrate vs repair-in-place.
Improved and new runbooks for customer comms
We have begun creating new customer communication runbooks which clarify how and when to communicate with customers about the issue and provide a clear escalation path and redundancies.
Exploring other data stores
We've been exploring using other data stores for the persons database and will continue to evaluate those.
Lessons learned
What went well?
Data integrity remained intact
We preserved all incoming events and persons data. While delayed, data was not lost.
Coordinated multi-team response
Engineers across ingestion, infrastructure, and application teams, plus external consultants and AWS engineers, collaborated effectively to diagnose a rare engine-level problem.
Safe migration under load
We successfully migrated to a new Persons table using triggers and backfill while the system remained live, minimizing additional downtime.
Transparent customer communication
We provided regular engineer-led status updates and committed to a public post-mortem.
What could have gone better?
Diagnosis took too long
It took roughly a day and a half to conclusively identify OID exhaustion as the root cause. We had no dedicated monitoring for TOAST growth, OID usage, or disk read amplification per write.
Single critical dependency on Persons
Many core features (analytics, flags, replay filters, CDP) rely heavily on timely updates to the persons table. When that became unhealthy, a wide surface area of the product was affected.
Backfill visibility and tooling
Our initial backfill approach lacked the visibility and robustness needed for a prolonged, large-scale migration. We had to move this logic into Dagster during the incident.
MSK disk pressure during catch-up
While secondary to the main cause, disk pressure on MSK during catch-up highlighted that our tiered storage configuration and alerting were not tuned for large backlog scenarios.
Lack of communication redundancies
All of the team members who are normally responsible for customer communications were unavailable for the duration of this incident and we had to scramble to identify fallbacks.
Moving forward
This incident surfaced a rare but serious interaction between our data model and a low-level PostgreSQL engine limit. It also highlighted how central the Persons data model is to the rest of PostHog: when the persons table slowed down, a wide range of features---from analytics and feature flags to replay filtering and CDP---were indirectly impacted.
We've taken immediate steps to recover by migrating to a new partitioned Persons table, stabilizing ingestion, and clearing the backlog of events. We are now focused on:
Completing reconsolidation on the new tables
Hardening observability and alerting around TOAST/OID behavior and disk read amplification
Improving our backfill tooling and Kafka tiered storage safeguards
Proactively designing and operating Person-like tables in a way that avoids similar limits in the future
We're committed to continuing to invest in the resilience of our ingestion and Persons infrastructure so that incidents like this become less likely, easier to detect early, and faster to remediate when they do occur.
At 4:11 AM UTC on November 24th, a number of our SDKs and other packages were compromised, with a malicious self-replicating worm – Shai-Hulud 2.0. New versions were published to npm, which contained a preinstall script that:
Scanned the environment the install script was running in for credentials of any kind using Trufflehog, an open-source security tool that searches codebases, Git histories, and other data sources for secrets.
Exfiltrated those credentials by creating a new public repository on GitHub and pushing the credentials to it.
Used any npm credentials found to publish malicious packages to npm, propagating the breach.
By 9:30 AM UTC, we had identified the malicious packages, deleted them, and revoked the tokens used to publish them. We also began the process of rolling all potentially compromised credentials pre-emptively, although we had not at the time established how our own npm credentials had been compromised (we have now, details below).
The attack only affected our Javascript SDKs published in npm. The most relevant compromised packages and versions were:
posthog-node 4.18.1, 5.13.3 and 5.11.3
posthog-js 1.297.3
posthog-react-native 4.11.1
posthog-docusaurus 2.0.6
posthog-react-native-session-replay@1.2.2
@posthog/agent@1.24.1
@posthog/ai@7.1.2
@posthog/cli@0.5.15
What should you do?
Our recommendations are to:
Look for the malicious files locally, in your home folder, or your document roots:
Pin any dependencies to a known-good version (in our case, all the latest published versions, which have been published after we identified the attack, are known-good), and then reinstall your dependencies.
We also suggest you make use of the minimumReleaseAge setting present both in yarn and pnpm. By setting this to a high enough value (like 3 days), you can make sure you won't be hit by these vulnerabilities before researchers, package managers, and library maintainers have the chance to wipe the malicious packages.
How did it happen?
PostHog's own package publishing credentials were not compromised by the worm described above. We were targeted directly, as were a number of other major vendors, to act as a "patient zero" for this attack.
The first step the attacker took was to steal the Github Personal Access Token of one of our bots, and then use that to steal the rest of the Github secrets available in our CI runners, which included this npm token. These steps were done days before the attack on the 24th of November.
At 5:40PM on November 18th, now-deleted user brwjbowkevj opened a pull request against our posthog repository, including this commit. This PR changed the code of a script executed by a workflow we were running against external contributions, modifying it to send the secrets available during that script's execution to a webhook controlled by the attacker. These secrets included the Github Personal Access Token of one of our bots, which had broad repo write permissions across our organization. The PR itself was deleted along with the fork it came from when the user was deleted, but the commit was not.
The PR was opened, the workflow run, and the PR closed within the space of 1 minute (screenshots include timestamps in UTC+2, the author's timezone):
Image: initial PR logs
At 3:28 PM UTC on November 23rd, the attacker used these credentials to delete a workflow run. We believe this was a test, to see if the stolen credentials were still valid (it was successful).
At 3:43 PM, the attacker used these credentials again, to create another commit masquerading, by chance, as the report's author (we believe this was a randomly chosen branch on which the author happened to be the last legitimate contributor given that the author does not possess any special privileges on his GitHub account).
This commit was pushed directly as a detached commit, not as part of a pull request or similar. In it, the attacker modified an arbitrary Lint PR workflow directly to exfiltrate all of our Github secrets. Unlike the previous PR attack, which could only modify the script called from the workflow, and as such could only exfiltrate our bot PAT, this commit had full write access to our repository given the ultra-permissive PAT which meant they could run arbitrary code on the scope of our Github Actions runners.
With that done, the attacker was able to run their modified workflow, and did so at 3:45 PM UTC:
Image: Follow up commit workflow runs
The principal associated with these workflow actions is posthog-bot, our Github bot user, whose PAT was stolen in the initial PR. We were only able to identify this specific commit as the pivot after the fact using Github audit logs, due to the attackers deletion of the workflow run following its completion.
At this point, the attacker had our npm publishing token, and 12 hours later, at 4:11 AM UTC the following morning, published the malicious packages to npm, starting the worm.
As noted, PostHog was not the only vendor used as an initial vector for this broader attack. We expect other vendors will be able to identify similar attack patterns in their own audit logs.
Why did it happen?
PostHog is proudly open-source, and that means a lot of our repositories frequently receive external contributions (thank you).
For external contributions, we want to automatically assign reviewers depending on which parts of our codebase the contribution changed. GitHub's CODEOWNERS file is typically used for this, but we want the review to be a "soft" requirement, rather than blocking the PR for internal contributors who might be working on code they don't own.
We had a workflow, auto-assign-reviewers.yaml, which was supposed to do this, but it never really worked for external contributions since it required manual approval defeating the purpose of automatically tagging the right people without manual interference.
One of our engineers figured out this was because it triggered on: pull_request which means external contributions (which come from forks, rather than branches in the repo like internal contributions) would not have the workflow automatically run. The fix for this was changing the trigger to be on: pull_request_target, which runs the workflow _as it's defined in the PR target repo/branch_, and is therefore considered safe to auto-run.
Our engineer opened a PR to make this change, and also make some fixes to the script, including checking out the current branch, rather than the PR base branch, so that the diffing would work properly. This change seemed safe, as our understanding of on: pull_request_target was, roughly, "ok, this runs the code as it is in master/the target repo".
This was a dangerous misconception, for a few reasons:
on: pull_request_target only ensures the _workflow_ is being run as defined in the PR target, not the code being run – that's controlled by the checkout step.
This particular workflow executed code from within the repo – a script called assign-reviewers.js, which was initially developed for internal (and crucially, trusted) auto-assignment, but was now being used for external assignment too.
The workflow was modified to manually checkout the git commit of the PR head, rather than the PR base, so that the diffing would work correctly for external contributions, but this meant that the code being run was controlled by the PR author.
These pieces together meant it was possible for a pull request which modified assign-reviewers.js to run arbitrary code, within the context of a trusted CI run, and therefore steal our bot token.
Why did this workflow change get merged? Honestly, security is unintuitive.
The engineer making the change thought pull_request_target ensured that the version of assign-reviewers.js being executed, a script stored in .github/scripts in the repository, would be the one on master, rather than the one in the PR.
The engineer reviewing the PR thought the same.
None of us noticed the security hole in the month and a half between the PR being merged and the attack (the PR making this change was merged on the 11th of September). This workflow change was even flagged by one of our static analysis tools before merge, but we explicitly dismissed the alert because we mistakenly thought our usage was safe.
Workflow rules, triggers and execution contexts are hard to reason about – so hard to reason about that Github is actively making changes to make them simpler and closer to our understanding above. Although, in our case, these changes would not have protected us against the initial attack.
Notably, we identified copycat attacks on the following day attempting to leverage the same vulnerability, and while we prevented those, we had to take frustratingly manual and uncertain measures to do so. The changes Github is making to the behaviour of pull_request_target would have prevented those copycats automatically for us.
How are we preventing it from happening again?
This is the largest and most impactful security incident we've ever had. We feel terrible about it, and we're doing everything we can to prevent something like this from happening again.
I won't enumerate all the process and posture changes we're implementing here, beyond saying:
We've significantly tightened our package release workflows (moving to the trusted publisher model).
Increased the scrutiny any PR modifying a workflow file gets (requiring a specific review from someone on our security team).
Switched to pnpm 10 (to disable preinstall/postinstall scripts and use minimumReleaseAge).
Re-worked our Github secrets management to make our response to incidents like this faster and more robust.
PostHog is, in many of our engineers minds, first and foremost a data company. We've grown a lot in the last few years, and for that time, our focus has always been on data security – ensuring the data you send us is safe, that our cloud environments are secure, and that we never expose personal information. This kind of attack, being leveraged as an initial vector for an ecosystem-wide worm, simply wasn't something we'd prepared for.
At a higher level, we've started to take broad security a lot more seriously, even prior to this incident. In July, we hired Tom P, who's been fully dedicated to improving our overall security posture. Both our incident response and the analysis in this post-mortem simply wouldn't have been possible without the tools and practices he's put in place, and while there's a huge amount still to do, we feel good about the progress we're making. We have to do better here, and we feel confident we will.
A customer reported a critical issue in the PostHog SDK's Fetch API wrapper that rendered their site unusable. The issue had started a week earlier and was caused by the wrapper failing to pass the RequestInit object through to window.fetch, resulting in a TypeError for requests with a ReadableStream body.
Two SDK releases were made in an attempt to fix this bug. However, both introduced different but related regressions affecting other customers. Because the changes were in the lazy-loaded Replay extension rather than the core SDK, the issues also impacted customers who had not updated their SDK during this period.
After these regressions were reported, a bugfix release (1.327.0) was prepared. When this failed to resolve the issues, a follow-up release (1.328.0) rolled back all fetch wrapper changes.
Due to a recently introduced manual step in the process for publishing SDKs to the PostHog CDN, neither the bugfix nor the rollback was actually deployed. As a result, even customers pinned to version 1.328.0 continued to receive the broken lazy-loaded script from the CDN. The issue persisted for an additional two days until the missing deployment was identified and completed.
The original customer issue remains unresolved, but the customer has been provided with a temporary workaround.
Impact
At least 6 customers reported issues with the PostHog SDK after the changes were released, not including the customer that reported issues with the SDK initially
At least 4 customers reported critical issues with their production systems
Customers were forced to remove the PostHog SDK entirely to restore functionality if they did not identify that only network header/body capture needed to be disabled
The issue persisted across 5 SDK versions (1.323.0 – 1.328.0)
Even customers who use a fixed SDK version and did not update the SDK during this incident were affected
Timeline
| Time (UTC) | Event | |------------|-------| | Jan 14, 10:18 AM | A customer reached out to inform us that they had removed the PostHog SDK from their site as it was causing fetch requests to fail with a TypeError. They had first become aware of this issue a week prior and this was a high-severity issue for them that rendered their site unusable. | | Jan 15, 5:33 PM | A new version (1.323.0) of the PostHog SDK was released with an attempted fix for the TypeError issue. | | Jan 16, 5:44 AM | The customer informed us that the fix in version 1.323.0 was not effective. | | Jan 16, 12:52 PM | A new version (1.325.0) of the PostHog SDK was released with an amended fix for the TypeError issue. | | Jan 17, 3:31 AM | Another customer reached out to inform us that their site was down due to issues with the integrity of fetch requests and that disabling PostHog immediately caused the issues to resolve. | | Jan 17, 6:43 AM | A GitHub issue was submitted describing an issue with the fetch wrapper in the PostHog SDK causing mismatched FormData boundaries. | | Jan 17, 8:43 AM | A new version (1.327.0) of the PostHog SDK was released with a fix for the mismatched FormData boundaries. | | Jan 17, 7:38 PM | More customer reports of critical issues with the fetch wrapper in the PostHog SDK surfaced and the decision was made to roll back all recent changes. | | Jan 17, 8:13 PM | A new version (1.328.0) of the PostHog SDK was released, undoing all recent changes to the fetch wrapper, restoring it to the last known working version. | | Jan 19, 4:04 PM | We became aware that the SDK version bump had not been merged into the primary PostHog repository, meaning that even for customers who had pinned their SDK version to 1.328.0, the faulty lazy-loaded script was still being served by our CDN and was still causing issues. |
Root cause
The initial issue was caused by the SDK fetch wrapper being too simplistic and not passing on request options that are sometimes required – specifically any request with a body of type ReadableStream must include the request option duplex: half or duplex: full on all modern browsers. Even if the customer site _does_ provide this option, the fetch wrapper does not pass it down to the original window.fetch method, resulting in a TypeError.
The fixes that were introduced to attempt to address this caused another issue. The updated fetch wrapper was creating a new Request object and passing both this object _and_ the request options to downstream wrappers and window.fetch. This was causing the request body to be consumed multiple times which is not a problem for most requests but which results in mismatching boundaries for FormData requests. When the FormData boundaries do not match, the request is typically rejected by the server.
A fix for this issue was released (1.327.0) but due to the missing manual approval step, this fix was never actually deployed to the CDN. Customers continued to report problems and, believing the fix to be ineffective, the decision was made to roll back all changes to the fetch wrapper rather than attempt to diagnose further.
The decision to roll back was delayed due to a lack of understanding of the scope of the issue – ultimately we had to rely on reports from customers to get the full picture. This also contributed to the incident not being handled within the usual incident response process.
The incident was prolonged because a recently introduced process requiring manual intervention to publish SDK releases to the PostHog CDN was not followed. There was no verification step to confirm that releases were successfully deployed to the CDN. As a result, the bugfix (1.327.0) and rollback (1.328.0) releases were never actually served to customers.
Resolution
All recent changes to the fetch wrapper were reverted, including on the CDN, restoring it to the simple, original implementation:
const req = new Request(url, init)
return originalFetch(req)
The original TypeError issue remains.
Insights
Fetch wrapper changes are high-risk: The fetch API is fundamental to web applications; changes require extensive testing across diverse use cases, which our current test suite does not fully cover.
Use feature flags for high-risk changes: Feature flags would have enabled rapid rollback without requiring a new release.
Issues with the SDK can be hard to detect: Unlike issues with our backend systems, we do not get alerts when the SDK fails and so we relied entirely on customer feedback.
There should never be a mismatch between the latest SDK version deployed to NPM and the latest version being served up by our CDN: This is a sign that something has gone wrong in the release process.
Multiple fix attempts signal deeper issues: When fixes don't resolve the problem, step back to understand the root cause rather than iterating on partial solutions.
Changes to lazy-loaded SDK extensions affect all customers: We only test changes to the SDK extensions with the latest version of the core SDK but then we release it to customers running (much) older versions of the core SDK, without testing.
Action items
We are committed to:
Adding comprehensive integration tests for fetch wrapper with FormData, ReadableStream, and chained wrappers
https://github.com/PostHog/posthog-js/pull/2935
https://github.com/PostHog/posthog-js/pull/2936
Establishing a more robust testing strategy for the PostHog SDK – we should test lazy loaded extensions with _all_ past versions of the core SDK or implement a way to pin a version of the extensions
Implementing monitoring and alerting for SDK errors – consider tracking SDK exception rates, failed network requests, or other client-side signals in PostHog itself to detect issues proactively rather than relying on customer reports
Documenting and communicating SDK release process changes to the team
Adding an automated verification step to confirm releases are successfully deployed to the CDN
Implementing an automated notification polling on-call engineers to manually approve new SDK releases
Implement an easier mechanism for customers to opt in to lazy loading without opting in to auto-updating
Between February 2-6, 2026, PostHog's feature flags cache workers experienced escalating memory pressure, resulting in degraded cache update reliability. The issue was stabilized on February 6 at 22:34 UTC.
Summary
When a feature flag is updated, PostHog kicks off two Celery tasks: one to update the cache used by the /flags evaluation endpoint, and another to update flag definitions fetched by SDKs using local evaluation. Both tasks run on the same pool of Celery workers.
These workers experienced escalating out-of-memory (OOM) kills over a 4-day period, causing both caches to fall behind. Teams that updated flag rollout conditions or targeting rules would see those changes reflected in the PostHog UI but not propagated to the /flags endpoint or SDKs using local evaluation until the cache backlog cleared.
The root cause was an internal test automation system that had accumulated excessive test data over several months, creating cache update tasks that exceeded worker memory limits.
Timeline
All times in UTC.
Feb 2-5 – Intermittent OOM kills observed on feature-flags Celery workers; initially appeared low-severity
Feb 6 20:31 – Incident declared as OOMs escalate and 116k task backlog discovered
Feb 6 21:34 – Root cause identified
Feb 6 22:34 – Stabilized: OOMs reduced to 0-2 per 5 minutes, backlog clearing
Feb 7 – Internal test automation updated to use isolated environment
Feb 8 – Stale test data cleaned up
Root cause analysis
Accumulated test data
An internal test automation system had been running against production for several months. Due to a bug in test cleanup logic, failed test runs left behind test data that accumulated over time. This created an internal account with far more data than any typical customer workload.
No batching in cache updates
The cache update task loads all data into memory at once — flag definitions, cohorts, serialized representations, and the final JSON payload. For typical workloads this is fine, but the accumulated test data created tasks that exceeded the 8GB worker memory limit on a single execution. Each task for this account required holding all the data in memory simultaneously, causing immediate OOM kills regardless of worker age or prior memory state.
Impact
Stale flag evaluations: Both the /flags endpoint and SDKs using local evaluation could serve stale flag definitions when cache updates were delayed
No data loss: Flag definitions remained intact in the database; only cache freshness was affected
No downtime: Both the /flags endpoint and local evaluation continued responding to requests, but could return outdated results
Duration: Degraded reliability over ~4 days. Majority stabilized on Feb 6 with increased memory limits; intermittent issues continued until stale test data was cleaned up on Feb 8
Detection
The incident was detected through monitoring showing OOM kills escalating on the feature-flags Celery workers. The 116k task backlog was discovered during investigation.
OOMs were observable in the days prior, but the root cause wasn't investigated deeply at first because the numbers were low and seemed intermittent. Initial mitigation attempts focused on isolating the task to a dedicated queue and optimizing memory usage, but these didn't address the underlying issue.
It wasn't until a colleague noticed a team with an abnormal amount of data that the root cause was identified.
Recovery
Increased memory limits for workers
Enabled worker recycling (max_tasks_per_child=100) to give workers more headroom
Reduced worker load by pausing non-critical tasks
Purged backlogged tasks from the queue
Cleaned up stale test data (the actual fix)
Remediation
Completed
Cleaned up stale test data from internal account
Enabled worker recycling to provide more memory headroom
Added dashboard panels for worker health monitoring and queue backlog visibility
Fixed test cleanup bug to register resources before assertions
Updated internal test automation to use an isolated environment
In progress
| Follow-up | Priority | |-----------|----------| | Better alerts, metrics, and visualizations for celery queue backlogs | High | | Add metrics for anomalous workloads | Medium | | Task deduplication for cache updates | Medium | | Improve memory usage of cache update task | High | | Merge flag caches into a single cache build | Medium |
Lessons learned
What went well
Once we started investigating, we updated the status page and made regular updates
Once the root cause was identified, stabilization was achieved within ~90 minutes
The immediate fix (max_tasks_per_child) combined with increased memory limits was simple and effective
No customer data was lost; the issue only affected cache freshness
The long-term fix (cleaning up stale test data) brought us back to normal operations
What went poorly
The gradual escalation over several days wasn't investigated deeply until the backlog became severe
OOM metrics can be misleading—pods in crash loops don't generate OOMs during backoff periods, creating a false sense of improvement
Internal test automation running against production accumulated data invisibly over months
Key takeaways
Unbounded data loading is risky: Operations that load all data into memory work fine for typical workloads but can fail catastrophically for outliers. Consider batching or streaming for tasks that scale with customer data.
Correlate OOMs with pod health: A drop in OOM kills might mean workers are healthy, or it might mean they're stuck in crash loops and not processing anything. Always check pod status alongside OOM metrics.
Isolate test environments: Even with cleanup logic, test automation against production will eventually accumulate artifacts. Use isolated environments for integration testing.
Monitor queue backlogs: We had visibility into OOMs but not the growing task backlog. Better queue monitoring would have surfaced the issue sooner.
On February 19th, PostHog's Logs product experienced a major incident, which caused the loss of data collected more than 3 days ago in our US region. This data loss only impacted the Logs product, all other PostHog data is intact.
Summary
As with most queryable data in PostHog, we store data for Logs in a ClickHouse cluster. When we started building Logs, we decided to use a new, dedicated cluster, rather than building it on top of our main ClickHouse cluster, which is shared across most other PostHog products. This had a few advantages, allowing us to:
iterate faster without cross-team or organisational risk
use later database versions without time consuming backwards compatibility testing
optimise the cluster for Logs specific access patterns
isolate our other product from the impact of bugs or load from logs, a very high-data-volume system
This new cluster uses S3 disks in ClickHouse, with data parts being automatically uploaded to S3 after 24 hours – this is what enables us to handle the significant data volume required for Logs (in PostHog, we alone produce about 500MB/s of logs from across our systems, or about 1PB/month uncompressed).
A bug in ClickHouse caused it to unexpectedly attempt to delete almost all of the data parts in S3. The Logs database is replicated, with two replicas, however very early on in the project we had enabled "Zero Copy Replication" in the Logs cluster nodes. This is an experimental feature that ClickHouse does not recommend in production, for exactly this reason: a bug that should have caused a single replica to be deleted instead deleted the data everywhere.
Timeline
All times in UTC.
Feb 19: 10:54: A routine mutation was run to materialize an index
Feb 19: 11:02: The mutation finished, this triggered a bug in ClickHouse's zero-copy replication which caused one of the replicas to erroneously believe all of the data parts in the database were no longer referenced
Feb 19: 11:02-19:40: During this time the replicas were busy diligently deleting all of the data stored in S3 for the entire database. As data is only moved to S3 after 24 hours, and the vast majority of our queries are for recent data, no automated alarms were triggered as the volume of query errors was relatively low
Feb 19: 19:40: One of the nodes in the cluster crashes and restarts, it fails to start up due to the large volume of missing data it can't find. Engineers investigate and after some checks discover that the vast majority of S3-backed data is missing
Feb 19: 21:45: It is determined that the data is most likely unrecoverable – disaster recovery procedures start
Feb 19: 22:15: Decision is made to cut over to a new table and restore data from Kafka, where we have 3 days of retention
Feb 19: 23:00: We have switched over to the new table (without zero-copy replication) and caught up on recent messages.
Feb 20: 10:05: Data backfill from Kafka history begins
Feb 20: 12:21: Data backfill completes
Root cause analysis
Zero Copy replication bug
The decision to use zero-copy replication was taken extremely early in the Logs product development when it was an experimental internal-only tool.
Once Logs was released to external users this decision should have been revisited, but wasn't. Due to experiencing no issues at all during several months of internal usage, settings that had been set at the beginning were largely unvisited and unchanged.
Zero-copy replication has been largely unmaintained for the last 4 years, and still contains critical bugs, including the one we hit here. Because Zero Copy replication uses a shared storage medium (S3) for multiple replicas, when the logic on one node failed and issued delete commands for the underlying S3 objects, those files were removed for the entire cluster immediately. There was no redundancy layer between the database application logic and the storage layer.
Lack of detection
We lacked specific monitoring for the integrity of "cold" data stored in S3. Our alerts are optimized for ingestion lag, query latency, and error rates on active queries. Since users rarely query logs older than 24 hours, and the deletion process happened silently in the background without throwing application-level errors, the system remained "green" on our dashboards until the node restart forced a consistency check.
Lessons learned
What went well
Service Isolation: Despite the severity of this incident, all other products and features were completely unaffected. Our decision to isolate the logs product massively reduced the blast radius of this incident.
Kafka Retention Strategy: Configuring Kafka with 3 days of retention saved us from total data loss for recent activity.
What went poorly
Configuration Lifecycle Management: Experimental configurations (Zero Copy Replication) intended for MVP/Alpha stages were allowed to persist into production
Silent Failure: The system deleted petabytes of data over an 8-hour window without a single alarm firing. We were blind to the deletion of historical data because we only monitor the health of incoming data and hot data.
Backup Strategy: Relying solely on the database replication for data durability (when using shared storage) created a single point of failure. We did not have S3 Versioning enabled on the bucket, which would have allowed us to "undelete" the files removed by the application.
Key takeaways
Immediate Configuration Audit: Disable Zero Copy Replication on all clusters immediately. Conduct a full audit of the Logs ClickHouse configuration and ensure no experimental features are used in production.
Implement S3 Object Protection: Enable S3 Versioning on the underlying storage buckets. This ensures that even if the database application issues a destructive command due to a bug, the underlying data objects can be recovered.
Before a product is made Generally Available, we spot check configurations and our data integrity strategies to find and correct for potential single points of failure
Workflow "Wait until condition" steps silently failing
Between March 30 and April 22, 2026, a bug in our workflow engine caused workflows using "Wait until condition" steps to silently stop resuming. Affected workflows appeared to complete normally in the UI but never executed their downstream actions — such as delivering emails or sending Slack notifications. 48 workflows across 33 customer organizations were impacted, with 11,920 invocations silently blocked. The issue has been fully resolved and affected customers have been contacted and they will see a banner on each impacted workflow with a self-serve option to review and replay the silently-blocked runs. Importantly, 99.7% of all workflows triggered during this period executed normally.
Summary
PostHog's workflow engine allows customers to build multi-step automations. Some steps, like "Wait until condition," pause execution and periodically re-check whether a condition has been met before continuing.
On March 30, we deployed a deduplication mechanism to fix an earlier incident where ghost workflow runs were causing customers to receive duplicate emails and notifications. The dedup logic worked by comparing the invocation ID of a workflow when it first entered a step against the ID it carried when it resumed. If the IDs didn't match, the resume was treated as a duplicate.
This only affected "hold-state" actions — steps that pause and re-enter themselves ("Wait until condition"). Steps like "Delay" advance to the next action before pausing, so the dedup check on the next action started fresh and never hit the mismatch.
Unfortunately, the issue went undetected far longer than usual as we were lacking observability for the dedup code path.
Timeline
All times in UTC.
2026-03-30: Deduplication logic deployed to production via PR #52776 to fix a separate ghost-run incident. This deployment introduced the regression.
2026-04-20 13:17: A customer opened a support ticket reporting a workflow stuck at a "Wait until condition" step, with deduplication warning logs visible in their workflow logs.
2026-04-20 – 2026-04-22: We added metrics and logging to the dedup code path (PR #55282) to determine whether the issue was isolated or widespread. In parallel, we investigated the root cause.
2026-04-22 00:41: Root cause identified — the UUIDT-to-UUIDv7 rewrite during re-queuing caused dedup mismatches. A fix-forward PR was opened (PR #55652).
2026-04-22 06:35: Incident declared. Instead of fixing forward, we rolled back the entire dedup code path to eliminate any residual risk (PR #55672).
2026-04-22 08:21: New image deployed, verified working correctly. Incident resolved.
Root Cause Analysis
Invocation ID format mismatch across subsystem boundary
The workflow engine generates invocation IDs using PostHog's UUIDT format. The V1 job queue (job-queue-postgres.ts) validates incoming IDs using the npm uuid package's isUuid check, which rejects UUIDT-format IDs and silently substitutes a fresh UUIDv7.
When a "Wait until condition" step paused and was re-queued through the Postgres V1 path, the invocation ID was rewritten. On resume, the dedup logic compared the stored UUIDT against the new UUIDv7, saw different IDs, and concluded the resume was a duplicate — silently terminating the workflow.
Both sides of this boundary were tested in isolation: the dedup tests called the executor directly (never round-tripping through the queue), and the queue tests used uuidv4() instead of the UUIDT generator that production actually uses. Both passed, but neither caught the mismatch that only surfaces when the two subsystems interact.
Missing observability on a critical code path
The dedup logic was deployed without metrics tracking how many invocations were being filtered. Although legitimate deduplications were expected — thousands of ghost runs were still being correctly blocked — having a baseline would have made the anomalous spike in filtered invocations visible and drawn attention to the issue much sooner.
Lessons Learned
What went well
Once the customer reported the issue, the team quickly added observability and identified the root cause.
The rollback was clean — reverting the dedup code immediately unblocked all affected workflows with no further intervention needed.
Customer Success proactively reached out to all potentially-affected organizations.
Impact analysis was thorough: the team built a log-pattern fingerprint (UUIDT-to-UUIDv7 rewrite combined with pause-resume cycles) to precisely identify affected workflows and distinguish bug-caused blocks from legitimate dedup catches.
What went poorly
23-day detection gap. The dedup code path lacked dedicated metrics, which delayed detection.
Tests didn't cross the subsystem boundary. Unit tests for dedup and for the job queue each passed independently, but no integration test exercised the full round-trip (engine → queue → resume) with production ID formats.
Silent failure mode. Affected workflows showed as "completed" in the customer-facing UI with no indication that downstream actions were skipped.
Key takeaways
We've reverted the dedup logic and are investing in building a solution that fully mitigates this class of problems. The new architecture will also allow us to write more robust end-to-end tests to prevent issues like this from happening again.
We have deployed additional alerting that will notify the teams immediately for this class of failure case in the future.
This page contains public post-mortems for significant incidents at PostHog. We publish these because we believe transparency builds trust, and because we think the wider engineering community benefits from shared lessons.
We write post-mortems to understand what happened, not to assign blame. Every incident is an opportunity to improve our systems and processes. Our post-mortems typically cover:
A clear timeline of what happened
Root cause analysis
Impact assessment
What went well and what went poorly
Concrete remediation steps
Not every post-mortem is made public. Minor incidents that partially affect services are documented internally. We publish a public post-mortem when an incident results in permanent impact on user data (such as data loss), directly disrupts customers' own services (such as SDK bugs breaking customer sites) or result in extended unavailability of PostHog services for customers (e.g. if dashboards would not load for multiple hours).
This page contains security advisories and Common Vulnerabilities and Exposures (CVEs) related to PostHog. We maintain this page to ensure transparency and help our users stay informed about any security issues that may impact them. In the event that a security incident leads to a confirmed exposure or requires action from users we will always contact users proactively.
At PostHog, we take security seriously. We don't treat it as a checkbox, but rather as a core part of our decision making. We have a robust security program that includes:
Regular security audits, architecture reviews, and penetration testing
Automated code and infrastructure as code (IaC) linting
Responsible disclosure program
Proactive vulnerability monitoring
Transparent communication with our community
For more information about our security practices, see our main security page.
PRs to this page which update advisories or CVEs should only occur as part of an incident and should follow all our usual processes for an incident. If you need to issue an advisory or CVE and an incident is _not_ declared, you should declare one.
Declaring an incident will ensure that there is good internal visibility and that members of relevant teams, including our Support team, are aware. Once an advisory is posted to this page, you should also update other teams by posting in the #tell-posthog-anything Slack channel.
Security best practices
Security is everyone's responsibility, so we encourage all our users and staff to follow some basic best practices within their own organizations.
Use PostHog Cloud - We sunset K8s deployments long ago and our OSS version isn't suitable for use at scale. Use PostHog Cloud to ensure you benefit from the latest security updates.
Use strong authentication - Always enable multi-factor authentication, strong passwords, and SSO where available. PostHog supports all of these.
Monitor access - Regularly review who has access to your PostHog data and follow the principle of least privilege by only giving access to things people _actually_ need.
We will always proactively reach out to affected users in the event of an advisory requiring attention or action. However, if you'd like to stay updated about future incidents or advisories, please subscribe to our status page. If you want to drink updates from the firehose, you can also follow our GitHub repos for real-time updates about everything we do, as we're committed to working in the open wherever possible.
Current advisories
No active advisories
Currently, there are no active security advisories or CVEs. All is well.
<p><strong>6 customers were affected and we contacted them directly. If you run a self-hosted <code>nginx</code> (or <code>nginx</code>-family) reverse proxy in front of PostHog, update its configuration as described under Resolution.</strong></p>
<p>A security researcher found that some customer-hosted reverse proxies were sending PostHog traffic to IP addresses that PostHog no longer used. As some proxies didn't verify the upstream server TLS certificate, whoever hosted an HTTPs server on released IP addresses could read the traffic. The researcher was able to hold a few of those IPs, recorded the traffic that arrived, and reported it to us. We identified 6 affected customers from the recorded data and contacted them. To prevent such cases, we hardened our load balancers with a fixed IP address range, and we updated our reverse proxy documentation to have more secure configurations.</p>
<h4>Description</h4> <p>Some customers send events to PostHog through a reverse proxy that runs on their own domain. A common setup is an <code>nginx</code> (or <code>nginx</code>-family) server with a <code>proxy_pass</code> directive that points to <code>us.i.posthog.com</code> or <code>eu.i.posthog.com</code>.</p> <p>Events ingestion hosts (<code>us.i.posthog.com</code> and <code>eu.i.posthog.com</code>) resolve to AWS Application Load Balancers (ALBs), which use public IPv4 addresses from a pool that AWS shares between all its customers. As ALB nodes rotate over time, AWS returns its IP address to the shared pool, and another AWS customer can receive it (using an EC2 for example).</p> <p>Two default behaviors of <code>nginx</code> turned this normal rotation into a security problem:</p>
<li>When <code>proxy_pass</code> contains a hostname, <code>nginx</code> resolves that hostname once, at startup and it keeps using the same IP address until it restarts or reloads. A proxy that ran for a long time could send traffic to an IP address that PostHog had released.</li> <li><code>nginx</code> does not verify the upstream TLS certificate by default (<code>proxy_ssl_verify off</code>).</li>
<p>An attacker can launch EC2 instances in the same AWS region until they receive a former ALB address, serve HTTPS on port 443 with a self-signed certificate, and log every request that arrives. If stale proxies keep sending events to that server, the attacker can read the traffic.</p> <p>The researcher did this a few times between July 11 and August 4, 2026, with released EU ALBs addresses, for about one hour each time. They forwarded each request to PostHog and returned our real response, so neither the customer nor PostHog saw anything unusual.</p>
<h4>Affected users</h4>
<li>We identified <strong>6 affected customers</strong> from the traffic the researcher recorded and shared with us. All 6 are on <strong>EU Cloud</strong>. We contacted them directly.</li> <li>Only customers who run a self-hosted reverse proxy that both caches DNS and does not verify the upstream TLS certificate are exposed. This is the default for <code>nginx</code>, ingress-nginx, and tools built on them, including our Railway template.</li> <li>Customers who send traffic to PostHog directly from our SDKs are not affected. Browsers and our SDKs re-resolve DNS and verify TLS certificates.</li> <li>Customers using our <a href="/docs/advanced/proxy#set-up-managed-reverse-proxy">managed reverse proxy</a> were not affected by this.</li>
<h4>Resolution</h4>
<li>We moved the load balancers behind event ingestion hosts to a fixed IP address pool. Addresses we release return to our pool, not to the shared AWS pool, so no other AWS customer can receive them. This removes the attack vector for every proxy, including ones that are never updated.</li> <li><strong>Your proxy will stop working if it cached an old address.</strong> As load balancer addresses have changed, a proxy that resolved our hostname at startup will get connection errors until you reload or restart it. This is the safe failure mode. Reload or restart your proxy if you see errors, and apply the configuration below so that it does not happen again.</li> <li>We updated our <a href="/docs/advanced/proxy/nginx">nginx</a> and <a href="/docs/advanced/proxy/kubernetes-ingress-controller">Kubernetes</a> reverse proxy guides and our <a href="/docs/advanced/proxy/railway">Railway</a> template. The new default configuration verifies the upstream TLS certificate and re-resolves our hostname on a short schedule.</li> <li><strong>If you run an <code>nginx</code>-family reverse proxy, update it now.</strong> At minimum:
<li>Enable upstream certificate verification (<code>proxy_ssl_verify on</code>, <code>proxy_ssl_server_name on</code>, and a <code>proxy_ssl_trusted_certificate</code>).</li> <li>Use a <code>resolver</code> with a short <code>valid</code> time, and put the upstream hostname in a variable so <code>nginx</code> re-resolves it instead of caching it at startup.</li>
See the updated guides for a complete configuration.
<h4>What we learned</h4>
<li>Configuration snippets that we provide customers must have secure defaults, and we should better understand security aspects that are involved - along with reviewing them regularly. This research had put multiple pieces together, but we should have figured that out before someone pointed it out to us.</li> <li>We should avoid using AWS shared IP pool for highly-important workloads such as event ingestion. TLS verification will prevent most attack vectors on released IPs, but we should have accounted for traffic that would not verify it.</li> <li>The report waited too long in bug bounty triage before it reached our team. We'll improve this.</li>
<h4>Timeline</h4>
<li><strong>First capture by the researcher, and report submitted to our bug bounty program:</strong> July 11, 2026</li> <li><strong>Further captures by the researcher:</strong> July 17, July 22 and August 4, 2026</li> <li><strong>Report forwarded to PostHog:</strong> August 18, 2026</li> <li><strong>Root cause confirmed and fix agreed:</strong> August 18, 2026</li> <li><strong>Reverse proxy documentation published:</strong> August 18, 2026</li> <li><strong>EU load balancers moved to a PostHog-owned IP pool:</strong> August 19, 2026</li> <li><strong>US load balancers moved to a PostHog-owned IP pool:</strong> August 20, 2026</li> <li><strong>Affected customers contacted:</strong> August 20, 2026</li> <li><strong>Disclosed:</strong> August 21, 2026</li>
<p><strong>No customer data was accessed and no action is required.</strong> Our investigation using AWS CloudTrail and Wiz, together with the researchers' confirmation, found that no customer data was viewed, accessed, or modified, and no customer accounts were affected. The incident exposed our internal production credentials, not customer data, to security researchers and we have rotated those credentials as a precaution.</p>
<h4>Description</h4> <p>A security researcher exploited a known vulnerability (<a href="https://www.cve.org/CVERecord?id=CVE-2026-7899">CVE-2026-7899</a>) in an outdated version of Chromium that we ran via Playwright to generate heatmaps. This Chromium instance ran without a sandbox, which was a legacy configuration we had planned to change but had not yet enabled. The combination of the outdated version and the missing sandbox allowed the researcher to gain a shell on the Kubernetes pod and read credentials stored in the pod's environment variables.</p> <p>We were alerted when one of the researchers stored the extracted secrets in a private GitHub gist, triggering GitHub's secret-scanning notifications to the affected providers, including AWS. Based on the researchers' confirmation and our own investigation via AWS CloudTrail and Wiz, no customer data was accessed and the vulnerability was not exploited by anyone other than the researchers. The researchers confirmed that their last access to our environment occurred before we began rotating credentials.</p>
<h4>Affected users</h4>
<li><strong>No customer data was affected.</strong> No customer data was accessed, viewed, or modified, and no customer accounts were compromised. This was confirmed by our investigation using AWS CloudTrail and Wiz, and by the researchers.</li> <li><strong>No customer action is required.</strong> We rotated the most critical credentials immediately, and are completing rotation of the remainder as a precaution.</li> <li>This affected our <strong>US Cloud</strong> environment only. EU Cloud was not affected.</li> <li>The exposure was platform-wide in scope (credentials available to the affected workload), not limited to a specific product.</li>
<h4>Resolution</h4>
<li>We immediately began rotating production credentials, starting with the most critical (including AWS).</li> <li>We updated Playwright and Chromium to the latest version.</li> <li>We have begun moving heatmap generation and other uses of Chromium to an external service so that we no longer run Chromium in our own containers.</li> <li>We are exploring additional container hardening, including removing the shell from these containers entirely.</li>
<h4>What we learned</h4>
<li>A sandbox would have contained the exploit to the browser process rather than letting it reach the pod and its secrets. We should have closed that known gap sooner.</li> <li>Our initial status update was slower than it should have been because the incident began on a Friday evening, when fewer responders were immediately available. We also lacked a playbook for this specific incident type.</li> <li>Reducing the number of static, long-lived secrets limits the impact of any future exposure. We already use short-lived, automatically-rotated credentials (such as OIDC and IRSA) wherever we can, but many third-party services still only support static API keys. We'd like to see the industry move further toward short-lived credentials.</li> <li>Rotating our secrets is slower and more manual than it should be. We need better documentation of where each secret originates and who is able to rotate it.</li> <li>We need better tooling to propagate rotated secrets into running workloads and trigger a redeploy independently of a normal release, so rotation isn't gated on the deploy process.</li> <li>Automated secret-scanning notifications from our cloud providers were an effective backstop that alerted us quickly.</li>
<h4>Timeline</h4>
<li><strong>Secret-scanning alert received:</strong> May 29, 2026, 23:55 UTC</li> <li><strong>Incident declared:</strong> May 30, 2026, 00:08 UTC</li> <li><strong>Outreach to researcher:</strong> May 30, 2026, 00:16 UTC</li> <li><strong>Began rotating credentials:</strong> May 30, 2026, 00:24 UTC</li> <li><strong>Initial status page update published:</strong> May 30, 2026, 01:04 UTC</li> <li><strong>Researcher confirmed exploit path:</strong> May 30, 2026, 01:37 UTC</li> <li><strong>Initial fix deployed (Chromium/Playwright update):</strong> May 30, 2026, 02:40 UTC</li>
<h4>Description</h4> <p>An overly permissive table was available in the SQL editor that allowed users to see queries performed by other users in unrelated teams. The results of those queries were <em>not</em> accessible, but the queries themselves were visible.</p>
<h4>Affected users</h4>
<li>Our logs confirm that this feature was never used in our EU cloud.</li> <li>Our historical query log for the US cloud only contains data going back to July 3, 2025, and we can confirm the feature was not used during that period.</li> <li>We do not have query logs between December 12, 2024, and July 2, 2025. While we cannot fully confirm usage during this window, we believe it is very unlikely the feature was used in our US cloud, as it was never advertised.</li>
<h4>Resolution</h4> <p>Once discovered, we immediately removed the ability to query this table. We then reintroduced the feature with queries properly scoped to each user’s team.</p>
<h4>What we learned</h4>
<li>We have a logic guard to ensure that all queries contain a properly authorized <code>team_id</code> when the queried table includes a <code>team_id</code> field.</li> <li>This logic did not help in this case because the query log table did not contain a <code>team_id</code> field.</li> <li>We have since added a <code>team_id</code> field to this table and audited all other tables to verify that they contain a <code>team_id</code> field where appropriate.</li> <li>Going forward, we will introduce automated tests to ensure that all new tables also include a <code>team_id</code> field.</li> <li>Our historical query log contains a longer dataset in the EU cloud simply because it was deployed there first. Going forward, our US cloud logs will continue to accumulate historical data for future incident response.</li>
<h4>Timeline</h4>
<li><strong>Vulnerable code shipped:</strong> December 12, 2024, 14:45 UTC</li> <li><strong>Discovered:</strong> August 13, 2025, 11:32 UTC</li> <li><strong>Reported:</strong> August 13, 2025, 11:39 UTC</li> <li><strong>Fixed:</strong> August 13, 2025, 12:33 UTC</li> <li><strong>Disclosed:</strong> August 15, 2025, 09:00 UTC</li>
Advisory template
Use the advisory code as the <details>id (and the matching <AdvisoryAnchor>id) so it can be linked directly. Linking to the anchor (e.g. /handbook/company/security-advisories#PSA-2025-XXXXX) auto-expands the advisory.
<details id="PSA-2025-XXXXX">
<summary>August 15, 2025 / PSA-2025-XXXXX </summary>
<p><strong>Date:</strong> August 15, 2025<br />
<strong>Advisory:</strong> PSA-2025-XXXXX<br />
<strong>Severity:</strong> Low / Medium / Critical<br />
<strong>Status:</strong>Reported / Fixed / Resolved</p>
<h4>Description</h4>
<p>Brief description of the vulnerability and its potential impact.</p>
<h4>Affected users</h4>
<ul>
<li>Confirm if the advisory is limited to specific products.</li>
<li>Confirm if the advisory is limited to either US or EU customers, or both</li>
</ul>
<h4>Resolution</h4>
<p>Where possible, add a link to a PR. Be clear on any next steps.</p>
<h4>What we learned</h4>
<p>If there's a lesson we took to prevent this happening again, document it briefly.</p>
<h4>Timeline</h4>
<ul>
<li><strong>Vulnerable code shipped:</strong> January 10, 2024, 00:00 UTC</li>
<li><strong>Discovered:</strong> January 10, 2024, 00:00 UTC</li>
<li><strong>Reported:</strong> January 10, 2024, 00:00 UTC</li>
<li><strong>Fixed:</strong> January 10, 2024, 00:00 UTC</li>
<li><strong>Disclosed:</strong> January 10, 2024, 00:00 UTC</li>
</ul>
</details>
It is critical that everyone in the PostHog team follows these guidelines. We take people not following these rules very seriously - it can put the entire company and all of our users at risk if you do not.
Overview
We maintain a robust security program that follows best practice in order to meet the needs of our PostHog Cloud customers, making PostHog the ideal solution for customers who have GDPR, SOC 2, or CCPA obligations themselves. PostHog Cloud customers own the data they send to us for processing. We collect and analyze data about the use of PostHog Cloud by our customers, but that data does not include the user data that customers send to us to process on their behalf.
This page covers SOC 2, GDPR, and CCPA compliance.
All team members are required to enable multi-factor authentication (MFA) on their accounts. Passkeys are the preferred method for securing all accounts — they are phishing-resistant, easy to use, and supported by most major services including Google Workspace, GitHub, 1Password, and macOS.
Please set up passkeys for Google Workspace and GitHub at the very least. If you are new, please do this within your first week so you don't get locked out.
It is recommended to have most passkeys saved in 1Password itself, which will allow you to use them from your phone.
Yubikeys
We previously required all employees to purchase and configure two Yubikeys. These have been replaced with passkeys, and Yubikeys are no longer required nor recommended.
Signed commits
Every commit pushed to a PostHog repository must be cryptographically signed. An org-wide GitHub ruleset enforces this on all branches, so we can verify who authored a commit instead of trusting the Author field, which anyone can set. Engineers should set up commit signing in their first week.
Mobile device management (MDM)
We use Fleet to manage all of our laptops. It applies targeted policies that raise the security baseline of every device, including:
minimum password length
screen lock
auto-install of software updates
auto-provisioning of software like 1Password
absence of static SSH keys on the filesystem
We also use Fleet to investigate supply chain attacks, for example to see whether any laptops have been exposed to a malicious package or browser extension.
We chose Fleet because they are open source and a transparent company. In the same spirit, all of the policies we provision are stored in git at PostHog/fleet-gitops. Any employee can see the same data our security team sees by clicking the Fleet icon in the macOS menu bar and choosing "My device".
Fleet does not see:
your screen
your messages or photos
what you type
which URLs you visit
SOC 2
These policies are also relevant for GDPR (see below).
GDPR
For the purposes of GDPR, customers use PostHog in one of two ways:
PostHog Cloud
Self-hosting a hobbyist PostHog instance
If a customer is using PostHog Cloud, then PostHog is acting as Data Processor and the customer is the Data Controller. We have some GDPR obligations to the customer's end users here.
If a customer is self-hosting PostHog then they are both the Data Processor _and_ the Data Controller because they are responsible for their PostHog instance. We do not have access to any of their user data, so we do not have specific GDPR obligations to the customer's end users here.
PostHog's obligations as a Data Processor
We have reviewed our architecture, data flows and agreements to ensure that our platform is GDPR compliant. PostHog Cloud does not directly interact with our customers’ end users, nor does the platform automatically collect personal data. However, our customers might collect and send personal data to PostHog for processing.
PostHog does not require personally identifiable information or personal data to perform product analytics, and we provide extensive controls for customers wishing to minimize personal data collection from their end users. We provide separate guidance for our customers on how to use PostHog in a GDPR-compliant way in our Docs.
Technical and Organizational Measures ('TOMs')
We maintain an extensive security policies to ensure we are managing data responsibly - see above.
We enter into Data Processing Agreements ('DPAs') with PostHog Cloud customers when requested - you can generate a DPA here. We maintain a register of all DPAs we have entered into.
Customers can choose whether to host data on our AWS servers in the EU (eu-central-1 in Germany) or the US (us-east-1 in Virginia). If data transfer is required from the United Kingdom, EU, or EEA to our US based AWS environment, we rely on EU Standard Contractual Clauses (SCCs).
We are registered with the Information Commissioner's Office in the United Kingdom as Hiberly Ltd., which is the legal name for our UK entity.
A list of sub-Processors is maintained as part of our DPA - we keep this to a strict minimum.
Charles Cook (VP Operations) is our assigned Data Protection Officer and is responsible for overseeing compliance. Customers can email privacy@posthog.com for any questions relating to GDPR or privacy more generally.
CCPA
Under the California Consumer Privacy Act (CCPA), PostHog as a Service Provider to PostHog Cloud customers only. This is similar to the Processor definition under GDPR. We include a CCPA Addendum in our Privacy Policy.
We give all PostHog customers the tools to easily comply with their end users' requests under CCPA, including deletion of their data. We provide separate guidance for our customers on how to use PostHog in a CCPA-compliant way in our Docs.
We receive data collected by our customers from end-users and allow them to understand usage metrics of their products. We don't access customer end-user data unless instructed by a customer, and customer data is never sold to third parties. We do not have access to data collected by our customers who are using a self-hosted version of PostHog from end-users at all, unless they give us access to their instance.
Pen tests
We conduct these annually, most recently in May 2026 - you can find the report in our Trust Center.
Responsible disclosure
Security vulnerabilities and other security related findings can be reported via our vulnerability disclosure program or by emailing security-reports@posthog.com. Valid findings will be rewarded with PostHog swag.
For information about current and past security advisories and CVEs, see our advisories & CVEs page.
Fixing vulnerabilities in our own code
We import security findings in our own code from the AI pentesting services we use, currently Veria Labs and Parameter. Findings are triaged automatically, and true positives are forwarded to the product team that owns the code. They are collected in SecurityHog, and each team gets a weekly post in its Slack channel that lists the vulnerabilities found in the code it owns.
Each team fixes the findings for the code it owns. By default, the team's support hero picks these up alongside the normal support workload, but each team decides how to split the work. Critical and high severity findings must be fixed as soon as possible.
Reporting phishing
If you receive a phishing email/text/whatsapp, it's useful to report it to the security team so that they can make other employees aware. Take a screenshot and post it in #phishing-attempts. You may be asked to forward the email to security-internal@posthog.com for further inspection.
Secure communication (aka preventing social engineering)
We follow several best practices to combat social engineering attacks. See Communication Methods for more information.
Impersonating users
To provide a great customer experience, PostHog employees may occasionally need to access customer data or log in as a user (i.e. impersonate them). We allow this access when it's necessary to deliver our service, following these guidelines:
Only impersonate when there’s a clear, demonstrable benefit for the customer.
For example, to investigate an incident, resolve a support issue, or review a customer’s setup to give recommendations on how to use PostHog more successfully.
Do not make any changes to a customer’s setup without explicit consent.
Exceptions to this are cases where we are reacting to incidents or bad configurations that are negatively impacting PostHog services in order to protect ourselves _and_ the customer.
Ask for permission whenever possible.
While this isn’t always feasible, such as during an active incident, it’s best practice to inform the customer before accessing their account. When a customer raises a support ticket, we take this as consent to be able to impersonate their account and investigate based on the contents of the ticket. Customers will not be actively asked for permission by our support engineers when they are investigating a ticket, and the customer should inform us in the ticket if they explicitly do not wish for our support engineers to access their account.
Use good judgment.
If you’re unsure whether impersonation is justified, or if a customer might object, either seek their consent or find another way to get the information (for example, by checking our internal PostHog instance).
Impersonating users via MCP
The same rules apply when you connect the PostHog MCP server while logged in as a customer. Treat the OAuth connection and every MCP tool call as actions taken while impersonating them. Use read-only mode unless the customer has explicitly agreed to changes, only authorize the organization and project you need, and log out when you're finished. See handling customer issues for the steps.
PostHog is structured for speed, autonomy and innovation.
Many traditional organizations have big, separate functions. You have a product team, an engineering team, customer support, and so on. This slows things down when you scale because there are more layers of communication and complex approval chains. This stifles innovation because you have to get your boss to talk to someone else's boss to get work done. It also means that people can't really see the impact of their work.
PostHog started off as a completely flat company with one big goal: to increase the number of successful products in the world.
As we are getting bigger, we anticipate that it will get harder for people to see the direct impact of their work, which reduces the sense of ownership.
We have therefore introduced small teams. These are designed to each operate like a startup. We maintain our full org chart in our ops platform.
How it works
The overall goal for a small team is to own an area of the product/company and be as close to its own startup as possible, with only a handful of centralized processes.
A small team should _strictly_ be between 2-6 people.
A small team has a team lead responsible for its performance – whoever is most appropriate depending on what the team is working on. This does _not_ mean the most experienced person on the team.
A small team must have a customer (internal or external).
There may be certain functions where at our current stage we don't need a small team yet.
Each small team runs its own retrospective + sprint every week. This must be done transparently.
A small team has the final call in which of its features get into production, with no need for external QA/control - within our existing release schedule.
A small team will, at some stage, be able to create its own pricing.
A small team is responsible for talking to users, documenting what they build, and ensuring their features are highlighted in releases.
What does owning an area of the product mean?
The product small team is responsible for everything related to their area, particularly:
Usage
Quality
Revenue
What actions should the small teams be doing for their area?
Each quarter:
Create good quarterly goals
During the quarter:
Maintain a prioritized roadmap to help them achieve their objectives
Speak to customers
Monitor relevant metrics including those covering Usage, Quality and Revenue
Triage and fix related bugs
Assist the support hero in answering related questions
Collaborate with other small teams such as marketing
Become power users of their area of PostHog and use PostHog in their processes
What is the role of the team lead?
Overall, the team lead is responsible for ensuring the above happens. They should focus on enabling the team to solve these tasks together rather than trying to do it all themselves.
Once a new team lead is appointed, or a small team is created, team leaders take on additional responsibilities, along with a checklist of actions. To kick off the process, run /org-change in Slack and select the relevant change type – it'll create a tracked issue in company-internal with the right checklist.
Team leads also take on a range of broader responsibilities that revolve around releasing new features and communicating with other teams. Some helpful guidelines on what team leads should be taking responsibility for are listed below.
Setting up support processes
Setting up support processes is a team lead responsibility, but if you need any assistance just contact the Support team directly.
Team leads are responsible for creating a #support-<team-name> Slack channel and making sure their team is set up for support, so that the team can be alerted to support issues. Once the support process is set up, team leads are responsible for ensuring a sustainable and fair support rotation and setting up support hero notifications.
To kick off any org change, run /org-change in Slack.
Launching new products and features
It's the responsibility of the team lead to keep Marketing and Billing teams informed about product progress, so that product marketers can coordinate launches and the Billing team can implement pricing.
[ ] Inform the marketing teams a new roadmap item is available via the #team-marketing channel
Launching a new beta
[ ] As soon as user opt-in is available, move your roadmap item from concept to beta
[ ] Ensure your opt-in beta has a feedback link and docs link
[ ] Inform the marketing teams a new beta is available via the #team-marketing channel
Launching a new product
Typically, you must give at least 2-3 weeks notice of a product launch and you should reach out directly to marketing team leads if this is not possible.
[ ] Continue to communicate timelines / updates in the Slack channel created
Leading quarterly goal setting
Team leads are responsible for organizing quarterly goal setting within their team, leading the goal-setting session, and documenting the goals on their team page.
How do small teams and product managers work together?
With our engineering-led culture, the engineers on the small team are normally responsible for their area of the product.
We have a small number of product managers who support the product small teams in achieving their goals. This includes helping with prioritization, creating/updating dashboards, competitors analysis, speaking to customers etc. However, having product managers doesn't mean that the engineers can abdicate these responsibilities. The engineers should be the experts of the product they are building and their customers.
Additionally, the product managers should pay particular attention to cross-team alignment.
How do small teams and designers work together?
Similar to product, designers support small teams. Read our guide for engineers on how to work with design.
Managing larger cross-team projects
Each project should be owned by an individual within a single small team. However, some projects affect multiple other teams and require their support. For example, the performance work owned by Karl in product analytics requires support from the pipeline and infrastructure team.
For these projects, we recommend the individual owning it write a "Status update" every 2 weeks on slack and add a link to this update in the "Updates on bigger projects that affect multiple teams" section of the all hands doc. These status updates might include: what's been done since the last update, any blockers, and what are the next steps.
Small teams intros
Every small team should have an agreed charter which should include:
Mission
Long term goals
Description of what the team does
Target customer
Who is on the team
Key metrics
These should all be visible in the Handbook, updated when changes are made & confirmed ahead of each quarter so everyone is on the same page.
[ ] The team lead runs /org-change in Slack to kick off the tracking issue. Ops will be notified and picks up execution from there.
[ ] Exec informs everyone else in the company in the next all hands session.
The small teams template contains a list of tasks for the Ops team and the team lead.
These include standard tasks, such as creating Slack groups and a team page to ensure the team can communicate efficiently.
FAQ
Who do small teams report to? How does this work with management?
The team lead has the final say in a given small team's decision-making - they decide what to build / work on.
Each person's line manager is their role's functional leader (if possible). For example, engineers, no matter which small team they're in, will report to an engineer.
It's important to note that management at PostHog is very minimalistic – it's critical that managers don't set tasks for those in small teams.
Think of the small team as the company you work for, and your line manager as your coach.
Can someone be in multiple small teams?
Only if they're in some kind of supportive role. For example, product managers and designers can be attached to more than one team, but product engineers should never be in more than one team because this acts against proper ownership.
Who is in a small team?
No more than 6 people, but that's the only rule. It could be any group of people working together.
Will this lead to inconsistent design?
Eventually, yes. Other companies have a UX team that build components for everyone to use. Since we currently use Ant Design, we don't need this just yet.
We still expect people to have an understanding of the entire company and what various people are working on. In engineering, we still expect you to understand how the entire system works, even if you're only working on infrastructure. You can only do your job well if you understand how it fits in with other parts of the system.
You're actively encouraged to raise pull requests or propose changes to stuff that doesn't have anything to do with your small team.
Can people change teams?
We try to keep moves infrequent and when needed. We anticipate moving people roughly every 3-9 months. We'd rather hire new people than create gaps by shifting people around.
There are two scenarios that will trigger a move:
The small team may realize they no longer need someone, or that they could really do with someone currently in another small team internally.
An individual team member may wish to move in order to develop their skills or experience.
It is very important to raise any desire for a team change with your relevant Blitzscale team member early. Any changes are at their discretion, as their job is to ensure that our small teams continue to function and that any moves fit into our current hiring plans. They will also have the best context about which teams you may be a good fit for, based on your skillset but also each team's needs. Please don't go talking to other teams directly first, as it makes it harder to manage everyone's expectations.
Aren't most small teams way too small?
In general, no – it's surprisingly great how much just 2-6 people can get done.
If more mature product areas cannot cope with the workload, small teams will clarify where we need to hire too. In fact, it'll make sure we keep the scrappy fun side of working here as we get bigger. A team doesn't _have_ to be six people.
How does hiring in the small team work?
The small team is responsible for creating roles for those that they need.
We have a centralized team that will then help you hire.
James and Tim used to interview every candidate because it's a standard startup failure for founders to get too removed from hiring. We've relaxed this so that someone from Team Blitzscale always interviews candidates, normally whichever team member sponsors the team the candidate will be joining.
Regardless of the team, we aim to retain a high bar for new hires. In the words of James Greenhill: "If it's not a hell yes, it's a hell no." See how we hire for more on this.
How do we create new teams, or make changes to existing teams?
How do you keep the product together as a company?
James and Tim are ultimately responsible for us having (i) no gaps in product (ii) eliminating duplicate work (iii) making sure all small teams are working on something rational. This is how we manage the product.
How do you stop duplicate work?
James and Tim have the ultimate responsibility to make sure we don't build the same thing in two different teams, or that we don't accidentally compete with each other internally.
By keeping communication asynchronous and transparent, this is made much easier to do than is typical at other organizations.
Can a small team "own" another small team?
Not for now, no. Perhaps when we're much larger this is something to think about.
PostHog works based on Sprints. These are when a Small Team meets to discuss how the last Sprint went, and what the plan is for the next one.
Sprints are shared transparently inside the company, for every team – including the Executive Team. This means people can coordinate work without having to do meetings.
There should be a GitHub issue for the sprint up in advance and everyone should add their notes to it before the meeting starts.
Each _individual_ should come with specific written suggestions for what they'll work on over the next sprint. Note: if you're in an engineering role, product won't dictate to you what to build – it is up to you to drive this.
The _team leader_ for a small team is responsible for making sure the sprint takes place regularly.
Any important points discussed should be written down to clarify any decisions and to help those who didn't attend.
Teams generally meet either once a week or every two weeks.
Everyone in a small team should attend their small team's sprint as far as possible.
Anyone can attend a specific small team's sprints. However, all attendees should have a specific reason to be there.
Anyone can comment on the sprint issue before or after the sprint.
Anyone can propose a change by creating an issue suggesting the change.
Decisions should be made quickly – i.e. less than a week.
Team Blitzscale ultimately own the decision to make a change or not.
Complete consensus isn't necessary, but there should always be time for people to share feedback, and alternative solutions, before a decision is made.
We should never run lengthy consultations, or individual meetings with all those affected by a proposed team change, but a group meeting to make a final call can be useful provided you follow the process below first.
How to propose a team change
Follow this process whether you're proposing creating a new team, splitting up an existing team, or even closing down a team.
Tag all those directly affected by the change, and the Blitzscale Team member directly responsible for this area of the business.
Include context about why you're suggesting the change and the goals you think this change will help us achieve.
Be as concise as possible. This isn't an RFC, our goal is to make a quick decision.
2. Share your proposal widely
Please share the issue in the relevant team Slack channels, the #team-blitzscale Slack channel, and any relevant public channels, requesting feedback.
It's generally best to post once and then forward that message to other relevant channels to keep things tidy.
Include the deadline for the decision in your message and tag the directly affected people.
Our goal is to make the best possible decision as fast as possible. When giving feedback, consider the following:
Are there considerations the proposer isn't aware of that could impact the decision we make? Please share them and suggest solutions. Often these relate to feature ownership.
Is there a better or alternative solution? Disagreeing with a proposal is fine, but it's always best to propose a solution than to just disagree without an alternative. If you think no change is necessary, explain why.
Be direct and clear about how strongly you feel. If you're strongly against a change, explain why and make that clear. Likewise, if you're unsure about a change, but don't feel strongly, articulate that. Consensus is not our goal and decisions being blocked by people who are less invested in the outcome will slow us down and lead to worse decision-making.
3. Share the final decision in Slack
The final decision should always be made by the relevant member(s) of the Blitzscale Team in a timely fashion.
Once made, they should share their decision in #tell-posthog-anything and the relevant team channels, alongside a short summary of why we're making that change.
4. Execute the change
Once the decision is shared, the team lead kicks off execution by running /org-change in Slack and selecting the relevant change type. This creates a tracked issue with the right checklist, assigned to those involved.
FAQ
What if I want to move teams?
This process exists purely for making larger changes to existing teams, or forming new ones, that impact multiple people. If you are personally looking to change team, see the small teams handbook page.
- **Feature flags:** PostHog offers robust, multivariate feature flags which support JSON payloads. This enables you to push real-time changes to your product without needing to redeploy. Visit our feature flag page for more information. LogRocket doesn’t have any in-built feature flag functions.
- **Experiments:** PostHog offers multivariate experimentation, which enables you to test changes and discover statistically relevant insights. Visit the experimentation page for more information. LogRocket doesn’t have any in-built experimentation features.
- **Open source:** PostHog is entirely open source, under a permissive MIT license. The biggest advantage for users is the ability to build on top of PostHog and to access the source code directly. Our team also works in the open. LogRocket is not an open source company, nor is the product available under an open source license.
Feature flags: PostHog offers robust, multivariate feature flags which support JSON payloads. This enables you to push real-time changes to your product without needing to redeploy. Visit our feature flag page for more information. LogRocket doesn’t have any in-built feature flag functions.
Experiments: PostHog offers multivariate experimentation, which enables you to test changes and discover statistically relevant insights. Visit the experimentation page for more information. LogRocket doesn’t have any in-built experimentation features.
Open source: PostHog is entirely open source, under a permissive MIT license. The biggest advantage for users is the ability to build on top of PostHog and to access the source code directly. Our team also works in the open. LogRocket is not an open source company, nor is the product available under an open source license.
- **Feature flags:** PostHog offers robust, multivariate feature flags which support JSON payloads. This enables you to push real-time changes to your product without needing to redeploy. Visit our feature flag page for more information. LogRocket doesn’t have any in-built feature flag functions.
- **Experiments:** PostHog offers multivariate experimentation, which enables you to test changes and discover statistically relevant insights. Visit the experimentation page for more information. LogRocket doesn’t have any in-built experimentation features.
- **Open source:** PostHog is entirely open source, under a permissive MIT license. The biggest advantage for users is the ability to build on top of PostHog and to access the source code directly. Our team also works in the open. LogRocket is not an open source company, nor is the product available under an open source license.
Feature flags: PostHog offers robust, multivariate feature flags which support JSON payloads. This enables you to push real-time changes to your product without needing to redeploy. Visit our feature flag page for more information. LogRocket doesn’t have any in-built feature flag functions.
Experiments: PostHog offers multivariate experimentation, which enables you to test changes and discover statistically relevant insights. Visit the experimentation page for more information. LogRocket doesn’t have any in-built experimentation features.
Open source: PostHog is entirely open source, under a permissive MIT license. The biggest advantage for users is the ability to build on top of PostHog and to access the source code directly. Our team also works in the open. LogRocket is not an open source company, nor is the product available under an open source license.
AEO is about making sure PostHog shows up when someone asks an LLM or a coding agent a question that's relevant to us – whether that's directly about our product, or indirectly about our use case, industry, or competitors – and that it shows up accurately, reflecting what we actually offer today and our current positioning.
More concretely, if someone asks Claude "what's a good session replay tool?", we want to be in that answer, described correctly, with a link back to a page that helps move them through our marketing funnel.
It's roughly what SEO is for search results, with a few important differences.
We're much more in the dark. In traditional search we generally know what people typed into the search bar, because search volume data exists, and we know roughly where we rank for it. With answer engines we know neither. There's no volume data for prompts, so we can't tell whether anyone actually asks the questions we track. And there's no fixed ranking to check; the same question can produce a different answer depending on the model, the phrasing, and sometimes just the run.
The mechanics differ too. Google sends a crawler, builds an index, and ranks pages. An answer engine does that AND generates prose from what it found, which means it can mention us without linking us, link us without mentioning us, or describe us slightly wrong.
So the work we do for AEO is trying to wrangle all those possibilities toward the best case scenario: our content gets crawled, we're mentioned accurately, we get a link back to a relevant page, and that person signs up.
Why we care about AEO
Because it's already our biggest acquisition channel by self-reported attribution (meaning what people tell us in the signup form when we ask where they heard about us); bigger than Google, YouTube, Reddit and social combined, and still growing.
Two things make it matter more than that share suggests:
It's systematically under-measured. Assistants strip referrers, agents pass none at all, and plenty of people read a recommendation and then just type "posthog" into their browser. Whatever our analytics say about AI traffic, the real number is bigger; we only know about some of it because we ask people directly.
Our ICP lives in these tools. Developers increasingly ask a coding agent what to install, or a chatbot what to evaluate. This is where our audience is making decisions.
It's also a warmer introduction than most channels give us. Someone who asked a question and got told to use PostHog arrives already half-sold, which is not true of an ad for example.
How AEO actually works and how do we measure it
There are roughly four stages to what we're calling the "AEO funnel".
1. Crawling
A bot has to fetch the page before a model can use it. Two different things fetch our content:
Index crawlers (GPTBot, ClaudeBot, PerplexityBot) build the model's picture of the web ahead of time.
Live assistants (Claude Desktop, ChatGPT, NotebookLM) fetch a page in the moment because a user asked something.
Crawled doesn't mean indexed, and indexed doesn't mean used in an answer. But nothing downstream can happen without this step: if a crawler is blocked, we're invisible no matter how good the content is.
2. Cited & mentioned
The model produces an answer and either mentions us, links us, both, or neither. Those are two different measurements:
Mention rate (sometimes called visibility) is the share of tracked prompts where we get named in the answer at all, link or no link. Roughly: does the model think of us for this topic?
Citation rate is the share where the answer actually links to a posthog.com URL as a source.
Both move independently.
It's important to note that while a mention doesn't send anyone to the site directly, that doesn't mean it sends nobody. Plenty of people read a mention and then Google us, or type posthog.com straight into the browser, which lands in our analytics labeled as Direct or Organic Search traffic. So mentions are very valuable and are likely doing a lot more work than they appear to, it's just hard to attribute.
3. Clicked
Someone acts on the answer and visits our website. This is the stage we measure the worst.
In Google for example, we have a "click-through rate". Search Console tells us how many times a page showed up in results (impressions), how many people clicked, and the ratio between the two.
With answer engines we have none of that.
The first challenge is that referrers get stripped. When you click a link, your browser normally passes along a "referrer" – a note telling the destination site which page sent you. That's how our analytics know a visit came from Google or Reddit rather than nowhere. Many assistants don't pass one at all, and coding agents pass nothing by design. The visit still happens, but it arrives looking like the person typed posthog.com straight into their address bar.
Even if referrers worked perfectly, we'd have no objective idea how many answers we appeared in out in the world, only across the handful of prompts we happen to track. No denominator means there's no click-through rate to calculate at all, however good our click data gets.
4. Converted
A conversion here means someone signed up after discovering us through an LLM or coding agent.
We currently measure this by looking at what people tell us on the signup form, plus referrer tagging when any survives. Neither dataset is complete on its own, so we take the deduplicated union of both, knowing that's likely a gross underrepresentation of reality, but it's the best proxy we have.
TL;DR
We keep tabs on all four stages, while acknowledging the limitations alongside all these numbers.
Agent preference is a newer way to measure this. Instead of asking a chatbot to recommend tools and counting who gets named, it runs simulated coding sessions: an agent gets a realistic task like "add session replay to this Next.js app" and we watch what it actually installs. We'll start reporting on this soon.
What good looks like: all four stages hold their baseline or grow, and when one moves, we can tell which pages caused it and act on it quickly.
Which prompts we track, and why
Since prompt selection largely determines the result, it's worth being transparent about how we pick ours.
A tracked prompt is a question we run against the major models on a regular schedule, recording whether we get mentioned, whether we get cited, and who else shows up. The set is what our citation and mention rates are calculated against, so if the set is junk, so are the numbers.
How we choose them:
Google search volume as a proxy. If a lot of people search something, it's reasonable to assume people ask LLMs something similar. Imperfect, but it's the only "volume" data that exists.
First-party data from real users. Our onboarding form asks what people were actually doing when they found us, including the prompts they remember using. This is the closest thing to ground truth we have, and it's small but growing.
Bottom-of-funnel intent. We weight toward prompts where someone is choosing a tool ("best session replay tools", "X vs Y") over prompts where they're learning a concept. The second kind is worth writing for, but it converts differently and shouldn't be mixed into the same number.
Organized by product and topic, so we can see where we're weak rather than just getting one blended figure.
The limitation: search behavior isn't prompt behavior. People phrase things very differently to an LLM than to a search bar – longer, more conversational, with more context about their situation. Our set is a proxy for something we can't observe directly, and we keep refining it as more first-party data comes in.
What we leave out: anything where we already know the answer before we run it (prompts rigged in our favour like "the best product analytics tool with a fun mascot and a weird name"), and prompts with no evidence anyone asks them.
We've pruned our prompt set aggressively for this reason. A smaller set focused on our ICP tells us more than a large set padded with unreliable and/or unrealistic prompts.
We do track branded prompts like "what is PostHog" as they're useful for checking how accurately we're positioned in the eyes of LLMs, but they're excluded from the visibility calculation.
Want to poke at this yourself? We're working on making all of it easier to see. In the meantime, let us know if you'd like access to Gauge, and there's a bot in #marketing-reporting you can tag @Gauge to ask questions about our visibility data directly.
What we control and what we don't
We control:
Whether our content is crawlable at all (robots.txt, CDN rules, 404s)
How easy our pages are to extract and quote (by using clear headings, front-loaded answers, self-contained sections, etc.)
How much of a certain topic we cover (depth is an AEO lever; sites with more pages on a topic tend to get cited more on it)
Whether our positioning and pricing are clear, accurate, and consistent across pages
We don't control:
When models refresh their index, or what they retain from a crawl
Our presence on third-party surfaces like Reddit (for the most part)
Which prompts real people actually type
Whether a mention comes with a link
Industry-wide shifts (for example, models are suddenly citing fewer sources per answer and shifting toward first-party vendor content)
Underneath all of this: there's no forcing a model to recommend us, or describe us the way we'd like.
There's no submission form, no bidding system, no account manager to yell at. A model's picture of PostHog is assembled from not just our own content, but also what other people say (or don't say) about us on Reddit, YouTube, G2, comparison roundups, etc.
So the only real strategy is to try to be the source worth choosing: accurate, easy to quote, thorough, and consistent wherever we turn up.
And to accept that a good chunk of what shapes the answer is other people's opinion of us, which we have to earn.
What we're currently doing about it
Strengthening non-blog pages. LLM traffic overwhelmingly lands on the homepage, docs, pricing and the evaluative pages such as /demo, /products, /about, so we're making sure those are optimized.
Refreshing and optimizing existing blog content. Pages decay; models favor current information, and what was the best answer two years ago usually isn't any more. Refreshing keeps our strongest pages holding their spot.
Writing content where the gap is. We prioritize topics where our visibility is weak and there's real search demand behind it.
Fixing the technical stuff. Duplicate URLs split citations across several versions of the same page, broken redirects strand pages that used to rank, and a blocked crawler makes everything above pointless.
The specifics change every quarter. For what's currently in flight ping #team-editorial.
Finally: why you shouldn't panic about "brand X is beating us" threads
You've either run into one of these already or you will. They usually show a competitor crushing it on visibility or sentiment across some set of prompts.
It's worth internalizing how easy these are to manufacture, and why.
There's no ground truth to check against. No LLM provider publishes what people actually ask it. There's no equivalent of search volume data. So every AEO measurement, ours included, starts by assuming some set of prompts is representative, and nobody can verify that assumption, including the person who made it.
Which means prompt selection is the result. Pick prompts where you're strong and you win. Pick prompts where a competitor is strong and they win.
Neither is technically a lie; both are just true of a set somebody chose.
We could produce a thread showing us beating the competition just as easily, and we'd be doing exactly the same trick.
The underlying data is noisy anyway. The same prompt can return different answers on different runs, so any single sample is a snapshot rather than a measurement.
Two questions worth asking of any AEO claim, including ours:
Who picked the prompts, and is there any evidence people actually ask them?
Is this compared to itself over time, or to someone else's number? Citation rate is only meaningful against your own tracked set.
Our strategy is not perfect. We have a lot of blindspots and we try our best to stay honest and grounded about them, but be skeptical of anyone claiming they've "won at this".
There's far too much room to fudge the numbers for these to be taken too seriously.
Ping us in #team-editorial if anything here is still unclear.
Anyone at PostHog can write a blog post, and we'd love you to! You don't need approval or permission from the .
This page covers the basics, whatever your role or topic. If you're an engineer writing about something you built, writing blogs as an engineer goes deeper on tips for that sort of content.
Why write a blog?
Content is the main pillar of our marketing strategy, and blogs are a key piece of that.
It's also good for your career! People who've written good blogs at PostHog have received lots of industry attention and discussion on socials.
Finally, sometimes it's just useful to create a blog as a linkable artifact to explain a topic instead of repeating yourself dozens of times. It can be an "in" to talk to customers or an explanation of how something works at PostHog.
Is my idea worth writing about?
Our audience is the people we build for including product engineers, founders, and the teams around them. That's a group you have a lot in common with, so if you are excited enough to write something, it's probably worth a blog. But if you're still not sure, you can share the idea in #content-and-video-ideas.
Should I write a blog, a newsletter, a tutorial, or a doc?
Blog: An opinion, story, guide, or comparison. Most common.
Newsletter: build mode, our weekly Substack issue. Usually more for trending dev topics and designed to be highly actionable. Talk to Ian Vanagas first if you want to write one since they're much higher lift than blogs.
Tutorial: Anything that's like "how to do X in PostHog." Usually guides with a single path to follow along through them. Go in /contents/tutorials.
Docs: Features, context, resources, and references for tools. Canonical and structured.
Tips for writing good blogs
Read the style guide for how we write, and brand foundations for how we sound. Those two are the source of truth – the rest of this section is only the stuff that's specific to blogs.
Titles
Having something interesting to say matters more than the title – you can usually find a title to fit a good idea, but no title saves a boring one. That said, the title is what someone judges in search results, in a feed, and in an AI answer, so it's worth spending time on. Some that worked well, and why:
Avoid being vague or boring ("Our approach to marketing spend"); if a generic B2B SaaS company would write it, we shouldn't, but don't put being funny/clever above being clear.
How it'll reach people
Decide who the post is for and how it'll reach them before you write it, not after you publish. It really influences how you write it. Most blogs will be shared through one of these:
Social – fast and spiky, and how opinionated or surprising posts find their first audience. See the social media handbook and the LinkedIn guide.
SEO (search and AI answers) – slow, compounding, and the bulk of our long-term traffic. Right for comparisons, "best X tools" lists, and evergreen guides where there's real search demand. See the SEO guide.
Product marketing/email – stuff that's going to be distributed for people already interested in or using PostHog and on one of our product marketing email lists already.
Drafting
Preview as you write. Draft in this Google Docs template to see roughly how the post will look on posthog.com.
Don't let AI write the whole thing. We encourage using AI for research, outlining, and finding the weak spots in an argument, but avoid using it to actually write the sentences. Readers can tell, and we will ask you to rewrite it if it's too obvious.
Consider adding internal links for SEO. The SEO guide covers how many to add and what anchor text to use.
Don't sweat the mechanics. En dashes, sentence case, image sizes – we'll fix anything you miss during review.
Submitting for review
All blogs must be reviewed by someone on the Editorial Team before publishing.
Before you submit, make sure you have:
A hero image (grab a template from the blog graphics Figma, or request art for something custom), correct frontmatter, and a post that follows the style guide. Check the deployment preview on your PR to see how it renders.
An author entry in src/data/authors.json. The handle you add there is what goes in the author field of your frontmatter – see metadata for the format.
To submit, simply create a pull request. Add your .md file to /contents/blog in the posthog.com repo. It will automatically add the Editorial Team as reviewers.
If you're already talking to an editor about this blog post, add them individually as a reviewer, too. Otherwise, someone will pick it up shortly. Expect one or two rounds of feedback. If you don't hear back from us within a day, ping the #team-editorial channel in slack.
Once it's approved, go ahead and merge to publish!
Feature trailers are social-first videos designed to create excitement, interest, and awareness around new PostHog products and features. They can also be used as short demo videos for product pages and docs.
If you want one made, here's how the process works and what to expect.
Types of feature trailers
There are two types of feature trailer, depending on how much time you have and what you're trying to achieve:
| Type | Description | Production time | Example | |---|---|---|---| | Teaser (under 30 seconds) | Pure vibes, not a story. It shows a single user experience and is designed to create buzz and excitement about a new feature. | Up to a week and a half | PostHog Code teaser | | Use case video (30–90 seconds) | Narrative-based, showing a single specific use case for PostHog product or feature. Ideally based on our own usage of the product. | Up to two weeks | Slack app feature trailer |
The team can also make longer demo videos (e.g. 3 to 5 minutes or more), though these aren't feature trailers. They're a much bigger project that can take 4+ weeks, and work best on a product that's already stable – i.e. UI is finalized and unlikely to change. That's why we tend to avoid them for launches and announcements.
How to request a video
1. Message the video team
Drop a message in Team YouTube on Slack explaining what you want to create and why. There's no official request process – just start the conversation.
Important: Videos typically take two weeks to make, but a minimum of four weeks is necessary if you want to hit a specific date. This is because we need to fit things around existing video work, and leave time to agree a creative direction before production can start.
2. Talk through scope and timeline
The team will advise on what else is in progress and whether your timeline is realistic. If it's a yes, you'll move on to a storyboard.
3. Agree on the example use case
Product marketer should lead this and collaborate with product manager / product team. A good example use case:
Comes from our own use of the product, with something real you can put on screen, like a PR, a report, or a session recording.
Shows what only this product can do. If another PostHog product could have surfaced the same thing, the example isn't making the case.
Is recognizable to someone outside PostHog. Viewers should see their own problem in it without knowing how we work.
4. Create a storyboard
As the requester, you'll put together a short storyboard of what you want the video to cover, built around the example you agreed on. This is especially useful for 30–90 second feature trailers.
Also note any existing assets for the product – webpage, blog post, social post, artwork, custom hoggies, etc – and provide URLs if you have them. The team can reuse these rather than starting from scratch.
The storyboard doesn't need to be polished. It doesn't need a creative vision or production-quality assets. All it needs to do is convey the narrative beats you want the video to hit. For example, the storyboard for PostHog self-driving laid out: show the before and after, show a user solving the problem, ship the fix, then reveal that it was actually fixed autonomously using PostHog self-driving. Each beat just needs a note and a screenshot or rough screen recording.
5. Review the storyboard together
You'll meet with Jordo and Andy to talk through the storyboard and make any changes. Once everyone's happy with it, Jordo will turn it into a scratch edit – a rough moving version of the storyboard with a draft voiceover and script. It'll have plenty of missing pieces, but it gives you something to react to.
6. Iterate on the script and visuals
From here, you'll go back and forth refining the script and wording, then refining the visuals.
Expect to see roughly three versions of the video as it comes together:
The basic storyboard version.
A more refined version, with the script mostly locked and closer-to-final visuals.
A polish pass, catching any remaining issues or making final tweaks.
Depending on complexity, this can stretch to a fourth or fifth round of small fixes.
Timeline
The whole process usually takes up to two weeks, though it's often quicker depending on how complex the video is.
Content is the main pillar of our marketing strategy. Our strategy is to go _deeper_ and create better content as we grow. We don't rely on AI. We don't take content in exchange for links. We don't have arbitrary volume goals.
Product engineers: Software engineers who want to improve their product skills, understand users, and build successful new products.
Founders: Technical and non-technical founders seeking advice on how to run a successful startup.
PostHog users: Existing PostHog users who want to develop their skills and learn how to get the most out of PostHog.
B2B SaaS companies: Our ideal customers are B2B SaaS companies who need reliable user data and a simplified data stack. Most of our output is tailored toward B2B use cases.
Engineering tutorials: Guides on how to do specific things in PostHog. These can be for existing PostHog users, or aimed at potential users who are trying to solve a specific problem. Some, like How to set up Python A/B testing are SEO focused. Others focus on specific PostHog user pain points.
Newsletters: Our newsletter, build mode, is both a distribution channel and its own content category. Issues often curate or summarize our existing content, or that of others, into an easy-to-digest, snackable format.
How we work
We work autonomously. You don't need permission or approval to write something or make a change. You're the driver.
It is often helpful to share ideas in our #content-ideas Slack channel or as a GitHub issue. The GitHub issue template provides a structure to help you think through your idea.
You can ask for feedback whenever, but it's often better when it's:
Clear what feedback you're looking for. Ask if specific points or examples work, how you could word something better, where do you get bored, etc.
You have something solid to give feedback on. Again, pull requests are better than issues.
For specific details about writing, see our style guide. When you're ready to get writing reviewed, create a pull request for your Markdown file(s) (*.md or *.mdx) in the posthog.com repo. See developing the website for more.
Once you've gone through the pull request checklist and got an approval from the relevant person on the content team, you're ready to merge (aka publish).
Content distribution
So you've written a great piece of content. Now what? Here are various ways to spread the word:
1. SEO
If we can capture search traffic, we should try to do it. Start by identifying the keywords most relevant to your article, and aim for a mix of short-tail terms (broad, high-volume) and long-tail ones (specific, lower-volume but higher intent). Use them naturally throughout the piece – especially in headings, intros, and anchor text – and make sure your target keyword appears in the meta title and meta description.
Good SEO doesn’t just help your content rank in search, it also improves your chances of being cited by LLMs (aka AEO).
Share a post using either your own account or the company account, but note that the company account will have dramatically less reach than your personal one. If you feel something needs to go out on from company account, tag Liam Graham in #team-editorial.
Write a brief summary of the post while sharing as much content as possible in it. Good example.
Attach an image to the post (don't rely on the link's social graph preview). Again, you can use Add entry in the changelog to create a nice image.
Do your best not to sound "corporate" or serious. Authenticity is appreciated on Twitter. Have fun with it!
4. Share internally
Internal teams, especially sales, CS, and the relevant product team, can often make use of the content you write if they know about it. They can share it with customers and use the ideas and examples in their conversations.
It's worth sharing in their Slack channels directly as they don't see everything we publish. Asking them to smash the like button, subscribe, and share with their friends and family is a good tactic too.
5. Paid ads + newsletters
You can promote your post by buying sponsored slots in newsletters. Ian Vanagas has a list of newsletters and booked slots we can use to promote content. See sponsorships for more.
If you want to run a paid ad campaign on Reddit, Google, or Twitter, see the paid ads page.
It's a good idea to create an issue highlighting what you'd like to achieve in your campaign. Here's an example.
LinkedIn is the OG slop center, but it’s a popular channel with our ICP, important for recruiting, and our posts often do well there. Here's a few best practices to have your posts seen more on the platform.
Advice on LinkedIn posting
The hook is everything. Get people to click “show more.” What works:
Money - “We spend $X and here are the best things we learned”
Dilemma - “What would you choose X or Y?”
Provocative statements - “Collaboration sucks”
Transformation stories, before and after - “This product helped us go from X to Y”
Data reveals - “PostHog has seen an ~8x increase in traffic from ChatGPT in the last year”
Resource lists - “Here are the 10 best posts on X”
Takeaways - “After weeks of researching X, I’ve published Y deepdive. Here are Z interesting things I learned along the way.”
Work - “I wrote a 2000-word long article on how AI impacts performance of software and systems.”
Use lists and numbers.
Be specific with numbers. Say “$8,500” not “around 8k.” This feels more credible, like you aren’t making it up.
Ask yourself if there’s a story or anecdote you can use to make this real.
Be useful. Write the posts you want to read.
To drive clicks to links, either say “link in comments” and add it to the post ~6 hours later or include an image in your post. The algorithm hates direct posts to links.
A great graphic goes a lot way. “Zero-click” content like ByteByteGo gets thousands of likes with basically just a graphic. Information does better than memes.
Add a question at the end to get comments. People want to respond. Comments boost posts in the algorithm, often more than shares do.
Commenting on popular posts works, comments can get 30k+ impressions.
Posting time doesn’t matter to going viral, however it's good practice to post between Monday-Thursday and within 1 hour of standard working hours wherever most of your connections are based.
Posting daily beats 1-2x/week “perfect” posts. A lot won’t hit, but this will more than pay off for the ones that do.
If you are posting a changelog update, you can create nice images when clicking Add entry in the changelog. It's under the Social sharing header.
Once you've posted, throw a link into #shitposters-unite, and your fellow PostHog employees will shower your post with reactions, giving you a dopamine boost and helping it reach a wider audience.
Thank you to Lucas Faria for many of these tips.
Boosting posts from the PostHog brand account
If you post PostHog-related content to LinkedIn more than once per week and aren't scheduling it in advance, please:
Ask Liam Graham to add you as a content admin to the PostHog LinkedIn page if you aren't already.
Immediately after posting, switch your profile to the PostHog page and:
React (like, love, insightful, etc.)
Repost (the regular "Instantly bring [your] post to others' feeds" option)
The first couple of hours of a LinkedIn post are critical algorithmically, so sharing from the company page early helps maximize reach.
If you _are_ scheduling content, aim to engage from the brand account within ~an hour of the post going live (e.g. liking comments, adding the supporting article link as a comment). Liam will cover this when possible, but morning GMT posts may fall outside PST working hours.
LinkedIn posters and their newsletters
A primary way we use LinkedIn is to promote our newsletter, so here are some examples of people doing the same:
Every piece of writing we do has metadata included in it.
URLs and content folders
The URL is defined by the folder it's placed in and the filename.md of the markdown file - e.g. a post in the founders folder with the filename i-love-hedgehogs.md would have the URL /founders/i-love-hedgehogs.
Folders also decide _where_ on the website articles appear.
The main folders are:
/contents/docs - Docs.
/contents/blog - A catch-all posts section. Company announcements, technical deep dives, SEO-focused comparisons, and more.
/contents/founders - Posts written for founders.
/contents/product-engineers - Posts written for product engineers.
/contents/newsletter - Newsletters republished from build mode.
/contents/tutorials - Tutorials
/contents/customers - Customer stories
/contents/spotlight - Startup spotlight
/contents/handbook - The PostHog company handbook
Important: Some articles can rightfully belong in both the founder hub _and_ the product engineers hub. In this case, choose the most appropriate hub folder and then add the crosspost: field to your frontmatter so it appears in both. So, add crosspost: product-engineers to post a founder's hub article in product engineers as well, and vice versa. You can also add tags from either hub like normal.
Frontmatter
This is the default frontmatter for most posts:
---
title: "Your headline here"
date: YYYY-MM-DD
author: ["your-name"]
featuredImage: IMAGE URL
featuredImageType: full
tags:
- Content tag here
- Content tag here
- Content tag here
- Content tag here
- Content tag here
---
The frontmatter for tutorials is similar, but they don't require a featured image:
---
title: "Your headline here"
date: YYYY-MM-DD
author: ["your-name"]
tags:
- Content tag here
- Content tag here
---
Note: Each handle in the author field must match a handle in the authors.json file. If you're a first-time author, add yourself to authors.json in the authors data file using this format:
```json
{
"handle": "your-handle", // This is what you'll use in the author field
"name": "Your name",
"role": "Your role at PostHog",
"link_type": "linkedin", // Or "twitter", "github", etc.
We promote our newsletter across a variety of different channels. This page covers the paid options.
Budget
Budget plans can be viewed in this spreadsheet.
Uploading emails to Substack
Annoyingly, Substack doesn't have an API, which means that we manually need to upload emails we capture via our website, InstantForm ads, and most other paid marketing channels. This means that we have to manually upload these emails to Substack. Andy Vandervell does this once a week.
The emails are to PostHog via an event called newsletter_subscribed, which are sent to the #newsletter-sub-alerts in Slack.
If you wish to avoid doing this, an alternative is to send users directly to our Substack so they can sign up directly there. The drawback is that we're unable to send conversion events to 3rd parties (e.g. Meta, Reddit), so their algorithms won't know if their targeting is working (and we cannot send them the emails of people who signed up, because privacy).
You can still track how campaigns on Substack by using this loophole Ian Vanagas found:
Sign up for Substack with another email (lior+refer@substack.com or something, can create multiple).
Subscribe to build mode.
Go to https://newsletter.posthog.com/leaderboard and get your ref code/link. You can add the ?r=1tb4kk bit to any newsletter link and it will track who signs up using it.
See results here.
Meta Ads
In Q2+Q3 2025, we're testing Meta ads as a way to increase newsletter subscribers. You can view our ads in Ads Manager.
For access to the Ads Manager, please contact Lior Neu-ner or Brian Young.
We do not have Meta's pixel installed, as we do not allow any third-party cookies on our site. For tracking conversions, we use Meta's Conversions API via the PostHog destination.
🚨 Important: We must be extremely careful not to include any personally identifiable information. We should only include the fbclid parameter and the client_user_agent. Avoid sending personal identifiable information to Meta such as name or email.
Our ad creative can be accessed in Figma.
This issue has some information on learnings from previous ad campaigns
Instant Form ads
Meta has something called InstantForm ads, which enable users to sign up to our newsletter directly in the FB+IG apps without needing to open our website. Facebook then sends us these emails via Zapier.
Paid placements in other newsletters
We're not running paid placements anymore due to the high cost per conversion. More details in Slack
As mentioned above, Substack's attribution sucks. Historically, we instead created a custom link for each campaign using Dub.co and calculate cost per click to measure success. However, we should now be able to track signups using leaderboard + referral code workaround mentioned above.
We generally prefer to use a pay-per-sub model, which perform better and are easier to track. This issue outlines our current partnerships with other newsletter as of June 2025.
We look for newsletters that focus on software development and engineering. We don't care about list size or reach as much as we care about clickthrough rate (you can ask for their average CTR). Some we like working with and sponsoring include:
build mode: tools, tactics, and taste for product builders
build mode: the first newsletter dedicated to product engineers
The main copy is some variation of:
build mode is PostHog's newsletter dedicated to helping engineers improve their product skills. Learn how to talk to users, build new features users love, and find product market fit. Subscribe for free to get curated advice on building great products, lessons (and mistakes) from building PostHog, and deep dives into the strategies of top startups.
We have also found that linking to an article directly converts better than just a generic "subscribe to our newsletter" link.
If you need images, there is a collection of many sizes of them in Figma.
LinkedIn and Reddit Ads
We tried to run LinkedIn and Reddit ads for the newsletter but both were unsuccessful. Here's what we found:
LinkedIn is too expensive. Cost per link clicks were north of $5, about 10x-20x more expensive than meta ads
Reddit ads had CPCs similar to meta ads, but converted at a significantly lower rate (about 20x worse), meaning that cost per sign up was between $50-$90.
PostHog has unusually high editorial standards (especially for a B2B SaaS company). When I first started writing here, I struggled quite a bit. The feedback was good, but it was a lot, and for a while I couldn't tell if I was actually getting better or just spinning my wheels.
This handbook page is all the stuff I would tell myself from back then if I could. I wrote it for any future writers who join our editorial team. (It might also be useful for anyone trying to understand our unique developer content marketing and style more deeply.) It won't make the learning curve disappear, but hopefully makes it easier!
Before you write anything
Remember that you are new. Learning how to do any creative skill in a specific style takes time. Even the most talented writer in the world would make mistakes adopting PostHog's voice. As the wise old saying goes, "sucking at something is the first step towards being sorta good at something."
Don't compare your ramp-up speed to peers or people who've been here longer. Comparison is almost meaningless because everyone here has wildly different backgrounds It's why you were hired; it makes us better as a team. You have your own strengths and experiences, so make use of them.
While things are still relatively chill early on, read and absorb as much PostHog content as you can: blogs, newsletters, the handbook. Fix typos or update things as you go. Small PRs are genuinely appreciated and noticed.
Bonus tip: Keep a daily work journal. The random thoughts, questions, and observations you have as you're onboarding will make for great material later on. Even this guide is based on my notes from onboarding.
---
Timeline expectations for your first newsletter
A lot of people underestimate how much work it takes to write a genuinely good newsletter.
Experienced writers (i.e., people who've been doing this at PostHog for years) take about 2 weeks end-to-end to ship a great newsletter. That includes outlining, drafting, and 2–3 rounds of review to get to the finished piece (plus time juggling other projects in between).
As someone new, expect it to take longer. My first newsletter took me about 4–6 weeks:
1 week purely on the outline
5-8 rounds of feedback (shorter toward the end) spread over 2-3 weeks
The last stretch was tiny edits and infographics over 1 week
You will get sick of writing it. That's normal, too.
At the end, I didn't personally feel like my first newsletter was amazing, even though I was told it was very solid. Like I said earlier, remember it takes time to adapt to a new style for creative work.
To keep from going insane, have 1–2 smaller shippable projects running alongside the newsletter. In my first month, I tunneled on just the newsletter because it felt like The One Thing I had to do to prove to myself I could do this. In hindsight, putting all my confidence eggs in one basket added a lot of unnecessary pressure and honestly dampened my creativity. A blog refresh, smaller SEO post, along with handbook edits in parallel gives you breathing room. The early wins and visibility on the team are a real bonus, too.
---
The #1 guiding principle when writing here
Make it second nature to constantly ask yourself: "What do I want the reader's reaction to this piece to be?"
For example: "I want to challenge their assumptions and make them feel surprised."
Charles' Collaboration sucks article is a great example. It was right on the edge of clickbaity, enough for someone to comment "I was expecting to be annoyed but then I read it and was like, okay."
That's the goal. This one question should drive your title, your headings, your tone, your pacing — everything, really. A "How to do X" title can almost always be turned into something that makes a person feel something.
This matters most for newsletters, but it applies to everything we write. Our distinguishing factor is that we always have an opinion, a flair, a point of view. Without that, we'd become so bland, so fast.
---
Coming up with ideas
Ideas come from anyone and anywhere. A lot of times, conversations that happen in all-hands or Slack can be the inspiration for a blog. Basically, whatever you think might be interesting is game – you were hired as a developer who likes writing, so you have the advantage of already somewhat knowing our ICP's interests.
Even when you are new, don't let content ideas live inside your head. Turn them into a GitHub issue as soon as possible. Before you commit to writing something (including your first newsletter), have 2–3 issues with some preliminary research already done so you can make a more informed choice about what to actually write.
Not all ideas are good. Many ideas will die, fizzle out, or get picked up again later.
---
How to write for our readers
Writing nonfiction is a user-centered design problem. You have to start with: who is this for?
Our newsletter has three main reader groups:
Product engineers — developers who also own product work at startups
Technical founders — CEOs of early startups with technical or product backgrounds
Software engineers — not always our ICP, but developers who are curious about broadening their knowledge of product and startup culture (think: a SWE at a big tech company who wonders what else is out there)
Every article should naturally appeal to at least one of these groups — ideally all three, but that's not always possible.
Once you know your reader, make sure the intro and headline appeal to them immediately. The hook should answer: why should an engineer care?
Don't narrow the audience too much, but don't be so broad that you capture nobody. And note that the most compelling hook for your audience might not be the most interesting one for you to write and that's okay.
For example, when I was writing my first newsletter, 10x job posts for 10x engineers, I first kept gravitating toward hooks like "recruiting is so hard" or "we've all read boring job ads." Those were fun and interesting to write, but none of them were actually that targeted for any of the three audiences.
I realized that the best audience was technical founders who want to hire great talent early on, so I ended up opening with "your company is only as good as your people". It's a line that's been said a million times and I personally found a little dull. But it was highly effective for technical founders.
(Think of choosing a hook like choosing a character in a fighting game: sometimes your second-highest DPS character is the best pick because they do physical damage, and the enemy has a lot of magic resistance.)
You can also angle for one group first but weave in relevance for others. For example, the 10x job posts piece was aimed at founders, but by telling them what to look for when hiring great engineers, it was also implicitly signaling to the product engineers and SWEs reading it what traits they should aspire to have themselves while job searching and interviewing.
A few smaller principles worth keeping in mind:
Avoid double intros. Pick one good hook and then get right into the content.
Never say "it depends". If you're leaning that way, it usually means you need to go straight to examples
Paint the problem, then get to "how to deal with it" as early as possible. Developers want the useful part fast.
The line between funny and cringe is very easy to cross.
Don't lean on big enterprise company examples unless it genuinely fits the piece. It usually won't.
Snark and strong opinions are good. Pure negativity is not.
---
How to actually write a newsletter
The biggest lesson I learned was that writing a newsletter is 80% research, 20% writing.
What sets PostHog content apart is that we actually do the work. We don't just say what we think, we actually go and find out.
In other words, we gather evidence usually in the form of (1) real-world examples or (2) first-hand experience to establish credibility.
Real-world examples are observed data from other companies, blogs, and people — and this is what you'll lean on most as a writer. Research examples first. They don't just support your outline; they are the foundation of it. You might have a strong opinion and feel certain it's right, but you don't actually know until you go find out.
For example, for the 10x job posts newsletter, the "data" I used to develop my opinion were literally job posts from other companies.
You should include real examples even during your outline phase because without them, you don't actually have an informed opinion to build on yet.
Where to find good examples:
exa.ai — an AI search engine that's much better than ChatGPT for surfacing real examples (ChatGPT has a tendency to give you plausible-sounding examples that are just made up)
HN Algolia search — the comments can be just as useful as the posts themselves
Slack search for what PostHog people have actually said about the topic
GitHub — past PRs and issues at PostHog
Avoid using other blog posts as your primary source material. Basic digital literacy. "I saw it on the internet" or "I made that shit up" is not a valid source.
First-hand experience is more like "things we've learned at PostHog." Charles can write a piece that's mostly just his perspective because he has the experience and credibility as an exec — he'll almost always open with a personal anecdote or something from PostHog's history to establish that.
As a writer, you probably don't have that kind of experience to lean on yet, but you can do this too by framing things as "what we've learned at PostHog". I do this by reading all past PostHog content on a topic before I start writing, and then pulling out the real internal perspectives and examples. (Conveniently, you can save those to put in as internal links later!)
---
When your writing doesn't feel good
A useful gut-check: would someone who knows a lot about this topic share this with someone else? Worth noting that this person might not be the same as your target reader. For the 10x job posts piece aimed at technical founders, the person who'd actually share it is more like a seasoned recruiter or someone on a talent team.
If the answer is no, here's a quick diagnostic list:
The topic feels overdone and unoriginal. That's okay, originality isn't really the goal. Your goal is to write something that genuinely moves this audience at this time.
We've written about something too similar to this in the past. Also fine. Nobody remembers something we published two years ago. We commonly refresh old blogs into newsletters because the structure and style naturally evolves it into something different
It's too clickbait-y or fluffy. You probably need to go one level deeper. If it feels fluffy, it means you're not even convinced by your own argument. Find more concrete examples to back up your opinion.
It's getting dry and boring. It probably needs a stronger take. Talk to people with real experience on the subject. For example, when I was writing the "WTF does a PM do?" piece, I asked PMs directly what they thought were the most important parts of the role, and what made for a bad PM. That made it so much better.
The content is interesting but isn't flowing well. Rewrite it, then rewrite it again. When I was stuck on the intro for "WTF does a product manager do?", I wrote three completely different versions, then wrote out a pros/cons list of what I liked and disliked about each before deciding.
It's too deep and detailed. Try zooming out. Ask yourself "why would anyone actually read this?" Most of our newsletter topics hover at a certain level of detail. For example, we've written "An engineer's guide to talking to users," but we haven't written "An engineer's guide to dealing with difficult customers on quick calls." If the topic feels too niche, reconsider the scope (You'll probably also struggle to find enough examples for it.)
I can't figure out what's wrong, I just know it is. Ask for help — especially in your first few pieces. I asked Ian to write an entire section for my newsletter because I just needed to move on at a certain point.
I tried all of the above and it still just feels forced. The topic might just not be working. Depending on how deep you are, it might be worth pivoting rather than pushing through. You might just save it for a later issue.
---
When you hit writer's block
Writer's block is real and it will happen. It usually isn't actually about the writing — for me it's almost always anxiety or self-doubt in disguise. Things that helped me:
Change your environment. Go work at a cafe or outside for a bit. Especially since we work fully remote, getting out of the house makes a huge difference.
Switch to a different project. Something more tactical and less creative helps reset things and give you a little boost.
Brain dump — stream of consciousness, no editing, just write it. Even if you don't use the output later, it's like a nice warm-up exercise.
If your stuckness is rooted in self-doubt, try all of the classic self-care and self-compassion tips. Journaling, exercise, or whatever works for you. Staring at the doc rarely fixes anything for me, personally.
---
Things click eventually, but might just take longer than you'd expect. As always, don't hesitate to ask for help and feedback from the rest of the editorial team along the way. We want you to succeed!
Our newsletter is called build mode. It's owned by Ian.
Sent and managed via Substack, we put together an issue planning content for each installment of the newsletter. One person writes it and Andy edits and publishes it.
The newsletter is long-form, original copy, often based on blog posts we already wrote. It focuses on product and business lessons and information for engineers.
We run ads to drive subscriptions for this newsletter.
Art from previous newsletters is in Figma and diagrams are in FigJam.
How to write a good newsletter
These aren’t rules, just things that have worked well in the past. They provide some guidance on writing a successful newsletter.
Topic
Write about ideas, practices, and experiences unique to PostHog. Challenge conventional wisdom (ChatGPT is good for discovering what “conventional” is). For example, “Product management is broken. Engineers can fix it” goes against standard practice and details the way product management works at PostHog.
Help our audience directly. Our audience is engineers, founders, aspiring founders. Helping them get a job or launch a startup works well. Buying software, less so.
Let the examples guide you. It’s ideal to have strong examples in mind before you start. These can be from PostHog (like How we got our first 1,000 users) or from similar companies (like Doist, Gitlab, and Zapier in Habits of effective remote teams). It’s easy to say things, examples prove them.
Title
The title is the frame for the entire piece. It is worth spending more effort on upfront. Come up with multiple options and get feedback on them if you can.
Be bold and direct. Address common questions. Focus on a specific role (engineers, founders). In retrospect, “Using your own product is a superpower” is too boring and generic. Less is better: Gmail on mobile truncates titles at 35-40 characters
Get readers curious to learn more. Highlight a gap between where readers are and where they want to be. Hint at exclusive or non-obvious information.
Some title formats that have worked well:
Non-obvious lessons / advice [about topic]
Mistakes to avoid [doing a thing]
WTF is (thing) and what you should you care?
How to think like (person)
The magic of (thing)
What we learned about (blah) when doing (blah)
What nobody tells you about (thing)
X things we've learned about (thing)
Intro
Why trust us to write about this? We can write about hiring because 900 people applied in the last two months. We can write about A/B testing because Lior has run hundreds of them. Build credibility.
Use a counterintuitive take as a hook. If you’re writing about something we do differently than others, the intro is a great place to start. For example: "When Tim and I first started PostHog in 2020, I was adamant we would never hire a product manager."
Clarify what the reader will get out of it. A playbook, framework, lessons learned, pitfalls to avoid. Better yet, what’s the benefit to them? More sales, a job, product-market fit?
Structure
Headings, lists, and numbers are your friend. These help readers know where they are and create a sense of progress. 2, 3, 5, 7 are all a good number of points to aim for. 4 and 6 are awkward.
Use pattern breakers. Walls of text are hard to read. Make graphics in Excalidraw. Use hedgehogs. Add screenshots and quote blocks. Get more visually skilled people to help you if you need. Use these at the beginning and/or end of sections.
Think about rhythm: Two long paragraphs back-to-back is tiring. Use bullet points to break things up where needed, and mix short, clear sentences with longer ones, so the pace doesn't become monotonous.
Break up very hard to read sentences: Use a tool like Hemingway to identify sections that are very hard to read. Some long sentences aren't bad, but lots of them consecutively will drain the reader's attention. Aim for readability grade of 8 or less.
Use footnotes tactically: They're useful for adding context that's useful, but not important enough to bog down your core narrative. If something is hard to explain and slowing things down, consider using a footnote. They're also a fun way to add jokes, rants, easter eggs, and references.
Be opinionated: Sitting on the fence isn't interesting. It's ok for people to disagree with you, so avoid too much hedging.
Use graphics and charts: These are great ways for explaining complex ideas and make for great social content. Create bad version and ask the to help you make it better.
Be fun and lighthearted: We're writing about building software, not internet safety. Throw in jokes and memes occasionally. Again, footnotes and captions can be useful here.
But use memes sparingly: Too many memes can become overwhelming and a distraction. One per article is probably enough – two if they're really good, or the article is on long / serious side.
Address the reader directly: Say this "this will help you" rather than "this will help your company" or "this will help people". You're talking to one person, not a collective.
Publishing details
Having a good post preview image is important. Either create one using hedgehogs from the Hoggies file in Figma or open an art request to have Lottie make one for you (give her at least 1 week to do so). This needs to be 1200x630 px for the posthog.com OG image and 1456x1048 px for the Substack preview image.
We publish the newsletter on Substack and then add it to posthog.com/newsletter via GitHub.
Make sure links in the newsletter point to posthog.com and include UTMs like ?utm_source=posthog-newsletter&utm_medium=post&utm_campaign=enter_name_here.
This style guide explains our guidelines for contributions to PostHog's documentation, tutorials, and blog.
Be sure to familiarize yourself with our library of MDX components that are supported in Markdown to make your article more scannable and engaging.
General principles
Assume almost nothing
As you gain mastery of a product or feature, some things become second nature, but remember they weren't always so obvious. Call these out, and provide links to relevant docs or websites.
Make it easy for your reader to implement their feature or solve their issue, whether they are an expert or just starting out with PostHog.
Get to the point
If you're explaining something, don't wait three paragraphs to do so. Start with the explanation and expand later. Almost all articles can be improved by shortening (or removing) the intro.
Don't be boring.
Make it easy to read
Most readers will scan a page before committing to reading it. They're looking for signs it'll answer their question(s) and quality.
Use clear headings, diagrams and tables to demonstrate thoroughness.
Avoid hedging
We are opinionated at PostHog. That means avoiding hedging like saying "it's complicated" or "it depends." This is frustrating for the reader and doesn't add value. Instead:
Have an opinion.
Provide an example.
Do the research until you can do 1. or 2.
Style rules
Use American English
PostHog is a global company. Our team and our customers are distributed around the world. For consistency, we use American English spelling, grammar, date, and time formatting.
Use sentence case for titles
Write "Documentation style guide", not "Documentation Style Guide" and "PostHog has product analytics and session replay tools", not "PostHog has Product Analytics and Session Replay tools".
But...
Capitalize product names and proper nouns as appropriate
When using a product's name, capitalize it as a proper noun, like: "PostHog's second product was Session Replay." When referring to the general industry term while _not_ referencing a product name, you'd use it lowercase, like: "how many companies now offer product analytics."
Capitalize acronyms and define where needed
Write "URLs", not "urls".
Many acronyms, like that one, will be familiar to developers. When in doubt, link the first use of an acronym to a definition, or provide one.
Use the Oxford comma
Write "bananas, apples, and oranges", not "bananas, apples and oranges".
Why does this matter? Consider the old joke:
"There are two hard problems in computer science: naming things, cache invalidation, and off by one errors."
That doesn't work without the Oxford.
Use "enable", not "allow"
Allow is another way of saying permit.
Example: Your partner allows you to stay up late and play video games.
Enable means providing the means or opportunity.
Example: PostHog enables you to understand user behavior.
In most cases, PostHog _enables_ users to do things.
Add extra line breaks between long bullet points
Sections with long bullet point items are hard to read without extra line breaks (when looking at Markdown). For example, this passage:
Markdown Preview
Is harder to read than this passage:
Markdown Preview
Both render as the same list, but one is easier to read in Markdown. This isn't necessary for shorter bullet-point lists.
Use straight apostrophes and quote marks
Many writing tools, such as Google Docs, Notion and Word, add curly quotes and apostrophes. Please avoid using these. They can normally be turned off in the settings.
"Open source" vs "open-source"
Both can be correct depending on usage.
Open source should be hyphenated when it appears before a noun.
Example: "The open-source community is awesome"
But should be written without a hyphen in other contexts.
Example: "PostHog loves being open source."
Use British-style en dashes
While we default to American English in most things, we prefer using the British-style en dash ( – ) with a space either side rather than the longer em dash with no spaces (—) used in American English.
Example: "Don’t up vote your own content, and don’t ask other people to – post it and pray."
Please don't use a hyphen instead of en dash. On Macs, holding down Option and the hyphen key will give you an en dash.
<strong>A short public service announcement from Andy Vandervell:</strong>
As an editor, readability / aesthetics are more important to me than following grammar and style rules to the letter. British-style en dashes are a case in point.
Don't get me started on using hyphens instead (like - this) – that's just wrong. Here's that last sentence with an em dash instead... "Don't get me started on using hyphens instead (like - this)—that's just wrong". Doesn't that em dash look cramped and nasty?
Honestly, though, I don't care that much, but I will find and replace every em dash and orphaned hyphen on the website. It's fine. It's not a big deal. I'm cool about it.
Adding media
Images, gifs, and short videos
Most media for your article should be uploaded to Cloudinary (under 20 MB).
You can do this from posthog.com by signing in, clicking on your avatar in the top right, then clicking Upload media in the dropdown menu (available to moderators only).
Our uploader supports images, gifs, mp4 and mov, PDFs, and SVGs.
Image: Upload
Copy the link and paste it where you want the image or movie to appear in your file. A max of 1600px is usually good, as this is double the typical display width of an article. Using an image twice the size of the display resolution will make screenshots look crisp on hi-DPI/Retina screens.
Use the orig (optimized) size when adding a featuredImage to an article in Markdown frontmatter, as Cloudinary's resize strategy isn't supported by our Markdown parser.
There are MDX components available for embedding images or gifs (`) and [videos](/handbook/engineering/posthog-com/markdown#product-videos) (`).
Videos
Short videos (like screen recordings) should be uploaded to Cloudinary.
There are two other places we host videos:
YouTube - videos that are intended for wide distribution
Wistia - hosted videos used for embedding on PostHog.com (like our product demos) – like in product presentations, or for large videos (for blog posts or tutorials) that aren't beneficial to have on social media
YouTube embeds
When embedding YouTube videos, use YouTube's iframe embed code with the "Enabled privacy-enhanced mode" box ticked. This ensures Google doesn't drop a cookie on our website. You'll know it's enabled if the code includes "https://www.youtube-nocookie.com" in the URL. Also add the allowfullscreen attribute to the iframe so users have the option to watch the video in fullscreen (useful for reading code snippets).
Wistia
Jordo Dibb can upload videos to Wistia. It's best to also have a thumbnail image which can be uploaded to Wistia as well. Videos can be embedded on the site using our <a href="/handbook/engineering/posthog-com/markdown#embedding-wistia-videos">Wistia component</a>.
Best practices for images and videos
In most cases, PNGs are the ideal file format. Images are optimized for the web and converted to webp automatically. That said, don't upload 4K resolution images. Be sensible.
_Do not_ upload animated GIFs. They're large and lossy. Instead, record short clips as MP4s using Screen Studio and add them to your markdown file as you would any normal image.
If your article needs custom artwork, please file a request. See Art and branding requests for instructions.
If you plan on recording a demo, a screen share, or the PostHog UI for use on the PostHog website and/or YouTube channel, the PostHog YouTube team kindly asks you to watch the video below and follow the corresponding instructions for your recordings.
Important! While Loom is great for personal use videos, it does not meet our quality standards for videos that will be going on the PostHog website and/or YouTube channel. Please use Screen Studio for such recordings, steps listed below.
Feel free to ask any questions in the #team-youtube Slack channel.
Video:
You like cookies? Then watch this video. Plus, you’ll learn about how to properly set up Screen Studio and your recording area aspect ratio for PostHog videos:
Screen Studio is free to record and edit with, but exporting now requires a paid subscription. If you just need to hand a .screenstudio project to the YouTube team (see step 7), the free version is enough and you don't need to upgrade.
If you need to export the video yourself – for example to embed it in docs or the handbook – you will need to upgrade.
2. Set Recording Settings
Before recording, make sure you correctly set up the three Screen Studio settings listed below:
Camera If you’d like to record yourself during your recording, make sure you select which camera you want to record from. Most likely your laptop’s camera.
Important! Set the “Max Camera Resolution” setting to 4K or the highest available option. If you’d like to record your camera but don’t want to see yourself as you record, enable the “Hide camera preview” option. If you don’t wish to record yourself, then select “Don’t record camera”.
Microphone Select which microphone you’d like to record your audio from. Be sure to enable the “Reduce noise and normalize volume” setting.
System Audio If your screen recording requires that you capture audio from an app, then select the appropriate option. Otherwise, select the “Don’t record system audio” to ensure no system audio is recorded.
3. Set Up 16:9 recording area
You’ll need to ensure your recording area is a 16:9 aspect ratio. Most displays are not 16:9 by default. If yours is not or you are unsure, follow the instructions below:
Select the “Area” option in the Screen Studio toolbar
Click on the “Any” drop down and select 16:9
Adjust the recording box to be as large as possible while retaining the 16:9 aspect ratio.
Adjust the recording area and your browser to completely fill the 16:9 recording area and so it only shows the PostHog UI.
Do not record:
Your browser URL or bookmarks
Your computer’s menu bar
Your computer’s docks/apps
4. Prepare to record
Run through this checklist before recording to make sure things go as smoothly as possible:
Turn off your computer’s notifications or set it to Focus mode
Silence your phone
Ensure your notes/script are readable, outside of the recording area
If you are recording yourself, make sure you’ve taken measures to ensure you are positioned and lighted properly. Read this great guide for how to do this well.
5. Do a final test
Before you start your actual recording, run through these quick steps to ensure everything is set to go:
Double check all the steps listed above.
Click record and do a 10s test run. Speak some lines, make sure your recording area is only recording the PostHog UI, etc.
Stop the recording and preview it, with sound on. Make sure your audio was recording and everything looks and sounds good. Delete the test draft.
6. Record
Now simply record and do your thang! Use the Pause option to take breaks, answer the doorbell, compose yourself, etc. Re-enable when you’re ready, or use the restart function if you want to give it a fresh go.
Don’t be afraid to start lines over if you mess up or say “Cut”. Our post team loves direction vs having to assume things, so feel free to give us direction in the recording, do multiple takes, etc.
Click the red record icon to finish recording.
7. Save as a Screen Studio Project
Once you’re done recording, it’ll either open the recording up into a new editable project or you’ll see the “Edit” option in the preview box, which you should click.
Now simply go up to the “File” menu and select “Save as...”.
Use your name or the project’s name for the file name, and ensure the file ends in the .screenstudio file extension.
Important! If your recording contains any customer-sensitive information that needs to be blurred or removed, please leave exact timestamps of where the information appears in the recording project. Please triple check your work, as our post team will not always be able to catch this on our own.
8. (Optional) Export and upload to Cloudinary
If your recording is going into docs or the handbook rather than through the YouTube team, export it from Screen Studio (this needs a paid plan – see step 1), then upload it to Cloudinary to get a URL you can embed.
You don't need a Cloudinary login. Sign in on PostHog.com, then choose Upload media under Moderator tools in the account menu, upload the file, and copy the URL. See uploading assets with Cloudinary for the full walkthrough, and videos in Markdown for how to embed the URL once you have it.
Keep exports under 20MB so Cloudinary accepts them – for anything longer, use Wistia instead.
And voila! You’re done! Thanks for following these steps, and feel free to ask any questions in the \#team-youtube Slack channel.
Don't obsess over exact-match keywords, ask: What is the searcher really trying to accomplish? For example, a user searching "difference between retention rate and churn" will likely also benefit from actionable insight on improving customer retention, not just definitions.
We craft our content to address those underlying needs. Cover the main topic thoroughly, include related sub-questions and themes, and anticipate next steps a reader might take.
Here’s what that might look like for "Retention rate vs churn"
Quick answer first: Retention rate shows who stayed, churn shows who left. If churn is 20%, retention is 80%.
Context next: Add formulas, a simple numeric example, and a short paragraph on why retention matters for growth.
Related questions:
What’s a "good" churn rate?
How do you reduce churn?
When should you focus on retention vs. acquisition?
Next steps: Link to guides on retention strategies, cohort analysis, and churn reduction.
2. Make it easy to digest
When answering a question, lead with the answer first, then expand with supporting details. This helps impatient readers and aligns with how AI tools select responses.
We keep our structure simple and scannable:
Use a clear heading hierarchy (H1, H2, H3) so readers and crawlers can follow your logic.
Use one H1 per page to avoid confusion about the page’s main topic.
Write short paragraphs and use bullets or numbered steps for lists.
Use plain language – drop the jargon and explain terms plainly so anyone (and any language model) can understand what you’re talking about.
Facilitate easy navigation – use anchor links or a mini table of contents for long articles.
Use visuals – charts, tables, and screenshots make key points faster to absorb.
Structured extracts – add TL;DRs, “Key takeaways” boxes, or pull-quotes to highlight what’s most important at a glance.
3. Headlines matter
Our headlines are the front door to our content – they’re what convince someone (or an AI) to pick us. They should stand out in search results, be enticing enough to click, and still make it clear what the page is about.
We should be bold, creative, and opinionated – but not so clever that we lose relevance. If every result has a nearly identical headline, we win by being different, but if we get too abstract or too witty, we risk missing the actual query intent and dropping out of search entirely.
Quick rule of thumb: If it sounds like every other search result, sharpen it. If it sounds clever but hides what the article’s about, clarify it.
4. Demonstrate expertise and authority
The internet has never been so full of words. The friction for content creation has dropped to nearly zero (thanks, ChatGPT), which means the bar for quality has shot up. The only way to win attention is to raise the bar: create content that actually teaches, clarifies, and adds something new.
Establish yourself (and PostHog) as a subject matter expert. We do this by:
Backing our claims with data. Include relevant statistics, research findings, or mention credible studies. Citing reputable sources or adding footnotes for facts can also build trust (and AI models tend to favor answers with a cited source).
Including expert insights. If possible, add quotations or insights from experts (it can be an internal one). An authoritative quote or a first-hand insight provides uniqueness and value that generic content lacks.
Offering a unique point of view or proprietary data. Bring something new to the table – something only we can. Share internal data\* or a novel insight from your personal experience. Google’s algorithms now consider “information gain,” which measures the uniqueness of information your content adds beyond what’s already out there.
Be thoughtful about what you share – protect sensitive data and respect user privacy – but don’t shy away from leveraging the knowledge only we have. Our unique perspective is our moat.
5. Be conversational
Our tone is friendly, focused, and human – especially now that voice search and AI chat engines are shaping how people consume information. Content that sounds natural and answers questions simply is more likely to show up in featured snippets, People Also Ask boxes, and AI overviews.
That said, conversational doesn’t mean rambling. Stay on topic and be clear and direct. Think of how you’d explain the topic if speaking to a colleague – friendly but focused.
A more dialog-like tone can also help capture featured snippets or People Also Ask boxes, as the content directly addresses how users phrase questions.
Bad Q&A example
- Heading: Strategies for reducing customer attrition
- Body copy: Customer attrition is a key challenge for many businesses and must be addressed with a comprehensive set of initiatives. Companies should consider improving their product offering, implementing proactive customer success programs, and monitoring engagement metrics over time.
Good Q&A example
- Heading: How do we reduce churn?
- Body copy: Start by identifying where customers are dropping off – look at cancellation reasons, churn cohorts, and feedback surveys. Then tackle the biggest issues first, like onboarding problems or missing features. Even small fixes (e.g. a clearer onboarding flow) can reduce churn quickly. Follow-up questions we could answer: What’s a “good” churn rate for SaaS? What metrics should we track to spot churn early? How do we measure if our retention efforts are working? How can we build a feedback survey?
6. Don’t put all our eggs in one keyword basket
Good SEO articles always target more than one search term. While you may start with a core query (or prompt) in mind, remember there are always multiple ways to search for the same information. Sometimes it's better to target a similar but lower volume search term than the big obvious one.
For example, the parent search term "user persona" (27,000/mo) has numerous derivations:
Define user persona (8,100)
Create user persona (3,600)
Persona modelling (720)
Benefits of personas (50)
User persona examples (5,400)
Examples of user persona (260)
How to create personas (2,900)
What is a user persona (260)
User persona template (27,000)
We target clusters of intent, not just one keyword. Long-tail variations are often easier wins and build topical relevance. Over time, our page can rank for multiple terms and even capture the broad head term as authority grows.
7. Write for our ICP
The more specific we make our content, the more likely it is to resonate – and perform. This matters more than ever with AI-driven search and tools like ChatGPT's Deep Research, which don’t just answer the initial query but often fan out into follow-up questions and related recommendations.
For example, a generic “Best session replay tools” list might compete with thousands of others. But “Best open source session replay tools for startups” positions us as the exact match for a highly qualified search.
When we write, we should ask ourselves:
Who exactly is this for? What unique context, goals, or constraints does our ICP have?
What contextual qualifiers would they use? (e.g. “for nonprofits,” “for remote teams,” “for Europe in 2025”) and weave them naturally into the copy.
What’s next? Anticipate the next three questions they’d ask after reading and answer them in the same piece. This keeps us the source that AI models (and readers) turn to as the conversation deepens.
8. Updates work / are important
Publishing a great article is not the end of the story. SEO is an ongoing process, and one of the best ways to maintain or boost rankings is to keep content up-to-date.
How often this should happen is very subjective, but the more traffic a page gets the more often it should be updated. When updating, don’t just change a few words or the date; search engines are smart about detecting meaningful updates versus superficial ones. Add genuinely valuable content: new stats, a new tip, clearer structure, recent developments, etc. And if your last update was a while ago, consider adding an "Updated on \[Date\]" notice to show readers (and Google) that the page is maintained.
Likewise, updating and improving a page that isn't ranking is often the best way to get it to rank successfully. Just because something didn't rank at the first attempt, doesn't mean it never will.
9. Internal linking isn't optional
Internal linking is a vital part of successful SEO. It helps Google find our content and understand how pages relate to each other. It can also help prevent internal conflicts (where Google is unsure which article to list for a term), by signalling to Google what specific term we think a page should rank for.
Here are some best practices for internal linking:
Link early, where it makes sense. Google tends to value links placed higher up on the page more than ones buried at the bottom. So, when you mention a concept that you have a deeper article on, link it to that first mention if appropriate.
Use descriptive, varied anchor text. The anchor text (the clickable text of a link) should give a hint about the destination page’s content. Instead of saying “click here” or linking the same generic phrase every time, use keywords or descriptive phrases that fit naturally in your sentence.
Link relevant pages only. Ensure your internal links are contextually relevant. Don’t force a link where it doesn’t belong; Google can tell if links are unnatural. The goal is to guide readers to related content they’d find useful, which in turn guides search engines.
Don’t overdo it. A handful of well-placed internal links (3–5) is usually enough. You don’t need to link every other sentence. Too many links can dilute their value and be distracting for readers.
Maintain your links. Periodically, use tools or audits such as #alerts-broken-website-internal-links to check for broken internal links (if you reorganize pages or change URLs, update any old links). Broken links hurt user experience and can waste crawl budget.
10. Optimize for LLMs
We’re no longer just writing for Google – we’re writing for the answer engines too. ChatGPT, Perplexity, Claude, and Google’s AI Overviews are pulling from our content to build answers. To win those spots, we need to make our pages easy to retrieve, easy to quote, and obviously authoritative.
The goal is to make our content the easiest, clearest, most trustworthy answer in the room, for both humans and machines. How we do that:
Clarity over cleverness: Say the thing plainly. LLMs work best with clear, declarative sentences.
Structure for retrieval: Use clean headings, bulleted lists, and short paragraphs so answers can be extracted in chunks. Each section should stand alone if it’s pulled out of context.
Front-load the answer: Start with the takeaway, then explain. (Think: “TL;DR first, nuance after.”)
Semantic redundancy: Repeat key terms and phrases naturally – it helps LLMs reinforce relevance without guessing.
Authority signals: Cite sources, include data, and highlight expert input. Models tend to favor content that “looks” trustworthy. Author bios, sources, and first-hand insights boost trust.
Chunk quality: Keep sections focused. A 200-word section that completely answers one question is more reusable than a 1,000-word wall of text.
Stay fresh and correct: Outdated or wrong info can keep us out of results (or worse, get us quoted incorrectly). Include timestamps, years, and up-to-date references (“as of 2025”).
Favor Q&A format: Perplexity loves conversational answers and listicles (think “Top 5 tools for X”).
Consistency matters: Keep facts about PostHog accurate and aligned across different pieces of content.
Watch competitors: Monitor what SGE cites and improve on those answers to outrank them.
11. Steelman competitors
Many other companies "straw man" their competitors. They claim their competitors are worse than reality, focus on differences that don't matter, and make hyperbolic claims about how much better they are. We don't do this.
When writing about competitors, be honest about their capabilities. Assume they are reading and will dunk on you for being dishonest. PostHog may not have all the features competitors have today, that's okay. Our reputation and trust with readers is more important than whatever "marketing win" being dishonest gives us.
It's also okay to make mistakes here. Competitors change faster than we can keep up. Whenever we find a mistake, we fix it as soon as we realize. We also happily accept updates from competitors if they make our post more accurate.
Additional tips
Good metadata is like a handshake – it’s the first impression users (and AI tools) get before they ever see the page. Well-crafted titles and descriptions can improve click-through rates and help AI engines understand context.
Quick metadata checklist:
[ ] Meta title includes the primary keyword and stays under \~60 characters
[ ] Meta description is under 160 characters and compelling (can include primary or secondary keywords)
[ ] Each page has unique metadata (no duplicates)
[ ] Preview in a SERP simulator before publishing to check for truncation
[ ] Add dates, numbers, or benefit-driven language where relevant to make metadata feel fresh and worth clicking.
Useful SEO tools
We use and recommend all the following tools to all writers.
Ahrefs
Ahrefs is an all-in-one tool. It's useful for:
Rank tracking: We use the built-in rank tracking to keep an eye on our visibility in Google for terms we're targeting with content. It updates ranking every 7 days. We only track desktop rankings in the United States atm.
Competitor analysis: Arguably the most useful feature. Use the Site Explorer feature to analyze traffic and keyword patterns for competing websites.
Keyword research: There are better keyword research tools, but the Ahrefs Keyword Explorer is still a useful way to find and analyze keyword and article opportunities.
Site audits: We use Ahref's Site Audit tool to identify website issues – 404s, broken internal links, etc. A scan runs once a week. Andy looks after this.
Backlink analysis: Allows us to see who is linking to our website and competitors. We don't use this extensively atm, but it's useful every once in a while.
Keywords Everywhere
Keywords Everywhere is a very useful Chrome extension that adds keyword research context to Google searches and other popular SEO tools. It's a great way to do quick bits of keyword research and find related terms.
It's only ~$15 annually.
Google Search Console
While the data is somewhat sampled, Search Console is a useful tool for analyzing the top-level numbers, or specific pages. Especially useful for seeing exactly which search terms are driving traffic to a particular page – sometimes the results will surprise you.
Our primary platforms are X, LinkedIn, and YouTube. We optimize for them. Content is posted on secondary platforms, but it's not worth the resources needed to tailor content for them.
What we post
We post content that shows off our product, provides delight, and informs our audience.
When creating, evaluating, and putting out each post, we have to always ask the question "does this look like something another company would put out?"
If the answer is "yes", we have to go back to the drawing board, either in terms of the content itself or the copy that accompanies it.
The order of effectiveness for assets is video > graphics/photos > text only, and we prioritize what's posted accordingly.
Unless otherwise stated, we optimize for a mobile viewing experience, as that's where approximately 80% of our impressions on social media come from. That means photos in 4:5, and video in 9:16. It also means we include captions whenever possible, since approximately 80% of people also browse social media on mute.
We are not overly-concerned with everything PostHog-related needing to come from the PostHog brand accounts. On some platforms, LinkedIn especially, this is actually a hindrance: content performs much better and is perceived more earnestly when it comes from an individual.
Posts from the brand account follow our style guide, except if it's a reply.
Replies should be done in lowercase. This humanizes the brand slightly as it underscores that a human would have written it, and is in the same style that James uses on social media. More details on this can be found on the voice & tone handbook page.
Not a lot. We believe all social media metrics are bad. They aren't meaningless or not worth drawing insights from, but can be easily misconstrued to draw false conclusions. The performance of certain posts is to do with factors beyond the platform that they're on.
Because of this, we take a more holistic view at social media performance: we prioritize creating content our ICP would like, and look at metrics at a high level. Have we seen that a few videos edited a certain way have got way more engagements than normal? That's good insight, and we will use that learning going forward. Have we seen one video perform well in isolation? That's not good insight: we need more information and context before changing anything.
How to run social media for PostHog
There are two places to check a few times a day for opportunities to interact and repost: one is via each app's notifications. The other is the #brand-mentions Slack channel, where Octolens pulls in brand mentions from across several platforms. This channel is especially useful as it picks up mentions where we are not explicitly tagged.
On weekends at 11am PT, #weekend-brand-mentions has a summary of the 10 most relevant mentions we've received in the past 24 hours posted by a friendly bot.
To schedule posts in advance where we can, we use Typefully. Ask Liam Graham for a link to the team account.
Posting on X
We can think of content we put out on X in two silos: one is articles, and one is everything else.
X articles have performed very well for us on the platform, unlike on LinkedIn, so any time a blog post or newsletter goes out, we are default yes on whether or not we should cross-post it to X. When sharing X articles:
Use aggressive header styling (H2s in blog posts should be "Titles" in X's article composer).
Make sure all images are included (ask Liam Graham for a Claude skill that can do this automatically).
Take advantage of the tools X's article composer has, namely the ability to create tables and insert code and quote blocks.
For the banner image, create a 2000x800 frame in Figma, and adjust your artwork in it. Include an author icon inside the design.
Feel free to re-write headlines and any snippets of an article to be more appealing for the platform.
For "everything else", we follow the guidance above to optimize for mobile. Informative posts with a design or graphic will almost always outperform posts that do not have one. Copy should always be slightly unhinged.
We "like" all posts which are complimentary of PostHog to reinforce that behavior from users. We rarely retweet or quote tweet: only doing so for examples of helpful use cases that users share.
Posting on LinkedIn
LinkedIn is a platform that rewards individual contributions over amplifying company pages. As a result, we lean heavily on reposting content that employees and users tag us in, as it will achieve more reach.
The audience which sees our posts on LinkedIn is less interested in technical content than X, so what we share reflects that. Insight into the business of PostHog and testimonies of building from PostHog employees are what performs well.
Articles or posts are shared with a 4:5 graphic or photo and with the outbound link included at the foot of each post, only if required. This is an inexact science, as traditional advice is to never include outbound links or to bury it in the comments. However, LinkedIn-native articles have not performed especially well for us, so this is the logical best practice.
For specific LinkedIn posting advice on personal channels, see the LinkedIn posting page.
On these Twitter clones, our content consists of X posts, duplicated. In the case of articles, we duplicate our LinkedIn posts (4:5 image, short summary, link at bottom if necessary).
Because our offering is thinner on these two platforms, we can take more liberties with reposting use cases or mentions. Have fun with it.
Posting on Instagram
Instagram's a platform we are actively trying to mature on. Our goal is to set a cadence of posting articles in carousel format, interspersed with short-form video content.
Like Threads and Bluesky, we can take more liberties with the mentions and interactions we have, especially if someone tags us in an IG story when they're at a conference or event.
We experimented with YouTube from November 2022 to July 2023, but have paused creation and publishing for now. We may try again in the future.
Although videos were driving X00s of views each (some hit X000s), and we received some positive feedback, we didn't see an increase in signups, traffic, or mentions from the videos. For example, the video on why and how we use GitHub as our CMS got 3,000 views in 1 one week, but made no noticeable impact on signups.
We also were starting to run out of obvious tutorial and SEO blog content to turn into videos. Basically, we ran out of low-hanging fruit. New videos would have taken increasing amounts of time.
Learnings
The less PostHog-related videos did better across all three types.
Title and thumbnail matter more than video content.
YouTube growth compounds heavily, but it requires multiple years and 100s of videos to reach the scale we'd need for a meaningful impact.
Lighting is what makes the most difference in video quality.
The PostHog demo is the most important and popular video we have. It should be updated at some point.
OBS works well to manage the recording of videos (screen, audio, webcam).
Only 2.5% of video traffic came from posthog.com. 60% came from YouTube features like search, channel pages, or recommendations.
Some recurring reasons customers churn, and what we can do about them.
Things we can influence
Champion leaves
If our champion was the main user, their departure is high risk. The best defense: get more people across the org using PostHog before it happens. More teams using PostHog, more products adopted, more relationships across the org. Build relationships with more than one champion.
Champion isn't the decision maker
A great relationship with a non-decision-maker is good for context, but limits influence over PostHog adoption. Use them to introduce you to people who can actually move things — and remember decision-makers aren't always in leadership roles. Ensure team adoption, new feature roll-outs, or other key wins are consistently visible to decision-makers.
Customer replaces PostHog
Common reasons:
They built feature parity internally
We lack a critical feature
Leadership prefers a competitor
They got a sweetheart deal somewhere else
You can't always prevent this, but customers using multiple PostHog products are stickier. If they're switching for one specific need, you might keep them on the others.
When you spot a customer evaluating alternatives, get involved early and push for the changes that would keep them.
Poor customer experience
If a customer has struggled to get help or fast responses, turn it around by staying on top of their stuff going forward.
When you can solve a problem for them, solve it — and explain how, so they can do it themselves next time.
For feature requests, bugs, or anything else you're advocating for internally, circle back proactively. Don't wait for them to follow up. Provide updates if resolution is taking longer. Customers who've had a poor experience care most about communication and follow-through.
Customer can't extract value
Offer to work with their team. Set up regular meetings if they're open to it. Help them get the specific metrics that move the needle.
If their team doesn't understand how PostHog can help, run a workshop or training call with concrete examples.
Missing features or slow delivery
If they're an ICP fit, loop in the relevant PM and engineering team. PMs often want to talk directly to the customer.
Flag the churn risk openly in the team channel. We never want to lose a customer over a missing feature, but these conversations help our PMs prioritize.
Lack of trust in PostHog data
If a customer says PostHog data conflicts with what they see elsewhere, dig in. What stats are they comparing? Where's the implementation issue?
Customers who rely on a different source of truth are at long-term risk — they're not tied to PostHog. Fix this even when it's not an immediate threat.
Privacy, compliance, or data governance
Some customers have constraints we can't fully solve — e.g. they can't store data with third parties and need on-prem.
Make sure they know what privacy controls PostHog offers. We're anonymous by default, Session Replay masks sensitive data, and many customers don't realize what's possible. Useful links:
The Cohort Dinner is an opportunity to show appreciation for our customers, deepen relationships with our contacts, and get a group of people in a room talking about PostHog. This handbook entry serves as a guide for putting one together and making sure it is successful.
What?
"The Cohort Dinner" is a standardized format that we use to plan small dinner gatherings of customers, prospects, and PostHog people. We intentionally aim for the vibe to be less corporate, more fun, and it is paramount that the food is good. They have a soft cap of 25 attendees, and there should be one PostHog person for every 5-6 non-PostHog people.
They are always driven by someone that is part of Customer Success or Sales, and while fun, are not just an excuse to get together and buy expensive bottles of champagne. Going into planning, there should be concrete goals and a reasonable justification for why the dinner should happen. This likely looks like some mix of the following:
What expansion opportunities this helps move forward
What New Business opportunities this helps move forward
What contacts you are inviting and how they are meaningful to the relationship
This is not to say that there must be a direct 1:1 relationship between who is being invited and opportunities - at the end of the day, the goal is building relationships for the long term. However, it is important to make sure that that concrete impact can be traced back to holding these events.
When?
In general, we do Cohort Dinners under two scenarios:
As part of a team offsite
Any time there are a large number of PostHog people in one place is a good opportunity to do some community building in the city that is being visited.
As part of building community and customer relationships in your own city
You're the driver and if you believe there is upside potential from hosting a dinner in your city, let us hand you the keys. It is often effective to schedule the dinner around something happening in the city, like a tech week or a large conference.
Cohort Dinners should be intentional and require careful planning - the expectation is not to host these every week. A good rule of thumb is up to once per quarter in your home city, and ad hoc planning should happen alongside GTM offsites.
Who?
The best dinners bring a balance of people and perspectives. In general, we aim to achieve an equal proportion of each of the following personas when inviting customers:
Prospects
Anyone who is considering PostHog. New Biz has the most context on what's in flight, and it is worth asking them to invite some of their leads to come get a chance to see that we're not just names in Slack.
Expansion targets
This means anyone that currently has a TAM with open opportunities for cross selling. Do your best to find the right champions at the right time - e.g. if the expansion opportunity is on the observability side, it's much better to bring a Head of Engineering than a UX Product Manager.
PostHog evangelists
Who are your most PostHog-pilled customers in the area? They should be at this dinner! Arguably the most important cohort at the cohort dinner are people who use PostHog regularly, love it, and are happy to talk other peoples' ears off about all the different things they do with it.
You should also make sure to bring a number of PostHog people so that they can spread through the room and be part of small groups throughout the night. Everyone at PostHog is an awesome dinner guest (it's basically baked into our interview process), but try to think of the audience that will be at the dinner. Got someone coming who is evaluating our Managed Warehouse? Bring an engineer who is working on it!
How?
Planning a Cohort Dinner typically follows a couple core steps:
Making the event on Luma
To get access to our company Luma, speak to the kind folks over at Builder Relations. To generate a cover photo, refer to this Figma board for inspiration.
Deciding on a guest list
You can kick off the process using the cohort-dinner-planner in our skill store to pull together a list of customers and their users who are based nearby, along with their assigned owners. From there, individual account owners should hand select the users that they believe would be the most impactful at the dinner.
Finding and booking a restaurant
A key part of the dinner is the location - ideally, the restaurant you pick should be one that draws people to join, not just a space that caters to corporate events. An example of this was a dinner at Lunch Lady of Saigon in Toronto: multiple people who came stated that part of their motivation was that the restaurant has received so much hype lately but is super hard to get into. People also left knowing that we have good taste, and there are maybe thousands of articles at this point about how taste is everything in the age of AI so that is probably a good thing.
A number of our location-based Slack channels have PostHog employees' personal dining recommendations for people visiting, these are a great place to start. Outside of those recommendations, feel free to use your best judgement to pick a location that lends itself to good conversation (not too loud), excites and sparks joy, and can be booked for large groups.
Spreading the word
Invite your customers! In our experience, the most effective outreach is in DMs with people you already have a relationship with, closely followed by a message in a shared Slack channel with individual tags.
The dinner itself
Before the dinner, all PostHog attendees should be briefed on who is attending as well as any key context about the account that they are joining from. To gather this, you can export a CSV of emails from Luma and then run it through the shared dinner-attendee-brief skill.
At the dinner, have fun and talk to people about PostHog! The intention is not to make this feel like just another corporate dinner, but rather something that people are genuinely happy and excited to attend. Approach cross-selling opportunities organically:
If a cool new feature comes up, dive into it with the people at your table
If someone voices a pain they deal with regularly that PostHog solves, explain how we can help
Let your evangelists do the selling for you!
Documenting
Take pictures (or better yet, bring a PostHog person with a nice camera and an eye for photos. There are definitely a few of them!)
Send a follow up recap to #group-cs-sales-support and #team-builder-relations
Update any Salesforce opportunities with next steps (gotta keep things clean)
Expensing
Currently, the process for expensing Cohort Dinners is to use your personal budget. This is subject to change in the future.
Sometimes the most helpful thing we can do for a customer makes their bill smaller.
This page covers how we work on cost optimizations, how we record them with the cost optimizing tag in PostHog Customer Analytics, and how we share them with the rest of the team.
The principle
One of our customer success principles is to help customers save money, even when it costs us in the short term. A customer who overpays because of a bad implementation isn't revenue, they're a churn risk who hasn't churned yet. Doing what's right for them is the job.
You are not expected to justify a revenue decline that comes from a cost optimization. You are expected to add context to it, so anyone reading the number later can tell the difference between a customer we helped and a customer we aren't fully engaged with. The tag and a Slack message are how you add that context.
This is also why inherited accounts come with a 3 month grace period. We want you to right-size customers, not to leave a bad implementation in place because it happens to pay well.
Two ways a cost optimization starts
The customer asks. They tell you they want to spend less on PostHog. Risk mitigation and churn prevention covers how to run this: act on the request first, gather context after, and pause expansion work until they're back at a stable spend.
We offer. You spot something the customer hasn't noticed and tell them how to fix it. This one matters more, because they didn't ask and they'll remember that you did it anyway.
The cost optimizing tag
Add the cost optimizing tag to the account in PostHog Customer Analytics when the cost optimization starts and short term billable usage is impacted. There can be some time before the recommendations are acted on, so there is no need to flag this too early.
The tag means: I'm aware of this cost optimization, and I'm supporting the customer through it.
Add it when:
A customer asks for help reducing spend and you're working on it.
You've offered an optimization, and they have started to act on it (meaning revenue contraction has started).
Don't add it when:
Usage dropped and you don't know why. Find out first - an unexplained drop is a churn signal, so see when to flag an account as at risk.
The spend fell for a reason that isn't us: seasonality, a campaign that ended, or volume moving to another vendor.
You don't need to add it when:
They remove a product they were paying for but didn't need. There is not much to learn beyond "they didn't know they were paying for something they didn't need"
Cost optimization is a process that starts and ends. A customer that is constantly cost optimizing should be handled differently. Therefore, when the cost has stabilized and the optimization plan is completed, remove the tag. It explains a phase (the revenue contraction) but is not a customer trait.
Share it in #team-customer-success
When you add the tag, post a short message in #team-customer-success. The tag is the marker, the message is the story behind it.
Cover:
The account, and what they spend on today.
What the optimization is, in a line or two.
Whether they asked or you offered.
What you expect to happen to their spend, and roughly when.
How you found it.
The last point is the one people skip and the one worth the most. A cost optimization on one account is usually a pattern across several. If you found a customer calling identify() on every page load, someone else on the team has a customer doing the same thing and doesn't know it yet.
How to spot them
Cost optimizations are much easier to handle before the customer finds them:
Run a health check on accounts you've just inherited, and on anyone who hasn't had a technical review in a year. Most of the patterns above come straight out of that checklist.
Read event composition, not just totals. Use the usage tab on the account in PostHog Customer Analytics and their Metabase usage dashboard. A large $identify, $groupidentify, or autocapture share is the tell.
Watch #spike-detector. A spike with no launch behind it is usually a bug or a loop, not growth. These are the most urgent optimizations, and they may qualify for credits.
Listen for cost on calls and in Slack. A customer who mentions their bill once will mention it again to their finance team.
When you find one, work through the fix with them rather than handing them a list of what's wrong. The optimization is the easy part – being the person who found it is what keeps the account.
How to present recommendations
Two or three recommendations, each with a saving attached. A longer list reads like an audit and gets deprioritized as a whole. How you frame them is your call – this is one example, not a template.
Your $14k/month: product analytics $11k, session replay $3k.
1. Autocapture on your marketing site – $4.2k/month, 30% of your bill. Autocapture is 78% of your volume, mostly marketing pages, and you have no autocapture actions defined – nothing reads those events. Turning it off there removes most of that $4.2k. One line in your snippet config. You'd lose retroactive click data on those pages. Start here.
2. identify() on every page load – $2.8k/month, 20%. Called per page rather than once per session, which makes anonymous events identified at up to 4x the cost. Moving it to login should halve this. Small change, but it touches auth, so it needs an engineer. No analytical downside.
3. Session replay sampling – $3k/month, 21%. Half your recordings are under 10 seconds. Sampling at 50% with a minimum duration takes roughly $1k off. Config only. But you won't have the replay when a user reports a bug – if support leans on replay, skip this.
1 and 2 get you to about $9k/month without changing how you use PostHog.
Quantify roughly, keep the saving separate from the tradeoff, and say what the change actually takes – their engineering capacity decides what happens next. Don't invent numbers, and don't assume the biggest saving is the right one. Customers know their business better than we do.
Common cost optimizations
Most of the money sits in a handful of patterns. This isn't the full list, and it isn't the diagnostic guide – checking the health of a customer's deployment has a checklist and some queries to run.
| Pattern | Why it costs them | Where to point them | |---|---|---| | Identified events by default | Every event creates a person profile, and identified events can be up to 4x the cost of anonymous ones. Common on marketing and content sites, where person profiles buy them nothing. | Anonymous vs identified events | | identify() called too often | Called on every page or in a loop, it inflates event volume for no analytical gain. Their "refused to merge an already identified user" ingestion warnings are a good confirmation. | Call it once per session | | group() called too often | The same problem, in $groupidentify events. | Call it once per group per session | | Group analytics paid for, not implemented | They pay for the add-on and can't use it. | Help them implement it if they're B2B, or tell them to remove the add-on | | Autocapture noise | Most of their events are autocapture and they've defined no autocapture actions, so they're paying for events nobody looks at. | Tune or turn off autocapture | | Session replay recording everything | Short, low-value recordings bill the same as useful ones. | Control which sessions you record |
For customers with significant LLM spend, LLM cost optimization is a field guide you can work from and share with them.
When a human-managed account churns from PostHog, we share learnings in #customer-churn-retros. The goal is simple: learn from what happened so we can prevent it next time.
Who does this
The CSM or AE who managed the account writes the retro. Post it as soon as possible after the churn (or even when the risk is first surfaced as a possible churn) - while the details are fresh.
What to include
Keep it concise. We're looking for signal, not noise.
Basic info
Customer name:
ARR at churn: $X,XXX
Tenure: X months/years
ICP fit (1-10): X/10
Scoring guide:
1-3: Poor fit (wrong industry, too small, misaligned use case)
4-6: Marginal fit (some alignment but missing key characteristics)
7-8: Good fit (matches most ICP criteria)
9-10: Perfect fit (textbook ICP customer)
Primary reason for churn: One sentence
What we did well
Bullet points. Be specific about what actually worked:
Things we tried that had positive impact
Successful interventions or saves along the way
Strong relationship moments or engagement wins
Features or support that resonated
What we could do better
This is the important part. Be honest:
Warning signs we missed or ignored
Outreach we didn't do or mistimed
Technical issues we didn't catch early enough
Relationship gaps or communication failures
Contract/commercial missteps
Don't sugarcoat it. If we screwed up, say so.
Product learnings
What did this churn teach us about the product?
Feature gaps that mattered
Integration or performance issues
Competitive losses (what did they switch to and why?)
when an account in an AM's book contracts or fails to grow and the AM wants it removed from the book, we should retro the account like a churn. We should run these any time an account is removed from a book, a cross-sell is lost, or we see usage contraction about 10% (either overall or for a specific product). Use
Basic info
Customer name:
Current ARR: $X,XXX
Tenure: X months/years\
Time in book:
Number of products adopted:
Primary reason for contraction / lack of growth: This is the meat of the retro and what we care about qualitatively to help us refine book composition.
| # | Primary reason | Diagnostic questions (the qualitative meat) | Headroom heuristic — what to check | | --- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 1 | Grew to saturation point | Are there current or future products that make sense? Have we _really_ saturated them? What would trigger bringing them back into a book? | Test all four headroom sources before accepting saturation: use case gaps, workloads (apps/products/BUs instrumented vs. total), free-tier usage below paid threshold, commercial levers (credit conversion, annual, package fit). Saturation is only real if _most_ of these hold: all applicable use cases at meaningful spend; single fully-instrumented workload; customer states no expansion roadmap; flat/declining usage 2+ quarters; failed expansion convos with no actionable reason; price sensitivity dominating. | | 2 | Mis-qualified — we thought it was a growth account | Why did we think it was a growth account? What was the _specific_ opportunity we were targeting? What do we know now that clarifies growth status? What could/should we have known at add time? | The opportunity must have attached to a person. A generic product observation ("they don't use session replay") was never an opportunity. Also check whether the original size estimate was bottom-up (usage × published pricing, customer-provided budgets/team sizes, comparable accounts) or a guess. | | 3 | Customer-side change post-add | Acquired? Business folded? Champion left? Priorities shifted? Market dried up? | Headroom may still exist but is unworkable today. Identify the event that would re-open it (new champion, funding, post-integration replatform, budget cycle). | | 4 | Product gap / fit issue | Rocky beta enrollment? Tried a product and hit issues? Did we sunset something they need/use? Did their product needs change? Did they pick a competitor? | Re-run use case gaps against their _current_ business model, not the one at add time. Distinguish "gap we can close" (roadmap/beta maturity → Nurture) from "gap we won't close" (competitor won, product sunset → Release). Feed to product as a fit signal either way. | | 5 | Regulatory / operational barriers | Legal requirements we couldn't meet? Approval process that killed the growth? Did the decision sit with a different business unit? | Headroom is real but there is no priority is making it happen. Note whether the blocker is permanent (compliance we won't build for) or procedural (wrong BU, security review) — the latter is a re-entry path via a new workload/BU owner. |
Example retro
Customer name: HogFlix ARR at churn: $42,000 Tenure: 14 months ICP fit: 8/10 - B2B SaaS, 75 employees, solid PMF Primary reason for churn: Switched to Amplitude due to advanced analytics needs we couldn't meet
What we did well:
Strong relationship with eng team, they genuinely liked us
Proactive about billing limit management, saved them $8k over tenure
Quick response on support tickets (avg <2hr)
Successfully onboarded them to 4 products
What we could do better:
Saw usage decline 3 months before churn but didn't act fast enough
Never connected with their PM team, only eng - left us blind to analytics requirements
Should've involved product team when they asked about funnel analysis 6 months ago
Missed that their SQL queries were getting more complex - signal they needed more
Product learnings:
Lost to Amplitude's behavioral cohorting and advanced path analysis
They needed cross-product funnels we don't support well yet
Data warehouse integration wasn't mature enough for their analysts
Tagging @max-ai team - they wanted AI insights we couldn't deliver
Process learnings:
Health score didn't catch declining SQL query complexity (possible new signal?)
Need a playbook for "single-department adoption" risk - eng loved us but PM didn't know we existed
Should trigger alert when customer starts evaluating "advanced analytics" docs heavily
---
Tips for writing these
Be direct. This isn't a CYA exercise. If you missed something, own it.
Focus on prevention. Every retro should have at least one concrete "we should change X" takeaway.
Tag people. If product or process changes are needed, @ the relevant teams.
Don't make excuses. "They were never a good fit" isn't helpful. Why did we take them on? What should we have done differently?
Keep it readable. Use bullets. Be concise. Respect everyone's time.
Most customer calls follow the same script. You agree to topics in advance, audit the account, prepare a demo, then spend the call walking the customer through what you prepared. It works, but it puts you in front of the customer instead of beside them, and it caps a call at the two or three things you had time to prepare for.
This page describes a different way to run the call, where the customer does most of the talking and most of the demoing, and the detailed answers come afterwards. It has worked well enough that we recommend it as the default.
The old way
Agree topics with the customer ahead of time.
Audit the account and prepare demos for those topics.
On the call, set the agenda and demo what you prepared.
The problem is not the prep, it is the assumptions. You audit what you guess matters, you demo what you guess helps, and the customer spends the call watching. If they think of something new halfway through, there is no room for it.
The customer-led way
Still agree topics ahead of time. The customer should know what the call is for.
Set the agenda at the start, and make it explicit that this call is theirs. Tell them you want them to walk you through how they use PostHog, where they hit bottlenecks, what they have already tried, what questions they have, and what would move the needle most for them.
Ask about goals first. What are they trying to achieve, which metrics matter, and what do they care about most right now. Everything else on the call gets weighed against this.
Have them demo to you. Screen share on their side, not yours. Watch how they actually use the product, what they click, where they hesitate, and what they work around. See what is confusing.
Tell them up front that you will follow up in writing with specifics for everything covered. Notes, screenshots, click-by-click walkthroughs, and Loom videos where they help. They should leave the call knowing they do not need to remember anything.
Recap before you end. Repeat back everything you heard and get them to confirm each point, so you know exactly what they need before you start working on it.
After the call, do the audit. Now it is driven by what they told you rather than what you guessed, and each follow-up can go as deep as it needs to.
Why it works
The customer talks, you learn. You see their real constraints, their real workflow, and the things they have already tried. That is information you cannot get from just an account audit.
You come back with more. A prepared demo covers two or three pain points. Letting the customer go deep routinely surfaces significantly more, because people think of more as they talk.
The follow-up is better than a live demo. Each item gets polished instructions, screenshots, or a short video, delivered so they can work through it at their own pace. They learn how to do it themselves, not just how to solve today's problem.
It takes the pressure off. You do not need every answer on the call, you do not need to rush through a list, and you rarely need a second call because time ran out.
It removes prep based on guesswork. The audit happens after the call and targets exactly what they raised.
When to use it
Use this as the default for check-ins, health calls, and any call where the customer has brought their own list. It is especially useful if you tend to feel nervous going into calls or feel like you are racing the clock, because the structure gives the customer the floor and gives you the room to answer properly afterwards. Defer to the follow-up if needed.
Keep the old approach for calls that are genuinely about showing something new, like a product launch walkthrough or a training session the customer asked for - make sure the customer knows what to expect before the call if this is the approach you're taking.
Helpful sample checklist
Before the call
[ ] Topics agreed with the customer
[ ] Agenda ready, framed around them walking you through their setup
On the call
[ ] Ask about goals, metrics, and what matters most
[ ] Customer shares their screen and demos
[ ] Capture bottlenecks, things tried, questions, and what would move the needle
[ ] Say that everything will be followed up in writing
[ ] Recap and confirm each point
After the call
[ ] Audit the account against what they raised
[ ] Send the follow-up with notes, screenshots, walkthroughs, and videos per item
Customer Success Managers (CSMs) help customers get more value out of PostHog so they stick around. That means helping them onboard, train their team, work through support issues, find cost savings, and advocate for them inside PostHog.
Principles
Show, don't tell. Help customers prioritize their needs, deliver bad news early, and stay on top of their questions. Under promise, over deliver.
Help them save money, even when it costs us short term. Long-term value matters more.
Be their voice inside PostHog. Advocacy only works if you're willing to go to bat for them. Push product and engineering to understand why a feature matters.
Who we manage
CSMs cover all customers above $20k ARR, whether they're long-time customers whose spend tipped over the threshold, new business handed over after closing, or customers new to PostHog on an enterprise plan.
What we're aiming for
Our primary goal is retention, and the team target is 120% NRR (see how we work for how that's calculated and how it ties to bonus). We hit that by being genuinely helpful.
A big part of the work is spotting customers who need help before they ask. The loudest ones will find us anyway. The ones quietly struggling won't, and those are the ones where a well-timed outreach, a usage pattern in Vitally, or just reading between the lines on a ticket makes the difference.
No two accounts need the same thing. Some need deep ticket involvement, some need strategic time, some just need a catch-up call every quarter.
The levers we have
Establishing and building relationships. Be the person a customer Slacks first when something breaks or when they want to try something new. Getting started with customers covers the first 30 days; the lifecycle of CSM engagement covers how the relationship evolves after that.
Implementation and setup. Getting the right PostHog setup for a customer's use case, and improving what's already there. Implementations evolve - the person who set things up may have left, the product changes, or they want something more mature. Getting this right matters because if the implementation is off, customers stop trusting the data, and that makes everything else harder. The basic implementation review and health check are the two main entry points.
Technical troubleshooting and support. Debugging customer issues (the broken event, the missing identify call, the misconfigured flag) and answering "how do I do X." CSMs at PostHog are technical, so this is yours by default, and it's also one of the best ways to build a relationship - you show technical credibility, get a better read on how they're actually using PostHog, and connect with the engineers who own the implementation. Handling customer issues covers how we work through these.
Finding and navigating friction. Spotting where a customer is trying to do something they expect PostHog to handle and can't. Sometimes the fix is implementation or troubleshooting, sometimes it's training or pointing them to a feature they didn't know about, sometimes it's a feature request or bug report on our end. When it's genuinely our gap, we give credits generously. Churn reasons lists the patterns we see most.
Monitoring health.Health tracking is our main signal for who needs attention. Don't just look at the score, look at what changed.
Cost optimization. We think about cost and value together - customers should be paying for what they're actually getting. Optimizing spend (over-ingestion, session replay you can sample down, products on a plan they aren't using) is one of the easiest ways to show you're genuinely helpful.
Running training sessions for a customer's team on a specific PostHog product, usually requested by the customer or proposed when we see a clear gap.
Credit purchases. Helping customers buy ahead of usage they can predict, like annual deals, top-ups, and plan changes. Renewals covers the mechanics.
This is a living document — we'll keep adding tactics as we learn what works. If you've found something effective, add it here!
Why this matters
Unengaged customers churn. But "just checking in" rarely works. The tactics below give you concrete, helpful reasons to reach out — so your outreach feels like a favor, not a follow-up.
The common thread: do your homework first, then lead with something specific and valuable.
Pre-outreach research
Before reaching out, spend 10 minutes understanding where the customer is at. This makes all the difference between a generic check-in and a genuinely helpful conversation.
Review their engagement metrics
Use the customer's PostHog usage data to understand what they're actually doing before you reach out. Look at:
What features they're using — insights, dashboards, recordings, etc.
Insight titles they've created — these reveal what business questions they care about
Recent activity — are they creating new things or just passively viewing?
For example, if a customer is creating and viewing insights with titles around "funnel conversions," they almost certainly care about improving funnel conversion rates. Lead with that.
Where to look: Customer engagement dashboard in PostHog — filter by the customer's org/team and check insight creation and viewing activity. Use PostHog AI or the PostHog MCP (with CS Skills like User Deep Dive) to pull additional details and summaries.
Walk through their site with debug mode
Visit the customer's website and inspect their PostHog implementation firsthand:
Open the browser console and run posthog.debug() to enable debug mode
Check the config to see how PostHog is configured
Walk through key flows (login, onboarding, core product actions)
Watch what events fire — are they capturing meaningful actions?
Look for issues: missing events, misconfigured properties, no identify calls, etc.
This gives you a firsthand view of what the customer is (or isn't) capturing. You can come to the conversation with specific, concrete observations — "I noticed you're not capturing any events after sign-up" — rather than asking them to self-report.
Framing matters: Position it as a proactive health check, not a criticism. Something like: "I took a look at your implementation and spotted a couple of things that might be worth addressing..."
Outreach tactics
Ordered roughly by how often the trigger comes up — the first few you can do for almost any account, the last few only when external events line up. Apply the meta-tactics below to whichever you pick.
SDK health — flag outdated SDKs
Use the SDK health check to see if the customer is running outdated SDKs. This is one of the easiest, most concrete reasons to reach out. We recommend customers update monthly so they don't miss bug fixes and improvements.
Suggested cadence: Run the SDK health check on each of your accounts quarterly, or whenever a customer is ramping up usage of a specific SDK.
Suggested wording:
BTW our SDK health check is warning that you are using a three year old version of our Python SDK — I promise we've improved it since then! Also your iOS and Android SDKs are really out of date. Any chance of updating these?
Why it works: Specific, helpful, and low-effort for both sides. The tone is light and friendly, not alarming.
Spot new product interest and reach out proactively
Watch customer activity for signs they're exploring a product they haven't adopted — docs page views, product-page activity, exploratory events. Use that as a natural conversation starter (credit to Tyler).
Suggested cadence: Weekly scan of doc-page views and product-page activity for your accounts.
Suggested wording:
Hey @[contact], saw you checking out AI observability and wanted to share a few things. It occurred to me that our LLM observability suite might be really helpful for your team.
Not only do you get evals/traces/generations to track model performance, token usage, etc, you can then also connect those things back to PostHog session/user data. Which means you can actually easily run A/B and multivariate tests on things like prompts, models, and so on, while ALSO seeing how the LLM performance/quality have an impact on conversion and funnel.
You may already have something like that in place but thought it was worth mentioning!
Steady drumbeat of usage-specific tips
For customers who rarely reply, keep sending value anyway. Session replays will tell you whether your advice is landing — quiet customers often act on tips without ever responding (credit to Anna-Marie, who used this pattern on a customer that hadn't replied in months; replays showed they were quietly acting on every tip and eventually adopted multiple new features).
Suggested cadence: Every 1-2 weeks. Rotate value types so it doesn't feel like a stream of asks.
Value types to rotate through:
Cost optimization — e.g. "you have a couple of flags tied to completed experiments still enabled"
Alerts or monitoring opportunities you spot in their data
Data quality observations — e.g. "your group analytics has many groups being created with a UUID as the group key"
Workflow templates based on insights or dashboards they've drafted but not saved
Heads-ups on upcoming products in their space — especially competitive ones — so they don't get blindsided
New beta features that tie back to what they're already doing
OOO heads-ups with a fallback contact
Suggested wording (transparency about a competing product launch):
Hey @[contact], :wave: just wanted to give you a heads-up and be super transparent: as you might already know our engineers have been working on [new product]. I've just heard that the ballpark timeline is ~end of [month] for going into beta. I know this might be a sore point given your space, and didn't want you to feel blindsided.
I'd love to address any questions or concerns you may have, and as always — make sure that you continue getting value from our product analytics, feature flags and experiments you've been running.
1:1 individualized outreach to revive a dead channel
When a customer channel goes completely silent, don't mass-ping — it gets ignored. Instead, DM team members individually over a couple of weeks until you've rebuilt the channel one person at a time, then get them on a call together. Seb used this on a dead channel and eventually got the whole team back on a call.
Suggested cadence: Spread individual DMs over 2-3 weeks. Convene the group on a call once you have a critical mass.
Bonus — same-day call follow-up with a custom touch: A custom-branded merch discount code (set up in the Shopify admin — see the merch store handbook page) is a small detail with outsized goodwill impact. Sending it same-day rides the momentum, well before the "proper follow-up."
Suggested wording (same-day follow-up):
hey team! thanks for the productive chat earlier today.
i owe you a proper follow up on everything we discussed, but couldn't wait to share this discount code ([CUSTOM-CODE]) with ya'll so you can get your save posthog t shirt on the (hog)house :hog-party-wave:
lovely meeting you all - excited to keep working together :hog-offers-heart:
cc @[people who showed interest on the call] - tagging you since you were esp excited about the merch :slightly_smiling_face:
After events (Stripe Sessions, conferences, meetups), sweep through post-event outbound — including customers who already have a CSM/TAM relationship that's gone cold (credit to Lorena). Event context resets the conversation: it's not "checking in," it's "I just saw you at X." A different sender or different framing can revive a stalled thread that relationship-based follow-ups couldn't.
Suggested cadence: After every event your customers attended, do a post-event outbound sweep — don't filter out accounts with existing relationships.
Why it works: Event-tied context lowers the social bar to engage. The customer doesn't have to explain the silence — they just have to reply to "great to see you at X."
Use a competitor pricing change (or market news) as a value-based reason
When something happens in the wider market that could cost the customer money — e.g. a competitor's pricing change — that's a real reason to reach out. Will used this when LaunchDarkly's pricing changes started getting bad press: tagged specific engineers and offered to do the heavy lifting on a PostHog vs LD comparison.
Suggested cadence: Opportunistic — keep an eye on competitor news so you're not the last to know.
Suggested wording:
Hey @engineer1 and @engineer2,
i know you're using [competitor] for feature flags — we heard at [event] that the pricing changes are causing bill shocks, so if you're doing any sort of internal review, lemme know and i'll do the heavy lifting of the comparison from our side.
p.s. please lemme know if i should tag anyone specific
Follow-up pattern that worked:
If they engage, drop a deep, honest technical breakdown. Don't oversell — call out gaps in our product where they exist.
If they push back on a gap, close the loop publicly: "Let's put a pin in it for now. I'll keep an eye on this from our side, and if we can support [X] cleanly sooner, I'll come back with something then!"
Loop in engineering in the customer channel when relevant — turns the conversation into a product input loop and shows the feedback is being taken seriously.
Cross-cutting patterns that apply to any outreach above, regardless of which trigger you use.
Lead with their data, not a generic ask
Every message should open with a specific observation pulled from their actual PostHog usage. Pair it with a direct link to the relevant view in their project (e.g. eu.posthog.com/project/.../...) so they can act in one click.
Tag specific people, not channels
Name individuals in your message ("Hey @[contact], saw that..."). Channel-only pings get ignored; named tags lower the social cost of replying. Invite a redirect when you're not sure who's right: "lemme know if i should tag anyone specific."
Mix value types, not all asks
Rotate through tips, cost optimization, transparency about upcoming products, OOO heads-ups, beta invites. If every message is an ask, you train them to ignore you. Build trust before the ask.
Low-pressure framing
Phrases that consistently work:
"thought it was worth mentioning"
"lmk if interesting"
"if it's a bad fit, I'll say that and leave it there"
"you may already have something like that in place"
Don't push when they push back. Close the loop publicly with a clean "let's put a pin in this" so the door stays open for next time.
Strike while energy is high
Same-day follow-ups after calls beat polished follow-ups sent a week later. Small unexpected perks (custom merch codes, personalized touches) sent in the momentum window punch above their weight.
Investigating further with MCP
Use MCP to find frustration signals for specific outreach
Our MCP can be a great tool for understanding silent user frustation. Below are some signals to look out for and find specific individuals worth reaching out to.
Lost insights:: You can ask our MCP how many insights were started versus how many were saved and by who. This can signal users may be having difficulty trying to create the right insights. For example, a customer may have started 130 insights in the past week but only saved 6.
Rage clicks: This can be great to understand if there are specific pages or insights the user is showing higher than usual frustration. Understanding what the page or insight is about, and coupling this with session replay can give you an idea as to what the user was trying to accomplish as a way to be helpful.
Product engagement: By default, AI will sometimes assume certain users are not engaged because it's measuring PostHog UI engagement. To get around this, ask about MCP engagement as well to better understand how active users are engaging with PostHog. Additionally, Vitally may sometimes report low dashboard activities or product usage but this can be a false positive as its measuring dashboard views and not specific insights. Checking actual user engagement will get you a more accurate view of who is active and who isn't, and specifically what products they're engaging in to reach out with specific questions or help.
Query failures: Vitally can help surface query failtures but MCP can get more specific on the failures customers are encountering so this could be an opportunity to reach out with a specific message to see if the customer may want assistance with getting a specific query working. Sometimes the MCP will highlight the specific query that is failing giving you something to directly investigate and fix before reaching out.
Client request failures: This is separate from query failures and can mean customers are having issues loading specific data and could be a great opportunity to resolve the issue for them or reach out to confirm and file a bug fix on their behalf.
Priority summary: After requesting AI to look at all the potential frustration signals, you can request a prioritization summary for users you should reach out to with specific summaries of issues that particular user is dealing with and a sample crafted outreach message. The MCP will then priortize these and give suggestions that you can tweak making it easier to reach out to users that you typically may not speak with.
Use MCP to understand events changes for outreach
Event changes: MCP is great at is surfacing event changes on a daily, weekly, or monthly basis, and any potential implementation changes or product drops that can be easily missed. Ask the MCP to do an analysis at the organization level (important as sometimes the MCP can default to user engagement rather than product events), and if there are changes in event volume, request who was actively using these products prior to the change before reaching out to learn about the changes. For example, AIO volume suddenly changed 7 days ago, ask if this could have been related to implementation changes.
Product adoption: A quick way to see product adoption changes is to ask MCP for this info. Rather than only look at event volume increasing or decreasing, MCP has been able to surface when customers were testing a new product, sample events, reduce product usage, etc. These are all perfect opportunities for reaching out to specific users who are working on these with specifics such as "I see you recently are tested our data warehouse briefly but have discontinued sending data. Was there anything specific you were looking to do with data warehouse that I could help with or answer questions around. Curious on how your team is thinking about using data warehouse and what goals you have in adopting PostHog's data warehouse as a solution."
_Note:_ It can be helpful to request MCP ignore weekend events when doing these analysis as weekend events often dips and can create false positive signals in your analysis.
When working with our customers, they will occasionally ask for features which aren't in the product yet. We won't build a niche feature for a single big customer, but if we can see a request being of benefit to multiple customers, we should capture, track and feed it back to our product teams.
Urgent vs Non-urgent requests
If a customer is at risk of churn, or otherwise unhappy about the missing feature, then we should communicate this to the relevant team in their Slack channel (usually #team-xyz). Adding in the urgency, ARR and tagging the team lead is a good approach here to get some focus. Remember that you still own the customer and may need to follow up with product teams to get the right level of focus as they don't have all of the customer context that you do. Don't create false urgency where there is none - we only want to use this approach when things are _actually_ urgent.
For non-urgent requests we should capture them in Customer analytics using the process on this page, and then share them with the teams in their Slack channels ahead of quarterly planning.
Tracking feature requests in Customer analytics
We track feature requests in PostHog itself, on the Feature requests tab of Customer analytics. This replaces the custom object we used to keep in Vitally, so don't add new requests there.
Creating a new request
If you've checked the list and can't see an existing request then you should create a new one. You can do this in two ways:
From the Feature requests tab, using the button to create a new request.
From an account, where you can also see the requests that account is already linked to.
The New feature request form has these fields:
Title - what the customer needs, in one line. This is the only required field, and it's customer-facing, so write it for a product team that has none of your context.
Description (optional) - the request in the customer's language. It takes Markdown. Add the workaround they're using today and why it isn't enough, if you know.
Account - search by account name or external key. A request starts with one account, and you add the others as they ask for the same thing.
Product areas - one or more. This is how a request gets routed to a team, so it replaces filtering by team in the old view. Pick more than one when an ask spans products, for example Session replay and Error tracking.
Evidence (optional) - the context for this account's ask. Fill it in, even though it's optional. A request with no evidence is much harder for a product team to act on.
There's no status or priority field on the form. New requests start as Requested, and you set the status and the priority on the request itself once a team picks it up.
Evidence
Evidence is the biggest change from how we worked in Vitally. Context attaches to each account instead of to one shared text field, so you can still tell who asked for what, and when.
Each evidence item has:
Summary - what this account needs, in your words. Keep it internal-facing.
Customer quote - the customer's own words. Paste them rather than paraphrasing, because a direct quote carries the most weight with a product team.
Source - where the request came from, for example a customer conversation or a support ticket.
Request date - when the customer asked. This is what tells a team whether an ask is fresh or has been sitting for two quarters.
Source URL - a link to the Slack thread, ticket, or call. Add the contact information of the person asking for it, if it's not a Slack thread.
Images - screenshots, when the ask is easier to show than to describe.
Adding a customer to an existing request
Search the list first. There are hundreds of open requests, and a duplicate splits the evidence for a single ask.
Open the request and add the account to it.
Add an evidence item for that account with the summary, quote, source, and date.
Statuses and duplicates
A request has a status of Requested, Planned, Completed, Won't fix, or Duplicate, and an optional priority of High, Medium, or Low.
If a request turns out to be a duplicate, set its status to Duplicate and move the evidence onto the request you're keeping, rather than deleting it. You can archive a request you no longer want in the list and restore it later, and both edits and status changes keep a history.
Using MCP and the API
Everything above is available through MCP, so you can ask PostHog AI to find, create, and update requests instead of using the UI. This is most useful for checking whether anyone else has asked for something before you file it, and for filing a request straight out of a Slack thread or a support conversation.
The same object is on the REST API at /api/projects/:project_id/feature_requests/, using the customer_analytics:read and customer_analytics:write scopes.
Signals coverage for feature requests is in progress. Until that lands, keep sharing requests with the teams in their Slack channels ahead of quarterly planning.
Prior to a customer discovery call, review session replays of the user to see how they interact with PostHog, and where improvements can be made. Check historic conversations in Vitally, or calls in BuildBetter, for wider context.
For fundamentals, use this checklist to check for common issues before a customer discovery call. PostHog only shows you some of this — for backend implementation details, you'll need to ask on the call.
Events and event properties
Check what events the customer is tracking, whether they have custom events, whether autocapture is on, and whether they're collecting event properties (custom or autocapture).
Two places to look:
Activity — recent events.
Data management — custom actions, event definitions, property definitions.
Look for custom actions. Customers without any actions often aren't using PostHog effectively. Common patterns: renaming events into something more meaningful (e.g. purchase_completed instead of clicked_purchase_button), or bundling events like user signups or purchases.
If a customer has autocapture enabled but no actions defined, that's worth raising with them on the call.
Reverse proxy configured
Check whether the customer has a reverse proxy set up:
If session replay is on: open a replay, go to Activity → Inspector → Doctor, search "config", expand api_host. If you see us.i.posthog.com or eu.i.posthog.com, no proxy. If you see one of their domains, they have one.
If session replay is off: add ?__posthog_debug=true to a URL where PostHog is loaded, open the console, type posthog.config, and check the api_host property.
If neither works (no session replay and the site isn't publicly accessible): ask on the discovery call.
Person properties, group properties, and cohorts
Check whether the customer is using person properties, whether they might be over-identifying, and whether they're using cohorts.
Worth a look:
What person properties are being added? Are there obvious ones missing for their business?
Are they using cohorts? What kind?
If group analytics is enabled: do their group types and properties make sense? Group types are limited to five, so they need to be set up intentionally.
Ecommerce events
For ecommerce customers, check whether they've implemented the ecommerce events specification — events like sku, product_id, category. Many customers don't know it exists.
SDK or library version
Check that the customer is on an up-to-date SDK:
In Activity, click Configure columns and add Library and Library Version.
Or look up the Library version audit table in Metabase.
Compare against the latest versions in our GitHub repos.
Sign up for an account
If the customer's product offers a free account, sign up and walk through the flow. You'll see which events fire, which don't, and what's likely missing.
Dashboards
Have they set up custom dashboards or insights for their own goals (sign-ups, retention, free-to-paid), or are they relying on defaults? On the discovery call, you can ask whether what they're tracking matches their priorities.
Data pipelines for event notifications
Check whether they're using data pipeline destinations (e.g. Slack notifications on specific events). Many customers don't realize this use case exists — it's an easy upsell.
When a customer is assigned to you, your job is to understand their business, learn how they use PostHog, and find ways to be useful — whether or not they choose to engage. This page walks through how to research, reach out, and run your first call.
Get introduced in the existing Slack/Teams channel or via email.
Coordinate with the previous owner for continuity.
Set your own CSM relationship rating on the account. Start at 2 — do not keep the rating the previous owner gave it.
Cold (no established contact)
Cast a wide net — org owner, org admin, recent ticket raisers, anyone active in the last month. Even if there seems to be a point of contact, things probably changed — multi-thread by reaching out to several people.
Your intro message
Cover:
A value nugget — grabs attention and shows you've already done your homework.
Who you are and that you're their new CSM.
What a CSM does — their dedicated PostHog human, go-to for help, questions, training, and strategic guidance. Many customers misunderstand CSMs as "just support" — distinguish yourself.
Value nugget ideas
Pull from Vitally and Metabase to find something specific to mention:
Event count spike or drop — make sure it's expected and tracking is correct.
Recent support ticket — follow up to confirm it's resolved.
High user count or low engagement — offer a training session.
Legacy pricing plan: "We moved off legacy plans over a year ago. I'd like to transition you to standard pricing — happy to walk through the changes."
New feature for their use case - Highlight a new PR or functionality for an app you know they use.
If you're inheriting an existing Slack channel, do the intro in Slack.
Subject lines
Find what feels natural to you — keep it in PostHog's voice. Examples:
"Hello 👋 from your new CSM at PostHog + hook"
"hi from PostHog"
"Checking in from PostHog"
In Vitally, an account's Active conversations tab is a good place to see how teammates have reached out in the past.
No response?
Follow up after 2-3 business days. Try engineering, product, or data folks. Emphasize that you're not selling — you want to understand their use case and help optimize their PostHog integration. Reach out to users directly, avoid large group messages.
Connecting with a champion
Once you've got someone responsive, aim to build a 1-1 relationship — ideally with someone in engineering, product, or data.
Acknowledge their time, make clear you're not pitching, and ask for a 15-minute call (async works too).
Pro tip: if they're not in Slack yet, don't ask — send them a direct invite. For accounts without a shared Slack channel, follow the shared Slack channels guide to set one up.
3. Your first call
A quick discovery call is one of the most effective ways to learn about a customer. It beats a month of back-and-forth in Slack.
Typically 15-30 minutes. Aim: rapport, pain points, and a sense of where you can help.
Goals to clarify
Use the call to figure out how deeply you'll work with this customer. Think through:
What do you want to achieve with this customer? Keep an eye on them, or go deeper as their partner?
Do they need help fixing their current setup?
Do they have plans to implement new PostHog products?
If they need help or are expanding their use, that's an opening to work with them more closely — collaborate on a detailed success plan. Some customers won't want to engage deeply, and that's fine — keep monitoring their usage and check in when appropriate.
Prep
Before the call:
Understand their PostHog usage. Which products are they using and how? What metrics do they care about? Which products are they not using that should make sense for them? E.g. if they use product analytics but not web analytics, understand why.
Show them feature previews. Recommend PostHog AI (relevant to most customers). Otherwise, recommend new products they likely already use (Messaging, CRM) — frame it as "you probably already have this — we're trying to launch it, would love your feedback."
Leave room for Q&A on the product.
Plan next steps and an ideal cadence.
Question bank
Don't interrogate the customer — pick a few that are relevant.
What's your role and team?
What does your company do?
What are your immediate and overall goals?
Can you describe your current analytics setup and any tools you use alongside PostHog?
Which user flows or features do you most want to understand better?
Any blind spots or gaps in understanding?
What problems have you had with analytics (ad blockers, data privacy, endpoint reliability)?
What does success look like after implementing a new analytics solution?
Are you more comfortable with direct SQL or do you prefer visual dashboards?
How do you make decisions about scaling, feature adoption, and pricing flexibility?
Who are the main users of PostHog on your side?
Any concerns about compatibility or integration with your current stack?
Anything weird happening in PostHog?
What metrics do you deeply care about?
Do you feel set up for success with your current PostHog setup?
Which teams currently use PostHog at your company?
Are there opportunities for other teams to adopt PostHog?
Could you introduce me to champions on other teams to learn about their use case?
Would training or workshops be useful for you and your team?
How do you feel about PostHog overall?
4. Ongoing
Prioritization
Prioritize potential churn risks, low engagement, and accounts where something is changing (for better or worse):
Upcoming renewals: accounts with renewals in the next 3-4 months.
Low engagement: customers who aren't using PostHog or engaging with us.
MRR variance: significant decline or growth in the last quarter.
Account research
A lot of valuable context lives in past conversations:
BuildBetter — recordings of customer success, sales, and onboarding calls. Use People to search companies or contacts and see call history, or use direct search / AI chat.
PostHog Support — filter tickets on your own ae_* or csm_*tag to see every ticket raised for the accounts you own. You can also open a person's profile in PostHog to see any support tickets they've raised. See who the key contacts have been, who's supported them in the past, and how frequently they raise tickets.
Product usage analysis
PostHog is the best place to see how customers actually use our product. We also pipe product events to Vitally via the CDP, so you can see active users, MAUs, and which paid products an account uses.
Metabase has more detail, including cross-sell and upsell signals.
News alerts
We use Watch Tower to track news about companies in your book of business.
To set up:
Create an account with your PostHog email.
Create a list and import your book from Vitally or Salesforce.
Check that company names and domains are correct — Vitally and Salesforce often have inaccurate domains, and Watch Tower uses the domain for context.
Set up notifications (email by default, Slack also available).
Watch Tower will scan the news daily and ping you when there's a match.
Find your own rhythm
There's no strict playbook. Use whichever sources work best for you.
As the dedicated PostHog human for your customers, you're the first stop for issues. You have the most context on them, so you're best placed to triage and escalate.
Support and engineering are always available to help, but try to solve issues yourself first. You'll level up your product knowledge faster.
Customers can create tickets from Slack by adding the 🎫 emoji reaction (or mentioning @SupportHog). This means they can get help even when you're asleep or on holiday. Let your customer know about this, and remind them now and then.
If you're working on a ticket the customer raised in Slack, assign yourself as the owner in PostHog Support, and then either resolve it or assign it to Team Support if you need to escalate it.
Tip: Customer messages from SupportHog channels also go to #support-managed-customers. Find the ticket there and follow the link to see the ticket in PostHog.
Ask for specifics: links to the insight, feature flag, or dashboard; a screenshot or the exact error message.
If it helps, log in as the customer. Clicking a link from their PostHog instance will sometimes offer a "log in as" option. Otherwise, go to US admin (EU admin), search for the org or user, and click "Log in as user". If you don't see that option, ask Dana Zou to add you as a staff member in admin.
Use our docs, troubleshooting tips, and search Slack, PostHog Support, and GitHub for similar issues. If you've just joined, spend 30 mins to an hour investigating yourself before asking for help — onboarding is when you learn the products best. Use common sense based on urgency.
Keep the customer in the loop while you investigate — progress, blockers, next steps.
Using the MCP server while impersonating
You can connect the PostHog MCP server while logged in as a customer. This is useful when you want to investigate their setup from Codex, Claude Code, Cursor, or another MCP client.
Log in as the customer using the steps above. Leave Read-only mode selected unless the customer has explicitly agreed to you making changes.
Add the PostHog MCP server to your client. For Codex, run:
claude plugin install posthog@claude-plugins-official
Disconnect any existing PostHog MCP session so the OAuth flow starts again:
For Codex, run codex mcp logout posthog.
For Claude Code, run /mcp, find the posthog plugin, and select Clear authentication.
Start a fresh OAuth flow while you're still logged in as the customer:
For Codex, run codex mcp login posthog.
For Claude Code, run /mcp, find the posthog plugin, and select Authenticate.
Only authorize the organization and project you need for the investigation.
Work within the scope of the ticket. If you need to make changes, get the customer's permission first, upgrade the impersonation session to read-write, then log out and log in to the MCP server again so it gets the right scopes.
Disconnect the MCP server, then log out of the impersonation session when you're done. OAuth tokens created while impersonating are short-lived and revoked when the impersonation session ends.
If you use Claude Code for repeat customer audits, the impersonation toolkit wraps this flow, copies safer permission rules into each customer folder, and disables the PostHog plugin when you exit.
If the organization has disabled PostHog AI data processing, the OAuth flow will return a 403 and the MCP connection won't be authorized while you're impersonating them. This is intentional. Ask the customer to authorize the MCP connection themselves instead. Their connection will work, but MCP tools that use PostHog AI internally will stay unavailable while PostHog AI data processing is disabled. Don't enable PostHog AI on their behalf.
Either way, attach a private note explaining what you're escalating and why, plus what you've already tried. Even confirming you followed the customer's repro steps and saw the same issue is valuable context.
Auditing impersonations
Customers sometimes ask who from PostHog has accessed their account. Use this SQL query on project 2 to get an impersonation log for a specific organization. Get the organization ID from Vitally.
-- Get all user emails for an organization from persons table
WITH org_users AS (
SELECT DISTINCT
properties.email as user_email,
properties.org__name as org_name
FROM persons
WHERE properties.organization_id = 'ORGANIZATION_ID'
AND properties.email IS NOT NULL
)
SELECT
e.timestamp,
ou.org_name,
e.properties.target_user_id as target_user_id,
e.properties.target_user_email as target_email,
e.event,
e.properties.staff_user_email as staff_email,
e.properties.mode as mode,
e.properties.reason as reason
FROM events e
JOIN org_users ou ON e.properties.target_user_email = ou.user_email
WHERE
e.event IN ('impersonation_started', 'impersonation_upgraded')
AND e.timestamp >= now() - INTERVAL 30 DAY
ORDER BY e.timestamp DESC
In a world where a lot of our high-paying customers have self-served without ever speaking with a PostHog human there is scope for them to implement PostHog in a less than optimal way. This could result in people spending more than they need to, or having inaccurate reporting data available to them. Ultimately if left unchecked these things will lead to avoidable churn.
When a health check turns up something that lowers a customer's bill, tag the account cost optimizing in PostHog Customer Analytics and share it with the team. Cost optimization covers how we handle these.
Are they paying for things they don't need?
Group analytics
Group Analytics can be a real value-add for B2B companies, allowing them to track analytics at the company or workspace level rather than an individual person. They do however need to implement group tracking in their PostHog SDK. Customers who haven't done this may end up paying for Group Analytics but not able to use it.
We have a Vitally risk indicator added to customers who are paying for Group Analytics but not using it.
To help the customer you should figure out whether they are B2B or could otherwise benefit from sending group information. If so, reach out with guidance. If not, reach out telling them that they can save by removing the Group Analytics add-on from the billing page.
Autocapture
Autocapture is a great way for users to get up and running with event capture without a huge engineering effort. Autocapture can however get very noisy very quickly, and if users aren't leveraging these events they may not be getting value out of them. You can understand a customer's Autocapture event volume from their Metabase customer usage dashboard (instructions above on how to get there). There is a breakdown of the Key event volume Last 30 days which shows the number and % of Autocapture events they are sending across all projects. If that is high (>50%) then check the Actions (by type) visualization on the same dashboard to see if they have any Autocapture actions defined. If not they are likely to not be benefitting from Autocapture events.
If they aren't benefitting from Autocapture you should reach out to let them know how best to use it. Alternatively, they can tune or turn it off by following the Autocapture configuration docs.
Legacy Teams package
Customers on the legacy "Teams" package ($450/month) can save $200 by switching to the Boost package ($250/month) if they don't need SAML SSO. The Teams package has been split into:
When Session replay is enabled it will capture all sessions by default. As every session is counted for billing purposes, customers may end up with a bunch of low value short recordings and still be paying for them.
If a customer has Session replay enabled, log in as them and look at their session replay settings. At a minimum we recommend setting the minimum duration to 2 seconds or more but there are other tuning options which they may also benefit from.
Are they running up-to-date SDKs?
Outdated SDKs miss out on bug fixes, performance improvements, and new features. A customer using a three-year-old SDK will hit issues we've already solved, which can silently erode trust over time.
Check SDK versions using the SDK health check or in Metabase via the Library version audit table. At minimum, the SDK sending the bulk of their event volume shouldn't be more than 3 months behind the latest. Monthly updates are the best-practice habit to encourage. Some SDKs have breaking changes between versions, and if so, make sure you make the customer aware about the breaking change.
A light nudge on this also doubles as a natural re-engagement touchpoint for customers you haven't spoken to in a while.
Have they implemented tracking incorrectly?
Calling identify too often
A common pattern is for users to call posthog.identify() on every page, or in an endless loop. Whilst this won't break their tracking (unless they use different distinct IDs in the identify call) they will end up with a drastically inflated event volume. You can diagnose this by looking at their Metabase usage dashboard in the Key event volume visualization. If either the volume of $identify or $set events is higher then 5% then something has likely gone wrong in the implementation.
You should get in touch and let them know that they only need to call posthog.identify()once per session.
Calling groupidentify too often
As with identify() above users may also end up calling posthog.group() more than they should. In the Key event volume visualization in Metabase if the $groupidentify count is higher than 5% they've likely set it to call once per page.
You should get in touch and let them know that they only need to call posthog.group()once per group per session, or when the group changes.
To see where duplicate groupidentify calls are being generated, you can use the following SQL:
SELECT properties.$lib AS lib, count() AS groupidentify_event_count
FROM events
WHERE event = '$groupidentify'
AND $session_id IN (
SELECT $session_id
FROM events
WHERE event = '$groupidentify'
GROUP BY $session_id
HAVING count() > 1
)
AND timestamp >= now() - INTERVAL 30 DAY
AND timestamp < now()
GROUP BY lib
ORDER BY groupidentify_event_count DESC
Calling posthog.reset() before identifying the user
Posthog.reset() will generate a new anonymous distinct ID. If this is called before a user is identified then two anonymous unlinked user may be created. There is no easy way to proactively diagnose this however if a customer says that their tracking between web and app is off, this is a common culprit.
It is best practice for a customer to use PostHog's Managed Reverse Proxy or to configure their own for events to be sent from their own domain.
When using either PostHog's managed reverse proxy or deploying a non-managed reverse proxy, events should populate the "Library custom API host" property. Host mapping and domains can potentially be seen in Metabase. You should verify the setup with a customer.
Cookieless tracking
If a customer mentions their user/event count seems to be missing a lot of data from their website, ask them if they have implemented cookie opt-in and to share the part of their code where PostHog is initialized. Some customers may not be aware that we have specific recommendations for how to initiatlize PostHog for cookieless tracking.
For example, if they implement PostHog on their website similar to as follows:
They will not be capturing anything for customers who visit their website and opt-out of cookies or ignore the cookie banner completely. We recommend instead they use the cookieless_mode parameter in their initializer as outlined in the cookieless tracking tutorial. If the customer wants to move forward with implementing cookieless mode, ensure they enable "Cookieless server hash mode" in their project settings under Project Settings > Web analytics.
Cookieless mode can help them have more accurate tracking totals because when using cookieless tracking, the PostHog SDK will generate a privacy-preserving hash, calculated on our servers.
Are feature flags resilient?
Falling back to working code
It is important that hitting the flags endpoint does not block an application from otherwise functioning correctly. If the flag fails to load or returns an unexpected value for any reason, such as None, (empty string), or false you should always fall back to working code.
Server side local evaluation
Implementing Server-side local evaluation will ensure that flags continue to return values regardless of the network status of the flags endpoint. By default, PostHog will attempt to evaluate the flag locally using definitions it loads on initialization and at the poll interval. If this fails, PostHog then makes a server request to fetch the flag value.
As a note, server side local evaluation is billed differently than other flag requests.
Do they have a custom implementation that's causing issues?
Some customers build layers in between their app and PostHog, oftentimes as a precautionary measure or to accommodate a highly specific use case. While these custom configurations are mostly innocuous, sometimes they outlive the problem they were solving or create net new reliability issues. From the customer's POV, it can be difficult to discern the root cause of those issues, and it's on us to create clarity for them (even if those issues are self-inflicted). The last thing we want is for them to doubt PostHog's reliability when their custom implementation is the culprit.
In this process of creating clarity for them, we should never cast blame or get defensive. Our goal is to diagnose the root cause of recently reported issues with a clear intention to help them understand what went wrong and how they can fix it. The evidence of self-inflicted issues is enough to push them towards a fix. More importantly, however, our respectful presentation of that evidence shows a good faith effort to help without the need to be right.
Creating a reliability audit
Things you'll need:
Written history of past issues (tickets, Slack threads)
Up to date documentation from the customer explaining their custom integrations
Clarity on when those custom implementations were deployed to production
Exa MCP (for reading through PostHog docs)
Slack MCP (for reading through past threads)
PostHog MCP
Local clone of PostHog's product repo on your machine
These will serve as context layers for your coding agent to help research and collate our own product's behavior and map it against their custom implementation.
To get started, just ask your coding agent:
/reliability-audit for {Customer} - here's their org ID: [xxx], Slack channel: [xxx], custom implementation documentation: [paste the full doc or link to it].
The /reliability-audit skill is available here.
One helpful way to frame your audit is to organize it into these dimensions: issue, date, root cause, verdict, resolution, link to the original Slack thread / ticket. The idea of "verdict" is to give yourself a clear space to articulate whether the issue was due to their custom implementation or PostHog.
While the format of what you deliver to the customer is entirely up to you, a Slack Canvas with a clear table and some descriptions can go a long way. Here's an example.
Your audit should push your customer to take action, so it may be helpful to include a clear articulation of what to keep versus change about their custom implementation. Make it easy for them to decide which parts of your audit they want to act on.
Why it's worth doing this
Aside from restoring their confidence in PostHog's data integrity and reliability, it's radically hospitable. Even if the customer has expressed misplaced frustration at PostHog, you're still demonstrating a good faith effort to help them win by doing this audit. At the minimum, it unlocks goodwill and deepens their trust in you as their advocate at PostHog.
We use Vitally as a customer success platform. You can log in via Google SSO to view customer data but will need Mine or Simon to grant you admin access to let you manage your accounts. It integrates with our other systems such as PostHog, PostHog Support, and Salesforce to give you a complete view of what's going on with your customers.
Health scoring
This section covers the computed score. For the rating you set by hand on your own accounts, see CSM relationship.
Overview
Health scores are a great way to assess whether your customer is at risk of churn or in a good state and are a common pattern in Customer Success tracking. We compute an overall health score out of 10 based on the following factors and weighting. You can read more about how Vitally health scores work in their docs here.
Health score metrics are divided into two categories: Customer Engagement (25%) and Product Engagement (75%).
| Score Name | Measuring | Weighting | |---------------------------|--------------------------------------------------|--------------| | User engagement | Are they using PostHog regularly? | 15% | | Product experience | Are there negative experiences with the product? | 5% | | Company engagement | Are they engaging with PostHog humans? | 5% |
| Score Name | Measuring | Weighting | |-----------------------------|--------------------------------------------------------------------------------------|--------------| | Product Analytics | Event volume and users analyzing insights | 33% | | Session replay | Replay volume and users analyzing replays | 20% | | Feature flags & Experiments | Flag requests, users creating feature flags, users creating or viewing experiments | 17% | | Surveys & Data warehouse | Users creating and viewing surveys, volume of rows synced | 5% |
Customer engagement
Non-product metrics, looking holistically at: Are customers using PostHog? Do they have friction when using PostHog? Are they engaging with PostHog humans?
User engagement
This tracks whether users are logging in to PostHog. It can tell us if customers are getting value from PostHog (regardless of the products they're using). Customers that have a low active user percentage, or only have 1-3 users engaging with PostHog are at risk of churn.
| Measure | Poor | Concerning | Healthy | |-----------------------------------------------|---------|------------|---------| | Last seen in product | >5 days | 1-5 days | ≤ 1 day | | Active user percentage | <20% | 20-40% | ≥40% | | Percentage decrease in active user percentage | >20% | 5-20% | ≤5% | | Users engaging with features | <3 | 3-10 | ≥10 |
Product experience
This looks at the experience of using PostHog.
Creating a lot of tickets can mean users are not satisfied with PostHog, haven’t implemented PostHog correctly or aren’t using the product correctly (opportunity to offer training)! Similarly, visiting docs can mean users are trying to do something and could need help.
We also look at query failure rate. Failed queries are common (users can cancel a query, there can be SQL syntax errors, etc.), however, a high failure rate means users aren't getting the data they need from PostHog. You should help investigate and provide recommendations.
| Measure | Poor | Concerning | Healthy | |-----------------------------------------------|------|------------|---------| | Tickets created in last 30 days | >10 | 5-10 | ≤5 | | Urgent tickets that remain unresolved | >2 | 0-2 | 0 | | Docs visited in last 7 days | >100 | 20-100 | ≤20 | | Query failure rate in last 7 days | >13% | 5-13% | ≤5% |
Company engagement
This looks at a customer's engagement with PostHog as a company. Most of PostHog's customers are happily self served so this is weighted very little in the overall healthscore.
| Measure | Poor | Concerning | Healthy | |-----------------------------|----------|------------|----------| | Most recent meeting | >90 days | 30-90 days | ≤30 days | | Most recent ticket | >90 days | 30-90 days | ≤30 days | | Total product count | <3 | 3-6 | >6 |
Product engagement
Across PostHog's products, we look at 2 factors – data volume & user engagement.
Data volume
This tracks _percentage decrease_ in data volume over the last 30 days. We use success metrics to track billable usage over the last 30 days and compare it with the previous 30 days on a rolling basis. The percentages you see in the tables below are the _decrease_ between the previous and current period.
User engagement
Data volume is a lagging indicator, by the time it drops, customers may have already decided to churn. We combine data volume with product-specific user engagement, measuring the percentage of _active users_ interacting with product features over the last 14 days.
There are products we don't include in the health score. Vitally has a limit of max 20 health metrics so we are excluding other products for now as the overall ARR from them are still very low compared to the others.
| Measure | Poor | Concerning | Healthy | |----------------------------------------------------|------|------------|---------| | Decide requests last 30 days (percentage decrease) | >20% | 5-20% | <= 5% | | Active users creating feature flags last 30 days* | <5% | 5-20% | ≥20% | | Active users using experiments** | <5% | 5-20% | ≥20% |
Feature flag usage includes: creating or updating feature flags. We look at this over 30 days instead of the usual 14 as feature flags provide value over a longer time frame.
Experiments usage includes: creating experiments, viewing experiments, and launching experiments.
Health scores are useful for tracking the long-term trends in an account, but occasionally there are more immediate point-in-time events that we should react to. These are tracked as indicators in Vitally and fall into one of two categories
Risk indicators - show up red against the account name and indicate potential churn
Opportunity indicators - show up green against the account name and indicate a potential opportunity for growth
Risk indicators
These are automatically applied via Vitally playbooks (see the Risk category here):
Forecasted MRR decrease
Applied if the Forecasted MRR Change is less than -10%, indicating a drop in MRR. We should look into the account to understand whether it is just a reduction in usage, or they are trending towards churn.
Increased billing page visits
Applied if there have been more than 1 visits to the billing page in the previous 7 days. Can be a good indicator that the customer needs help understanding or reducing their bill.
Query failure rate > 10%
Applied if the Query failure rate over the last 7 days (Success metric) is greater than 10%. Use Vitally to see which user was impacted and see if you can help optimize their queries or flag to our team for investigation.
Sudden decrease in event volume
Applied if the Event count last 7 days (Success metric) decreases more than 20% versus the previous 7 days. Indicates that they may have turned event tracking off.
No insights analyzed past week
Applied if insight analyzed was last seen greater than 7 days ago. Indicates that they may have stopped using PostHog to track analytics data.
Payment failed
Applied if there is a failed payment on their Stripe account. We should reach out to get this resolved ASAP.
Startup credit will run out this billing cycle
Applied if they are currently in the Startup plan segment but also have Forecasted MRR, meaning that they are on track to make a payment this month.
Organization owner recently removed
Applied if the Owner role has been removed from a user in the last 14 days. May be a sign that you've lost a champion.
Opportunity indicators
These are automatically applied via Vitally playbooks (see the Opportunity category here):
Forecasted MRR growth
Applied if the Forecasted MRR Change is more than 10%, indicating an increase in MRR. We should look into the account to understand whether it is likely to be deliberate or an accidental spike.
Organization owner recently added
Applied if the Owner role has been added to a user in the last 14 days. This is a good opportunity to reach out to a potential champion if you've not met them before.
CSM relationship
The health score above is computed for you. CSM relationship is a rating you set by hand on your own accounts, in Customer analytics.
It records the relationship you personally have with the account. It does not measure how the account is doing from a usage/spend/metrics standpoint. A large, healthy, fully self-serve account can sit at the bottom of the scale, and that is a correct reading in a product-led book, "assigned to you" and "known to you" are different things.
| Rating | What it means | |--------|---------------| | 1 - No relationship | The account is yours on paper only. It is fully self-serve, and you have no two-way contact with anyone there. | | 2 - Introduced | Warmly introduced from another team member but no direct trust yet OR limited response to engagement attempts but no real relationship built | | 3 - Reactive | They contact you when they need something, and there is no contact between times. | | 4 - Working relationship | You have regular two-way contact with a named person who replies to you and takes meetings. | | 5 - Trusted advisor | You are multi-threaded in the account. They bring you problems early and include you in their plans. |
To set the rating, add the CSM relationship column to your account view, then click the cell.
How to use it
Only the CSM on the account sets the rating. Do not rate an account for somebody else.
Change it when the relationship changes. There is no review schedule.
On handover, rate your own relationship. Start again at 2 instead of keeping the rating the previous CSM gave. If you keep their rating, the field tells you about the history of the book and not about the relationship the account has today.
Be honest. A book of all fives is less useful than an accurate one, and a one is not a failure — it tells us which accounts might need more focus from the CSM team and beyond.
Each label starts with a digit, so the scale sorts in the accounts table and totals in HogQL and PostHog AI. Use toInt32OrNull(substring(value, 1, 1)) to get the number.
Customer Success at PostHog means managing \~30 accounts per CSM while maintaining deep, meaningful relationships with each customer. Automation and AI tools can help surface important signals and streamline repetitive tasks, allowing CSMs to focus on strategic guidance and relationship building.
Automation should never be used as a replacement for human connection and interaction, but mainly as a tool to help a CSM be better prepared, informed, and effective.
Current automation stack
PostHog CS leverages several integrated tools to monitor account health and identify opportunities:
Core monitoring systems:
Vitally: Tracks usage patterns, billing changes, health scores, and engagement metrics.
Opportunities and Risks are surfaced via "Indicators"
Health scores update regularly as a composite of multiple metrics with different weights
Data is synced in from Salesforce, PostHog, BuildBetter, and Stripe
PostHog pipelines: Alerts for usage milestones, new product adoption, and behavioral changes. These are sent to Vitally, Salesforce, or Slack via PostHog CDP for alerts and data updates.
BuildBetter: Analyzes customer calls for feature requests, pain points, and sentiment.
Notes from calls are automatically synced to Salesforce and Vitally
feature requests and painpoints are automatically added to Vitally and sent to \#feature-request-feed channel
On larger accounts, a TAM and a CSM share ownership. Both need visibility of every customer call, not just the ones they attended. For each shared customer, we keep a dedicated internal Slack channel named customer-name-internal. This sits alongside the customer-facing Slack Connect channel, but stays internal only. To surface calls there, set up a Gong Stream:
In Gong, open Your Library and find Streams (ask Simon for access)
Configure a stream for the account
Point it at that account's customer-name-internal channel
Once live, the stream posts each call to the channel after it ends. Everyone working the account is notified once the call is done, with the transcript and summary to hand.
Key automated workflows
Account monitoring triggers include:
MRR changes exceeding certain thresholds generate investigation tasks
inactivity periods to flag engagement reviews
New product usage (any amount) creates cross-sell opportunity indicator
Payment failures and low credit balances to send Slack alerts to assigned CSM
Health score changes trigger Vitally indicators
Annual renewal dates trigger preparation workflows in advance and a ping in Slack
Human-first automation philosophy
Every automated workflow includes deliberate human decision points. For example, when an account begins using session replay, Vitally creates an indicator suggesting outreach about their use case \- but the CSM determines whether and how to engage based on the account relationship and context.
This approach ensures automation enhances rather than replaces the human elements of customer success.
Working effectively with automations
Best practices:
Review automated tasks such as Vitally indicators, Slack alerts, and customer health scores at least twice weekly.
Treat automated insights as starting points for investigation, not final answers\!
Set-up individual alerts in Vitally or PostHog CDP that match your own portfolio and experiences
As an example, setting up your accounts as a Cohort in PostHog and then setting up CDP alerts/notifications to Slack based on product usage and activity.
What remains purely human:
Initial customer responses and relationship building
Renewal negotiations and strategic planning
Technical implementation guidance
Complex problem-solving and consultative conversations
Requesting new automations
CSMs are encouraged (as are all PostHog employees) to experiment and surface new ideas frequently in Slack or team stand-up. Examples of areas where automations could be useful include, but are not limited to:
This page covers more of the operational detail of how our team generally works - for a broader overview of roles and responsibilities, visit the customer success team page.
Main metrics for each role
Technical CSM: revenue retention
Book of business
Customer Success Managers
Each CSM is assigned customer accounts accumulating to ~$2.5m ARR to work with. We use the CSM Managed Segment in Vitally to track this against goals. Don't assign yourself as the CSM on an account - assigning a CSM automatically adds the account to the segment. Allocation is up to Dana, Phil and Simon.
Weekly Customer Success standup
In addition to the weekly sprint planning meeting on a Monday, we do an account review standup on Wednesday to discuss any at-risk accounts.
The objective of the meeting is to hold each other to account, provide direct feedback, and also support each other. It is a great place to ask for help from the team with thorny problems - you should not let your teammates fail.
How contractual bonus works - Technical CSMs
CSMs are responsible for ensuring that a larger book of existing customers - both annual and monthly - continue to use PostHog successfully. They nurture customers and are product experts - this isn't a role of just going back and forth between customers and support engineers, or collecting feedback.
This plan will _also_ almost certainly change as we scale up the size and complexity of our success machine! As above, we will always ensure folks are treated fairly when we make changes.
Variables
Your OTE comprises an 80/20 split between base and contractual bonus.
Bonus is paid based on revenue retention above 100%, and is _uncapped_.
For example, if you have 100% revenue retention and your target is 120% revenue retention, you get 0% of bonus. For 120% retention, it's 100% bonus, and for 140% retention, it's 200% bonus. This is on a sliding scale so if you hit 110% retention you get 50% bonus.
The Q3 2026 target is 110% quarterly NRR. This may change in future depending on how things go.
To calculate retention we use the total usage over the past quarter and annualize this, then compare it to the quarter before that.
For monthly customers this is the total of their 3 invoices multiplied by 4
For annual customers, we look at the usage-based MRR and multiply by 4
An account starts counting toward NRR once it has 3 paid invoices in the previous quarter (a $0 month doesn't count).
Bonuses are paid out quarterly, and in any case after an invoice is paid
Bonus payments are made at the end of January, April, July, and October - at the end of each quarter, we'll monitor how many invoices actually get paid in the first two weeks of the next quarter. Fraser will send you an email that breaks down how you did.
Your bonus is guaranteed at 100% for your first 3 months at PostHog - this gives you time to get up to speed, but also if you over-perform then you will get your additional bonus.
If an account is added to your book:
If you inherit a new account that hasn't been managed by a PostHog human before, you have a 3 month grace period - if they drop or churn in that initial period, they won't be counted against you. We want to encourage you to right-size customers, rather than your deliberately letting them wastefully spend money due to some poor implementation.
If you inherit an account from another CSM, AE, or AM, it will normally count toward your NRR in that quarter, even in the first 3 months.
In exceptional circumstances we may need you to take on an account which we know isn't in a good state (ie. despite the previous owners best efforts we haven't been able to work with them). We will note in writing on a case by case basis that any churn or downgrade in the first 3 months won't be counted against you.
How bonus is calculated:
In general, we compare annualized ARR over the past quarter with annualized ARR from the previous quarter.
For Q3 2026 bonus: Q3 ARR vs Q2 ARR
For customers on annual plans, we will look at their usage-based spending (instead of total contract amount / 12)
If an account is removed from your book mid-quarter (we do this extremely rarely), it will not be included in bonus calculation.
If a customer churns during the quarter, their current ARR counts as $0 and they will be removed from your book the next quarter.
If a customer drops below the $20k threshold with no likelihood of growing, we don't adjust their ARR - it counts as-is, and they will be removed from your book the next quarter.
If we have to give a customer a big refund, we'll deal with your bonus on a case by case basis depending on what happened, but usually this will still be counted.
If we give a customer additional credits (goodwill, bug/incident compensation - not the credits they pre-purchase with a contract), the NRR treatment depends on why we gave them:
Unintended usage spikes - a misconfiguration, SDK bug, or runaway loop inflates usage: we credit the customer and exclude the excess usage from NRR. Nobody's NRR should go up because of an accident. There are eligibility criteria for credits - check them before promising one.
Goodwill credits - a bug hurt a paying customer's experience but their usage was real: the credit compensates them, and the usage counts as normal.
Startup / YC credits - usage covered by these doesn't count toward NRR. If a customer isn't paying us real money, we don't count it. In practice the 3-paid-invoices rule above handles this.
Comped usage on contract buy-outs / early renewals (e.g. comping 2 months of usage to move a customer onto a new contract early) - no blanket rule here, so flag it to your team lead and we'll handle it case by case.
Account allocation
CSMs manage approximately $2.5M in ARR. Books are balanced by shape as well as total: a target number of accounts per ARR bucket, so a single large account doesn't dominate a book.
As of Q3 2026, a typical book is roughly 4 accounts at $20-30k, 12 at $30-60k, 5 at $60-100k, 5 at $100-250k, and 2 at $250k+. These numbers come from our live capacity calculation, and will shift as coverage grows and capacity modelling improves.
When rebalancing accounts (e.g., if accounts drop below the $20k threshold), we'll bring you up to the current quarter's target amount.
Working with engineering teams
We hire Technical CSMs. This means you are responsible for dealing with the vast majority of product queries from your customers. However, we still work closely with engineering teams!
Product requests from large customers
Sometimes an existing or potential customer may ask us to fix an issue or build new features. These can vary hugely in size and complexity. A few things to bear in mind:
Engineers at PostHog talk to customers. It's much better to bring engineers onto calls to speak to large customer to talk to them directly than just do the call yourself and copy and paste notes back and forth. This is especially useful if a) the team was already considering building the feature at some point, b) it's an interesting new use case, or c) the customer is really unhappy for valid reasons and could churn.
Provide as much internal context as you can. If a customer sends a one-liner in Slack, don't just copy and paste into a product team's channel - find out as much as you reasonably can first, ask clarifying questions up front etc. Otherwise the relevant team will just ask you to do this anyway.
We already have principles for how we build for big customers - if you have a big customer with a niche use case that isn't applicable to anyone else, you should assume we won't build for them (don't be mad!)
For any feature requests customers care deeply about, we should file and track those in Vitally.
Inviting a product engineer into a customer conversation
Separately from product requests, there are moments where it's worth seeing whether a product engineer wants to join a customer conversation - as much for what _they_ get out of it as the customer. Always pitch this as an open invitation ("this might be an interesting call, would anyone like to join?"), never as "we need an engineer on this call." Situations where it's usually worth asking:
A customer is moving to or from another tool. If someone's weighing PostHog feature flags against LaunchDarkly, or shifting their error tracking to Sentry - in either direction - the relevant product engineer often wants in. It's a first-hand look at why a customer picks one platform over another and the trade-offs they weigh, which is useful to us whichever way they're moving.
The customer's on early-access or giving feedback. For anything in alpha, beta, or just shipped - or a not-yet-GA product they're already using and forming opinions on - engineers get a lot from hearing live first impressions, and the customer gets direct access to the people building it. A customer actively feeding back on pre-release features is exactly the kind of call worth pulling the team into.
You're meeting the customer in person. An on-site visit is a great chance to bring along a product engineer who's local, if there's one whose area matches what the customer uses (e.g. someone from the experiments team for a heavy experiments customer). This doesn't need to fit the two cases above - a good match nearby is reason enough. Have an agenda, and keep it to topics relevant to whoever's joining.
Why not just always invite one?
CSMs here are technical enough to solve real problems without asking our engineers. You're the expert! Bringing an engineer in is the exception, earned by genuine two-way value (one of the cases above), not a default or a comfort blanket. If you can't say what the engineer would get out of it, that's your answer.
Finally, if you are bringing engineers onto a call, brief them first - what is the call about, who will be there. And then afterwards, summarize what you talked about. This goes a long way to ensuring sales <\> engineering happiness.
Complicated technical questions
You will run into questions that you don't know the answer to from time to time - this is ok! Some principles here:
Try to solve your own problems. Deep dive the docs, ask PostHog AI, ask the rest of the sales team first - a bit of digging is a valuable opportunity for you to learn.
Similar to the above, don't just copy and paste questions from Slack with no context. Add some commentary - 'they have asked X, their use case is generally Y, I think the answer might be Z - is that right?'. Do some of the lifting here, rather than putting all the mental load on an engineering team.
Working with customers in Slack
Most of our customers use Slack, and it's a great way for us to be responsive to them. Everyone has the permission in Slack to create a Connect channel with a customer, and you should do this as early as possible in your relationship with them.
When you've created the channel you should also add SupportHog, our own tool that syncs Slack conversations with PostHog so that our Support and Engineering teams can work on customer issues in a familiar context. Follow the shared Slack channel setup steps to invite SupportHog and configure the channel.
Once it's in the channel, you can add the :ticket: emoji to a Slack thread — or mention @SupportHog — to create a new ticket in PostHog Support. Customers can also do this.
It's your job to ensure your customer issues are resolved, make sure you follow up with Support and Engineering if you feel like the issue isn't getting the right level of attention.
Extended Time Off
During extended periods away from work (generally more than two weeks) it's important that we maintain customer relationships - we don't want to leave emails or Slack messages unanswered. For planned time off, it's recommended that you make a list of your accounts, then add an appropriate colleague to the Slack channel. Try and balance the workload, but our policy of working transparently (eg. ensuring conversations on Slack don't happen in DMs) makes it easier for others to dip in seamlessly.
The expectation is that this temporary CSM will ensure your customers aren't completely ignored. This may mean answering questions themselves or opening support tickets on a customer's behalf, but not attend routine meetings (eg. monthly check-ins) or pro-active work. For standing meetings in your absence customers should be notified that the meeting is cancelled but any questions can be asked through normal channels.
For longer periods away, Dana may look to reassign some or all of your accounts.
Tools we use
Gmail We use Gmail for our email and the team uses many different clients from Superhuman to Spark to the default Gmail web interface. Find something that works well for you. To get your own email signature, copy the signature from someone else on the team (like Simon) and then fill in your own details.
Calendly: We use Calendly for scheduling meetings. In order to schedule a meeting between a customer and multiple members on the PostHog team, click on "Event types" in the left hand navigation, then click "+ New Event Type" button in the top right, and select "Group" from the dropdown. This will allow you to create a group meeting and add multiple team members to the event and create a link you can share with the customer.
Zoom: We use Zoom for all customer and sales calls. If you have Calendly properly integrated, calls that are booked through the tool will default to Zoom. You can find backgrounds to use for the calls here: This is fine \(and other awesome PostHog wallpapers\).
Gong: We use Gong to record calls. Once it's set up, Gong automatically joins your Zoom calls and saves the recording to a shared library the whole team can search and review. See sales & CS tools for how to connect Gong to your Zoom calls. BuildBetter is still where we store historical demos and meetings, and some teams continue to use it.
Granola: We use Granola for transcripts and AI notes. It runs on your laptop and transcribes whatever call you're in, so you get a transcript without adding another bot to the meeting.
When you start as a Technical CSM, you're assigned a book of business with ~30 accounts. Customer engagement falls into three stages.
The stages line up with CSM relationship, the rating you give your own relationship with an account. Stage 1 covers ratings 1 to 3, stage 2 is rating 4, and stage 3 is rating 5.
Once you've worked through your book of business, focus on building trust with your champions.
Show, don't tell. When a customer has a question or goal, build the solution rather than linking to docs. Create the insight or dashboard, then share what you did so they can do it themselves next time. Don't create dependency — they should be able to do it without you.
Be timely on alerts. Our automated alerts flag event spikes, drops, and other unusual behavior. Reach out quickly so the customer can investigate. If a customer's company raises funding or gets press, send congrats.
Push beyond the basics. Look at what they're not using yet. Have they set up tracking funnels for key metrics? Created alerts on important actions? Tried PostHog AI? Implemented error tracking to explain conversion drops? Cross-sell here, but frame it as helping them get more value.
Regularly invite new users to the Slack channel. The more people on the customer side who know you exist, the more come to you when they hit issues. Monthly is a good cadence — Vitally shows you who's new.
Offer recurring calls with your champion so you have a touchpoint and can stay close to what's happening.
Stage 3: Getting deeply embedded
At this stage, dig into the customer's goals and help them build on top of their existing PostHog setup.
Two examples:
Custom recommendation engine. An ecommerce customer used PostHog to track key metrics, then wanted us as the source of truth for personalizing returning visitors' feeds based on past views, searches, and purchases. That meant custom event tracking, pushing data to their backend, and more.
Real-time alerts. Customers have wanted notifications when a visitor abandons a purchase, when a download fails, or when high-value actions happen. Each needed custom implementation work.
If your champion can push these changes through, great. If not, ask for an intro to the decision maker — or reach out directly to the head of engineering or product with their quarterly goals and offer to help. Either way, showing you understand their goal helps them justify prioritizing the work internally.
This exercise can help you learn more about your customer’s usage of PostHog while helping you ramp up on your own PostHog skills!
Tactical questions
To get started you’ll need all the organization IDs for your accounts. You can get those via SQL query: SELECT DISTINCT posthog_org_id_c, NULL as empty_column FROM salesforce.account WHERE owner_id = 'your_salesforce_id' You can find your salesforce ID by going to your profile and copy the text in the website URL after “/User/” then export the results via CSV. (The empty column is there so we have commas as delimiter for the org ids, this allows you to directly copy and paste all the org ids into a filter input text field.)
Cohorts
Who are all the users in your accounts?
Who are all the admins / owners in your accounts? (Hint: check the current_organization_membership_level property)
Who are the new users in your account this week?
Who are the power users in your account? (Power users can be across multiple products, or you can split it by product. Define a power user as you see fit!)
Activation
For the new users on your accounts, how many came back to analyze an insight, watch a recording, create a feature flag, etc. within their first week?
What are the monthly activation rates across all your accounts for product analytics? (Hint: read this activation metric post and these insights)
Retention / Usage
Which of your new users have retained their usage after their first 3 months?
Which of your organizations have viewed /docs/ pages more than once in the past week? How many /docs/ pages views have there been across accounts for the past week?
Churn
Have any of your accounts churned from a specific product within the last 3 months? How many/if any across all your organizations within the last 3 months?
Strategic questions
Are any of your users getting stuck setting up a product?
What alerts / CDP destinations can you set up to help you monitor drastic changes in your account metrics in PostHog?
What analysis would help understand why accounts take so long to convert from first login to consistent usage?
Example answers
If you get stuck or want to verify your implementation against an example, below are existing cohorts, insights, etc. to match each question.
So you've got a new CSM joining your team! This page is for team leads - the joiner-facing plan is new starter onboarding. Here's what to prepare and when:
Before they join - prepare their book, book the 1:1s, plan the in-person week
First week - welcome 1:1, get the team sharing calls and tips
In-person week (usually week 2) - 3-4 days working together, agenda template below
First month - any spillover from in-person onboarding
Before they join
Prepare their book of business:
Accounts come from a few places (listed by priority): CSMs can offload accounts if they're overloaded, product-led sales and new business sales can have accounts waiting for a CSM handover, and Simon frequently pulls net-new accounts - ask all groups to see what needs coverage.
Tee up ~20 accounts so they're not at capacity immediately - it also leaves room for late handovers.
Follow the capacity model, and bonus points if accounts can line up with their previous experience.
Book the 1:1s: Welcome 1:1 on day 1, a recurring 1:1, and (optionally) an extended 1:1 every 4 weeks.
Find an onboarding buddy: Another CSM (same geography) to schedule a 1:1 and provide additional support if they need it. Plan the in-person onboarding: Usually week 2 - the agenda below is what we've been running. Logistics that help:
Ask the wider team to see if they're free to drop by for a day or two
Put sessions in your own calendar so you’ve got time blocked for onboarding
Post in the local city channel about the onboarding and organize a dinner with local PostHog humans
First week
Welcome 1:1:
Walk through their onboarding plan - week 1 is a lot of reading, watching and shadowing. It'll feel unproductive!
How we work - sprint planning, account review, ask in public by default.
Our feedback culture, and give them their SuperDay feedback.
How you want to use 1:1 time. Management at PostHog is relatively light-touch - worth resetting expectations upfront, especially if the new CSM is used to heavier structure.
Additional things if there’s time:
Share your readme.
Ask them to post their first five customer calls in the team channel for feedback - gets them used to sharing in public early.
Ask how they like to receive feedback (and praise!)
<summary>Example welcome 1:1 agenda - to copy into your 1:1 doc</summary>
1:1s
- Let's use this doc as our shared agenda for 1:1s and other chats - you set the agenda
- In the 2nd or 3rd 1:1, bring: an email or outreach message you sent to a customer, a call with a customer, and questions you need my help on
- Share your first 5 calls in the team channel
Onboarding
- Here's your [plan](https://posthog.com/handbook/cs-and-onboarding/new-hire-onboarding) for the next few weeks (emphasise!)
- Week 1 is a lot of reading! watching! shadowing! - probably not a lot of doing, which will feel weird. the aim is to load up on context so you're ready to go in onboarding week.
- Share calls to watch - a few recent good ones, ask the team for picks
- Suggested reading:
- PostHog - the company:
- Why: [why does PostHog exist](https://posthog.com/handbook/why-does-posthog-exist), [where are we going](https://posthog.com/handbook/future)
- What: [who we build for](https://posthog.com/handbook/who-we-build-for), [how we make money](https://posthog.com/handbook/how-we-make-money)
- How: [what we value](https://posthog.com/handbook/values), [a wide company](https://posthog.com/handbook/wide-company) with [small teams](https://posthog.com/handbook/company/small-teams)
- GTM / Customer Success:
- [GTM overview](https://posthog.com/handbook/growth/sales/overview)
- [CS overview](https://posthog.com/handbook/cs-and-onboarding/customer-success) + have a skim of the follow-on links
- [Use case selling](https://posthog.com/handbook/growth/use-case-selling/use-case-selling)
- [CSM + TAM](https://posthog.com/handbook/growth/sales/account-allocation)
- [Contract rules](https://posthog.com/handbook/growth/sales/contract-rules)
- Work through your onboarding plan - make sure to prioritize Drata
- Practice your demo
- The plan for onboarding week
How we work
- Sprint planning issue on GitHub
- By default ask questions in #team-customer-success unless it needs to be private
Questions from me
- What's your GitHub handle so I can add you to the sprint template?
- What do I need to know about you to help you do your best work?
Ask the team to share things! And for calls the new CSM can shadow on.
Optionally, a check-in 1:1 on day 3. The first week is a lot of solo reading - a midweek touchpoint helps. Also check to see if the onboarding buddy has scheduled a 1:1 as well!
In-person week (usually week 2)
In-person onboarding covers the company-wide process. Below is how we run the CSM week over 3-4 days - there's a 4-day agenda template to start from, which we copy into a canvas in their onboarding channel. It's a living template - add what you learn from each onboarding. 3 days can feel tight with a lot of information, but it's enough to cover all the content!
By the end of the week they should:
Know how to use the data we have to tell whether a customer is getting value from PostHog, prioritize their book, and plan next steps
Know where to find answers and how to verify them
Have their own Vitally / Customer Analytics views set up, and a first outreach drafted - maybe even sent!
Sessions tend to work best as observe, do, review - you do it once, they try it on their own, and you give feedback.
Topics to cover
Context (day 1)
CSM overview - who we cover, why we exist, how comp works, the CSM + TAM overlay
How we work - sprint planning, account review, the quarterly goal
Tools & access check
Agent setup - MCPs, a PostHog repo clone, impersonation, and a list of GTM skills from the skills store
Finding info - where to look (handbook vs repo vs Slack), maybe even a working exercise (e.g. "what is the Teams plan?")
Understanding a customer's usage (day 2)
What is the customer using PostHog for? The products they pay for, the events they capture, what they do with the data
How's the relationship? The active users and what they're doing (candidates for outreach), recent tickets and calls, which PostHog humans they've talked to (AE, onboarding, TAM, CSM)
The contract, if they're on one - how much credit they bought, when they renew, are they on track? Talk through contract rules and the tools we use (QuoteHog, PandaDoc, Salesforce)
Prioritizing across the book + deciding next steps (days 3-4)
Prioritizing a book - the signals we look at and which ones are more worrisome, both when a book is first assigned and on an ongoing basis. Have them set up their own Customer Analytics views
Deciding next steps - by now they should have a read on where each account's at (or know how to find out). Use next steps that haven't come up yet as chances to talk them through - e.g. a new Slack channel (invite you + support-hog), an upcoming renewal (how renewals work)
Throughout the week
Demo practice with feedback (the more team members attending, the better)
No stupid questions sessions
Their feedback on the week at the end
Optional
PostHog fundamentals - a walkthrough, depending on their familiarity with the product
From here it's much less structured - what to cover and when is your call. Use the 1:1s to go through anything you couldn't fit into the onboarding week, and be okay with repeating things that were covered - onboarding is a lot to take in.
Ask for feedback on the onboarding week, especially on the content covered, so we can keep improving it
Optional: a book walkthrough around week 3-4 - they walk you through their read of their book
Welcome to the PostHog Customer Success team! We only hire about 1 in 400 applicants, so you've done well to make it here!
Onboarding here is mostly self-serve - we won't sit you in a room for training for two weeks, and unlike a lot of companies, we'd prefer you get up and running with your book of customers quickly. If you're not sure who's supposed to make something below happen, the person responsible is almost certainly you.
Below is a rough plan for your first month - use it as a guide, not a contract. The handbook itself is a work in progress, so you'll find gaps as you ramp up, things you needed to know that weren't written down. That's normal, and when you find a gap your job is to fill it in so the next person has it easier.
General advice
A few things every recent joiner has run into:
Everyone will seem to know everything. They've just been here longer. Asking in public is the culture working, not you falling short.
It won't all stick, and it's not supposed to. Onboarding is an info dump - the goal is knowing where to look things up, not remembering it all.
Breadth beats depth early. Don't build a big write-up per account you'll never reopen - a shallow pass over your whole book serves you better in the first weeks.
Don't let product knowledge get in the way of jumping in. You will learn fastest by working with your customers. Be the driver and start building relationships and solving customer requests.
Week 1 – how we talk about PostHog
This week is about getting set up and learning how we talk about PostHog. You'll feel extremely unproductive, and that's fine - the aim is to set yourself up for in-person onboarding in Week 2. Read everything you can, work through the product fundamentals, and come to Week 2 with questions we can work through together.
Focus on:
Setting up the day-to-day tools you'll be using - Vitally, our canonical call stack (Zoom, Gong, and Granola), Slack, and Metabase. See sales and CS tools for set-up, and start copying other CSM's views and automations (or even better, build your own!)
Reading the CS and sales sections of the handbook.
Preparing your PostHog demo.
Picking a recent customer call on Gong to watch, and asking team members to add you to as many of their live calls as you can - the goal is exposure to how we talk about PostHog and how we talk to customers. Best way to do this is check folks' calendars and just ask to join calls that work with your schedule.
Nailing the product fundamentals - use the framework as a guide. For hands-on exercises, the onboarding exercise gets you familiar with the PostHog product, and the HogLabs with implementing it.
Session replay, feature flags, and experiments are the next priority. They're PostHog's most mature products with the most overlap with everything else. But let your book guide you - if your customers are all-in on error tracking, logs, or AI observability, that's an opportunity to go deep early.
Learn how to use the MCP across all products. This is increasingly how customers will interact with PostHog.
Exploring Slack. We're public by default, so Slack is one of the richest resources you have. You'll find outreach messages that worked, prior conversations with customers, PostHog history on decisions like pricing changes, and context that didn't make it into the handbook. Channels to join from day one: #team-customer-success (ask questions here by default), #group-cs-sales-support, #team-product-led-sales, #closed-won, #spike-detector, #customer-churn, and your local city/country channel. For #spike-detector, ask your team lead to add you and tag you as owner on your accounts.
Get your AI investigation setup running early - PostHog Desktop, Claude Code, and the MCPs. It quickly becomes a go-to for digging into accounts.
How to think about each product. As you go through the fundamentals, for each product you're trying to be able to answer:
The value add - why a customer would care
Common use cases to demo
How it's implemented and implementation quirks worth knowing
Signs of poor implementation
How it works alongside other PostHog products
How to get value out of it
What you can do with the MCP
Week 2 – in-person onboarding, your customers
In-person onboarding typically happens this week (3-4 days led by your team lead). You'll get your book of customers, work through how to prioritise it, start digging in, and see how all the systems we use come together.
Focus on:
Walking through your book of business with your team lead - prioritisation, where to start, who to reach out to first.
Digging into individual customers - what they're using, where they are in the lifecycle, any open issues, recent conversations.
Demo practice and feedback.
Seeing how the systems we use (Vitally, PostHog data, PostHog Support) come together day-to-day.
A no-stupid-questions session - bring everything you've been wondering about from Week 1.
First look at signals - what Vitally tags and alerts are, how the team uses them. You won't be confidently responding to them yet, but that comes over the rest of the month.
Weeks 3–4 – start working with your customers
This is when you start working with your customers. Reach out, take the first calls, pick up the questions that come in, and start figuring out what each customer needs from you. You'll learn more about the product as you go, but the main thing in these weeks is starting to be helpful to your customers.
Focus on:
Reaching out to customers in your book to establish contact, scheduling handovers for any coming from existing owners. Getting started with customers covers the playbook for early outreach and intro calls.
Picking up customer questions and tickets as they come in - this is where the bulk of customer work happens. See handling customer issues for how tickets flow.
Evaluating implementations as you go - is the customer set up well, are they getting value? The basic implementation review and health check are the structured ways to do this.
Refining your demo with each conversation.
Starting to respond to Vitally signals on your book - what triggers your attention, what's the right next move? You'll feel confused at first, and that's fine, the goal is to start building a feel for it.
Ship your first handbook PR. Somewhere along the way you'll find a gap or mistake in the handbook, or want to add a new page entirely. Write it up and open a PR. The point isn't the PR itself, it's that the handbook only stays useful if everyone adds to it. Not knowing something isn't a failing, but leaving it undocumented for the next person is.
What good looks like at the end of week 4
This is the bar for end of month 1.
You have a clear read on your book:
Who's responsive and who isn't
Who you'd build a strong relationship with
Who knows you're there
Where the expansion opportunities sit
You're up and running with customers:
Made contact with every customer in your book of business
Handling tickets and customer questions across the products your book uses, with help when needed
Doing demos for those products
Evaluating customer implementations and seeing where to improve them
Understanding how pricing works and the levers you have for cost optimization
You're working with Vitally signals. You know what the signals are and have a sense of how to prioritise and work through them.
You're sharing with the team. You're posting wins, learnings, opportunities for feedback, and anything else valuable in our shared channels. You were hired because we think you can improve our team, so don't be afraid to share opinions and approaches.
Month 2 and beyond
By the end of month 2:
Saved your first 'we're going to churn' - it's going to happen, but you're going to save them!
Be independently working with your entire book to solve tricky technical problems with minimal assistance
Focusing strategically on your customers - engaging with accounts based on risk and growth opportunity, not just reacting to tickets and signals
By the end of month 3:
On track to consistently hit your retention targets
You've suggested and made changes to our systems that enable you to do your job better
Think about customer health scores and add/change anything you learn here
Learning PostHog
PostHog has a lot of products, and you can't learn them all upfront, so trying to will just frustrate you. The lenses in Week 1 are the bar for each product you do learn. This section is how to figure out which products to focus on, how to get hands-on, and what to do when you hit something you don't know.
Find out the products your customers are using. Once you have your book of business, you can see this in Vitally in a few places: the product usage widget in the CSM dashboard, the paid products widget in the default 360 dashboard, or the paid products trait. These look at paid usage only and won't include free-tier usage, though most of our customers aren't in free tier anyway. There's no point going deep on session replay initially if none of your customers use it, so use your book to guide what to prioritise first.
Start with the foundations, then focus on what your book uses. Events, persons, and product analytics are useful regardless of who your customers are. Session replay, feature flags, and experiments are the next priority - they're PostHog's most mature products and have the most overlap with everything else. Past that, prioritise the products that show up most in your book, that keep coming up in customer conversations, and that have expansion opportunities. Implementation, billing, and MCP are worth learning alongside all of the above.
If you learn better by doing, check out the HogLabs. It's a self-contained course on implementing PostHog: create a PostHog project, instrument a small app from zero, and use product analytics, session replay, feature flags, and experiments on data you generated. Then the lab will break your implementation using failure modes from health checks and the basic implementation review, and you diagnose each one and draft the reply you'd send. The lab is modular, so you can do just the foundations, or explore sections based on what your customers use.
Search Slack — you'll find that someone might've already asked the same question or documented the answer in a thread
Post in #team-customer-success
Below is a per-product reading list to work through - the reference you come back to when you need the detail. Add and modify as you go - products are added frequently and the list goes out of date fast.
We have certain automations in Vitally that your team lead needs to add you to. Please ask your team lead to add you.
Vitally name trait playbook: create a new branch that matches assigned CSM to new team member. In this branch, add action to update account trait CSM name to name of the new team member. This is used to populate account owner info in tickets created by customers we own, so support knows who to reach out to.
Each customer is going to be a bit unique when it comes to onboarding and implementation; especially with such a broad product surface area! There are still some best practices we can follow to collaborate with the customer and plan for their success. It really helps customers to build engagement if we can collaborate with them on a plan for their first 30 days at PostHog.
Customize the below template
Customize the template with the goals, specific products and commitments that make sense for your customer's use case.
Share with customer, ideally as a Slack Canvas
Template
PostHog 30-Day success plan
Customer: [Customer Name] | CSM: CSM or AE NAME | Start Date: [Date]
Our shared goal
Week 1: You're getting actionable insights from PostHog Week 3: You've identified specific opportunities to improve your key metrics Week 4: You're confident PostHog is driving measurable business value
---
Week 1: Quick setup & first insights
Goal: See value within 7 days
Your commitments
[ ] SDK Validation: Confirm SDK is properly tracking (usually done in trial)
[ ] Key Stakeholders: Attend 30-min kickoff call
[ ] Custom Events: Define business-specific events you want to track
[ ] Primary Use Case: Define the #1 metric you want to improve
Onboarding Phase: Training sessions and weekly progress check-ins
Post-Onboarding: Monthly or bi-weekly check-ins recurring
---
What You Can Expect From Us
✅ Rapid Response: Same-day replies to questions/issues from your PostHog Human ✅ Proactive Guidance: We'll suggest optimizations based on your usage ✅ Custom Resources: Tailored documentation and best practices ✅ Issue Resolution: PostHog human will resolve issues directly and escalate internally as needed ✅ Product Feedback: Feedback calls or user interviews with product managers or engineers
What We Need From You
✅ Clear Objectives: Tell us the specific metrics you want to improve ✅ Custom Event Planning: Help us understand your business-specific tracking needs ✅ Stakeholder Engagement: Keep key people involved and responsive ✅ Honest Feedback: Let us know what's working and what isn't ✅ Success Definition: Help us understand what ROI looks like for you
---
Questions or concerns? Reach out anytime - our success is measured by your success.
This plan is our shared roadmap. We'll adjust it based on your specific needs and progress along the way.
Prepaid credit plans (usually expiring 12 months after the contract was signed) work for both sides. Customers get a discount, and we get confirmed revenue.
When estimating the renewal amount, accurately project how many credits the customer will need over the next 12 months (or whatever period applies — e.g. 6 months if they prepaid for 6). This isn't the time to upsell. Drive that later through product usage.
Customers on track to use up all their credits early: 3 months before they are due to run out of credits.
The credit bot will ping you in Slack if a customer is set to run out of credits before their renewal date, but you should also keep on top of their credit burn proactively as their CSM.
Other customers: 3 months before the credit expiry date.
At the 3-month mark, the customer moves into the Upcoming renewal segment, a Vitally task is assigned to you, and Slack pings you.
Customers who fit into either of the above buckets will also appear on the CSM Managed — credits expiring in next 3 months insight.
Start with a message in the shared Slack channel — the person you worked with last time might not be the right contact now. Flag the renewal date and ask about preferred next steps.
Once a billing period has been invoiced, we can't backdate a contract start date into it, so a renewal that lands late leaves the customer with a separate invoice the new credits can't cover. This is your true renewal deadline, and you must plan your renewals with this in mind.
Work back from the end of the customer's final billing period (if they are going to expend their credits early, work from the final billing date partially covered by credits). As soon as the amount is agreed upon send the order form out for signature in PandaDoc. Ideally this is at least 2 months before the end of the final billing period. Sending the paper early lowers the odds of a problem but can't remove it. Customers routinely route our order form through their own procurement or e-signature system, and once they do you no longer control when it gets signed. Ask early whether the signer will be available and whether the form has to go through an internal system.
Regardless, have a checkpoint the week before the final billing period closes. If signature is going to slip, either:
Re-paper with the next period's start date. If the period is going to close before signature, don't hold the original start date. Move the Contract.EffectiveDate to the beginning of the next billing period and tell the customer the new credits apply from that date. The period we already invoiced stays payable separately.
Tell the customer which of these is happening while the order form is still out, not after they get an invoice they weren't expecting. If a customer does end up with a balance on an already-issued invoice because the renewal slipped, that's a refund, not a credit. Credits only apply to upcoming invoices.
When the contract dates and the billing dates don't match
The credit expiry date comes from the customer's metadata in Stripe (annual_plan_starts_at, annual_plan_ends_at, and credit_expires_at), not from the date on the order form. The two should not disagree. If for some reason the contract didn't have the right start date, we should note the mismatch with an explanation in opportunity record.
Check the order form dates against billing admin or Stripe when you start a renewal. If they don't match, you own the cleanup as the account owner:
Ask the revops team in #team-revops which date is correct, and ask them to correct the metadata if the order form is right.
Add a comment on the opportunity that records both dates, the confirmed date, and the reason they differ. The next person on the account must not have to repeat the investigation.
Update the renewal opportunity dates to the confirmed dates, including the close date and the contract start date.
Do this as soon as you find the mismatch. The renewal dates drive the Upcoming renewal segment, the Vitally task, and the Slack pings, so a stale date makes the renewal start late.
Unique renewal cases
Customers with credits expiring at end of contract
If a customer has a balance when their contract ends, the credits expire and they move to monthly payments. We have rules to let customers carry over credits on a flat renewal or higher.
If you spot a customer trending this way, reach out early to explain the credit expiry and the options. Use the call to explore projected growth and other use cases. Start the renewal conversation 3 months out so you have time to explore new features and figure out if the carry-over is worth it for them.
Customers with irregular contracts
Many customers are on legacy contracts that don't follow our contract rules — non-Net 30 payment terms, unique discounts, legacy pricing, monthly or quarterly payments.
Prioritize migrating these customers to standard pricing and discounts. The conversations may be difficult, but stick to handbook pricing whenever reasonable — and share the handbook directly to back up your point. Use your judgment on when an irregular term is a deal-breaker worth keeping, and then get approval from Simon Fisher (Ben Bradley as backup) before sharing it with the customer.
Renewal discussions
Do these on a call. There are a lot of moving parts and talking through it works best.
Before the call:
Review the customer's usage and start a quote in Quotehog.
For usage data beyond the last 6 months, use this PostHog dashboard and edit the variables.
Check if they're on a legacy pricing tier — either move them to standard pricing or factor it into your quote.
Use the call to learn about their PostHog experience so far and what's coming up next. It's also a good chance to explain how contracts, credits, and discounts work — our pricing philosophy and contract rules pages are useful references.
When walking through the quote, start with past usage and anchor to their main products (there can be a lot of numbers). Explain how you projected each product's usage. Check in throughout to make sure your assumptions still hold.
After the call, share the public quote link with the customer along with any usage info you discussed.
What to do when things aren't moving forward
If you are struggling to move things along either because the customer isn't engaging with you or you don't know who the right contact person is, ensure you do the following at least 2 months before the date when they need to renew. If things don't move forward within 2-3 working days, move on to the next step.
Message active users either via Slack (ideal) or Email (less ideal) to see if they know who the right person is to engage with on the renewal.
Check who signed the current order form in PandaDoc - it may be that they aren't an active user of PostHog so try and get in touch with them if you haven't already.
Prepare an order form in PandaDoc and send it to the person who is the owner of the PostHog account, or the previous signer. Use your best judgement here - an account owner who is active is likely the best bet, whereas if the owner hasn't been seen in months then they may have moved on from the company. LinkedIn could help you figure out whether these folks are still at the customer. At the very least PandaDoc will tell you if the email and order form have been viewed and forwarded.
Check Stripe to see if we have a finance contact on file - get in touch with them to let them know that
As we haven't got a signed order form they will lose their discount and will be paying $X more per month going forward.
We need a valid credit card on file which we will automatically charge.
Let them know the date of the first monthly payment and expected amount they will be billed.
If you still haven't heard anything from finance, send the information from step 4 to all active users and owners/admins in the account.
If you get to this point and you still haven't secured the renewal, Closed - Lost the renewal opportunity and follow our failed payment process if their first monthly invoice isn't paid, or we don't have a valid card on file.
In any situation where an account moves from annual to monthly, we need to make sure the information in step 4 is made clear to them well ahead of their credit running out. A direct conversation should be had, confirming the change in price, the expected charges, and that there is a valid card on file.
A field guide for customer-facing roles helping customers instrument events so that "X per Y" metrics – roles per user, items per order, messages per conversation, API calls per account – can be built with PostHog's native aggregations instead of HogQL workarounds.
The trap: analysis grain ≠ event grain
Almost every tricky instrumentation question comes down to one mismatch: the customer wants a metric about a fine-grained thing (per user) but instruments a coarse-grained event (per submission). The event fires once when the user acts, but the question is about a unit inside that action.
When the two grains disagree, people reach for one of two shortcuts – packing values into an array or sending a pre-calculated number. Both feel reasonable in the moment, and both quietly cost the customer self-service later. The fix is almost always to change the shape and grain of the events, not to do math on the way in or after the fact.
Running example. A customer is instrumenting an invite flow: one form where a user invites several people and assigns one or more roles to each, then submits once. They want three metrics – users invited per submission, roles assigned per user, and time to complete the flow. The whole guide is built around getting these right.
Rule 1: Match the event grain to the unit of analysis
If the metric is "per user," emit one event per user. The form submits once, but you loop over the invitees on submit and fire a child event for each one. That single move is what unlocks the per-user math – every downstream aggregation now has one row per unit you actually care about.
const submissionId = crypto.randomUUID() // one ID for the whole batch
users.forEach((u) => {
const rolesAssigned = u.roleAssignments.length || (u.role ? 1 : 0)
posthog.capture("invitation_recipient_added", {
submission_id: submissionId, // ties each invitee back to the batch
roles_assigned: rolesAssigned, // scalar → native math (see Rule 2)
roles: u.roleAssignments?.map((r) => r.name) ?? (u.role ? [u.role] : []),
})
})
The entity you're measuring "per" doesn't have to be a user – it can be an account, a session, or any custom object. The rule is the same: emit at the grain you want to analyze. (For account- or workspace-level rollups, reach for group analytics.)
Rule 2: Send scalars for anything you'll do math on; arrays read as strings
This is the one that bites people. If you send a property as an array – roles_per_user: [2, 1] – PostHog's UI treats it as one opaque string. You cannot average, sum, or max it in the insight builder. You'd have to drop into the SQL editor and parse it by hand, which is more than most operators and PMs want to take on.
Keep the array too, when a per-value breakdown is useful:
roles_assigned (number) → the scalar that powers count / sum / average / max. ✅
roles (string array) → the per-role breakdown still works, but only with some finesse: you'll build insights that use HogQL array functions like arrayJoin to fan the array out into one row per value.
So the array isn't wrong – it's just the power-user path. Lead with the scalar for self-service, and add the array when someone needs to slice by the individual values.
Rule 3: Don't pre-aggregate on the way in
It's tempting to compute average_roles_per_user or max_roles_per_user client-side and send that. Resist it. A pre-aggregated number locks the customer into exactly the cuts you anticipated – they can't later ask for the median, the 90th percentile, or the distribution, and they can't break it down by anything.
Send the atomic scalar per child event and let PostHog aggregate on demand. Raw and granular going in = maximum flexibility and self-service coming out.
Rule 4: Stitch related events together with a shared ID
Generate one submission_id (a UUID) per batch and stamp every child event with it. Now the children are linked to each other and back to the parent, so you can always climb from "roles per user" up to "which submission" – or filter one submission's worth of events – without guessing.
Rule 5: Use a parent + child pair when you need funnels and per-entity math
A funnel needs one clean signal per submission to key a step off of. The per-user distribution needs one event per user. Those are different grains, so emit both events, tied by submission_id:
const submissionId = crypto.randomUUID()
// Parent: one per submission — the funnel's terminal step
posthog.capture("invitation_submitted", {
submission_id: submissionId,
user_count: users.length,
submitted_at: new Date().toISOString(),
})
// Child: one per invitee — carries the per-user detail
users.forEach((u) => {
const rolesAssigned = u.roleAssignments.length || (u.role ? 1 : 0)
posthog.capture("invitation_recipient_added", {
submission_id: submissionId,
roles_assigned: rolesAssigned,
roles: u.roleAssignments?.map((r) => r.name) ?? (u.role ? [u.role] : []),
})
})
invitation_submitted (parent) – one per submission. It's the terminal step of the funnel and the home for submission-level numbers like user_count.
invitation_recipient_added (child) – one per invitee. It carries the per-user detail (roles_assigned, roles).
The parent answers submission-level and funnel questions; the child answers per-user questions. Together they cover both without compromise.
Rule 6: Derive durations from timestamps, don't compute them client-side
For "time to complete the flow," send the raw submitted_at timestamp and pair it with the $pageview timestamp PostHog captures automatically. Compute the delta in the analysis layer rather than shipping a pre-computed duration – same logic as Rule 3, and it keeps the raw timestamps available for other questions.
The payload, at a glance
Child – invitation_recipient_added (one per invitee)
| Property | Type | Why it's shaped this way | | ---------------- | --------------- | ------------------------------------------------------------------- | | submission_id | string (UUID) | Ties the invitee back to its submission and to the parent event | | roles_assigned | number | Scalar – enables native count / sum / average / max / percentiles | | roles | string array | Per-role breakdown, via HogQL arrayJoin |
Parent – invitation_submitted (one per submission)
| Property | Type | Why it's shaped this way | | --------------- | ----------------- | ----------------------------------------------------------------- | | submission_id | string (UUID) | Batch identifier and funnel key | | user_count | number | Users invited in this submission | | submitted_at | string (ISO 8601) | Paired with the auto-captured $pageview time to derive duration |
With this shape, each of the customer's original goals maps to a native insight: users invited per submission is user_count (or a count of children grouped by submission_id); roles assigned per user is the average of roles_assigned across the child events; which roles are most assigned is a breakdown of roles; and time to complete is submitted_at minus the $pageview timestamp.
Cheat sheet: When a customer hands you an array
Want to sum / average / max / count it? → send a scalar on a child event.
Want to break down by its values? → keep the string array and use HogQL, or emit one event per value.
Want both? → send both, exactly as in the example above.
The one-line version
Instrument at the grain you want to analyze, send scalars for anything you'll do math on, and never pre-aggregate.
A field guide for customer-facing roles helping customers reduce LLM spend with AI Observability.
Why this matters now
Every flavor of AI – agentic, generative, functional, to name a few – is now woven into the infrastructure of most major SaaS organizations. As the relative intelligence of frontier models converges, the exponential spend from LLMs is much more visible on a company's P&L. PostHog sits at every observable layer of the technology stack, so customer-facing roles will field a growing number of asks about how to optimize LLM-related spend.
_Token efficiency_ is delivering the required output quality using the fewest tokens across prompt, context, and response. It's the highest-priority lever, and the biggest wins are architectural. Customer-facing roles at PostHog are well positioned to understand and convey the common cost optimization levers and how they're instrumented.
The cost model
There are three main drivers of LLM spend.
Model selection – using a frontier model on a trivial task is like taking a Ferrari to the grocery store. Cost varies significantly across model family, catalog, and provider, so picking the right tool for the job makes the difference.
Context window usage – you might think it's just long prompts, retrieval-augmented generation (RAG) applications, and extensive chat histories, but you'd be wrong. It also includes tool and skill bloat, which happens when an AI agent has access to too many tools and skills, causing decision paralysis as it struggles to find the right one.
Output length – output tokens can cost ~4-5× input tokens because generation is sequential, which can make verbosity the most costly lever.
One note on the math: cost is an _estimate_ from tokens × matched pricing (OpenRouter data) – ideal for the breakdown (which model, feature, or customer, and the trend), but reconcile the absolute total against the provider console or gateway, since negotiated rates, brand-new models, and some customers' billing live outside PostHog. To improve accuracy, customers can pass pre-calculated $ai_input_cost_usd and $ai_output_cost_usd, or set custom per-token pricing with $ai_input_token_price and $ai_output_token_price.
The toolbox – and what each looks like in PostHog
The goal is maximum impact without affecting quality. Work top-down, starting with the lowest-risk levers.
A note on breakdowns: dimensions like feature and product below are custom properties the customer sets on their generations (plain property names, no $ prefix) – not reserved PostHog properties.
Low risk
1. Prompt caching – reuse a stable, front-loaded prompt prefix instead of reprocessing it. This isn't about making the prompt shorter; it's about keeping the prefix identical across calls. For example, using cache_control in calls to Anthropic models charges 0.1× for cached input because the compute is skipped.
Watch: any prefix change (even a timestamp) busts the cache.
_In PostHog:_ break down $ai_input_tokens by feature to find a stable prompt dominating input. After enabling, validate by watching the cached-token share rise and $ai_total_cost_usd per call drop at the same volume.
2. Output discipline – set max_tokens per task type (a classifier needs ~20 tokens, not the SDK's 4,096 default) and use structured outputs (JSON/schema) for extraction and classification. This can cut a significant portion (sometimes 30-60%) of output cost.
_In PostHog:_ rank features by output:input ratio ($ai_output_tokens ÷ $ai_input_tokens). Afterward, output tokens per call fall and cost follows.
3. Batch API – submit asynchronous work for a significant discount, processed via batching. Use it for large jobs that don't require streaming.
Watch: latency – it's a job returning data on a schedule.
_In PostHog:_ tag offline jobs with a task_type property and watch their share of total cost; cost-per-task on those features roughly halves after moving to batch.
Medium risk
4. Context hygiene – continuously evaluate and trim the system prompt (30-40% is often removable), use a sliding window or rolling-summary compression for long chats, and retrieve 3-5 RAG chunks instead of 50. Long workloads can be reduced significantly.
Watch: over-trimming drops context whose value shows up later – tune on real traces.
_In PostHog:_ watch $ai_input_tokens climb across a $ai_trace_id or session. Afterward, input tokens per generation flatten.
5. Model routing – route each request to the cheapest model that can handle it, using heuristics/rules or a model-based classifier. This takes more work up front since it adds a layer to the architecture, and the obvious risk is added complexity and another model in the mix. It won't work without LLM calls that carry metadata.
Watch: the math wins only if the savings exceed the classifier costs, the retries from routing errors, and the engineering maintenance.
_In PostHog:_ break down $ai_total_cost_usd by $ai_model and the relevant metadata (feature, product, etc.) to spot frontier-model spend on trivial features. Validate by watching spend shift over time toward cheaper models on trivial tasks.
High risk
6. Semantic caching – match queries by embedding similarity and return the cached answer, bypassing the model entirely. Use it for FAQ-style, stable-answer, low-context, read-only knowledge. This is the riskiest lever because it trades correctness for cost.
Watch: false-positive similarity (cancel "order" versus cancel "subscription"), time decay of answers (returning last month's price when someone asks for current pricing), data drift, and model or prompt upgrades.
_In PostHog:_ for customers serving features in scope, identify high-$ai_generation-volume candidates. Recommend shadow testing, then Feature Flags, then production. Validate by a reduction in excessive $ai_generation volume without consumer impact.
A field guide for customer-facing roles using AI to investigate and explain customer issues, without letting machine-generated output stand in for verified facts.
Why this matters now
L1 support might as well be dead. Have you really lived if you've never copy and pasted a customer's question into Claude Code and just typed "debug"? Don't get me wrong, AI is the fastest way to get an understanding of a customer issue. The speed is the point and the trap. We (you, me, us) exist as the human-in-the-loop, where the skill we are exercising is judgment.
Whether we realize it or not, a confident and well-formatted .md file from Claude is treated like ground truth when it's attached to a ticket or a Slack thread. The risk isn't that AI is wrong sometimes; it's that wrong output is indistinguishable from right output until someone verifies it.
The discipline that keeps this safe is one rule, applied to two audiences.
The two-output rule
Keep two things separate, always: the AI output (a hypothesis a model generated, which can be overly verbose and hard to follow) and your analysis (what you've confirmed yourself against the data). They are not the same artifact, and collapsing them is how speculation gets laundered into truth. AI theorizes, we validate and iterate.
This holds for both audiences below. Internally, we should do our best to explicitly separate the two to avoid confusion. The external version is about distilling down to only what survived verification before anything reaches a customer.
Internal: separate the analysis from the output
When investigating a customer issue, treat AI output as directional guidance. It is still your responsibility to shoulder the critical thinking around the product with your investigation workflow. The model will tell you where to look, but your understanding of the trace, the replay, the dashboard, and the query result. This is the analysis.
Label anything that is machine-generated, especially in shared notes and tickets. We're all developing a good eye for it, but mark AI output as AI output: a heading, a quote block, a "(AI draft, unverified)" tag. The goal is that a teammate skimming your investigation can instantly tell which lines are confirmed and which are a model's guess.
Watch: plausibility is not verification. AI is most dangerous when it's fluent and specific about something it can't actually know: a root cause, a customer's intent, an exact number. Torture your keyboard asking for verification steps. Phone a friend if you must.
External: distill before you share
What goes to a customer should be a short, human-reviewed summary of verified facts. Distillation is the value add: you've separated signal from speculation so the customer doesn't have to.
Share large AI analysis files sparingly, if at all. A long, marked-down AI analysis is an internal working artifact, not a customer deliverable. Sending the raw file is tempting. It can feel like something the customer might want to see ("I bet they'd love to see this!"). Customer relationships _will_ erode if we are shipping unverified claims, internal reasoning, or speculation from the model that is actually a hallucination.
Default to a concise summary; share the full file only when the customer specifically needs the detail and you've reviewed every line in it first. When an issue is resolved, send the customer the confirmed cause and fix in a few sentences. Keep the long AI investigation in the internal ticket, linked for teammates, not pasted into the reply.
Do and don't
Do treat AI output as a hypothesis until you've checked it against the source data.
Do label machine-generated content clearly in shared notes and tickets.
Do send customers a concise summary of verified facts.
Don't paste a confident AI summary into a ticket as if it were confirmed analysis.
Don't forward raw AI analysis files to customers by default. Distill first.
Don't put identifiable customer data into AI tools without applying our data-sensitivity rules.
The PostHog AI platform is our infrastructure for building and delivering AI-powered features across all PostHog products. Instead of each team building isolated AI capabilities, we provide shared architecture, reusable components, and a consistent framework that lets everyone contribute toward our AI capabilities while maintaining quality and consistency.
Think of it like HogQL: rather than having every team write their own query engines, we built one shared system that everyone can use and extend. The AI platform follows the same philosophy — avoid reinventing AI infrastructure and prevent "death by random AI widgets."
Why we built it
Almost every team at PostHog either is building or needs to build AI features. Without a platform approach, we'd face:
Fragmented user experience: Different AI interactions across products with inconsistent quality and UX patterns
Duplicated effort: Multiple teams solving the same problems (authentication, error handling, rate limiting, tool calling)
Maintenance burden: Each team maintaining their own AI infrastructure, models, and prompt engineering
Limited capabilities: Teams constrained to simple AI features because building advanced functionality (like multi-step reasoning or agentic workflows) from scratch is too expensive
The AI platform solves these problems by providing:
Shared architecture: A single-loop agent system that any product can extend with domain-specific tools and expertise
Reusable components: Common tools (search, data access, taxonomy reading) that work across all AI features
Consistent UX: Standard patterns for AI interactions, loading states, error handling, and result presentation
Platform-level improvements: When we improve the core agent (better reasoning, faster responses, cheaper inference), all products benefit automatically
Vision: Self driving product
The overarching goal of PostHog's AI direction is self driving product. A self-driving product can prompt itself. It understands your codebase, your data, and your users. It proposes and ships work on its own, inside of guardrails you set.
The self in self-driving isn't autonomy from the engineer. It's autonomy from user instruction as the starting point.
Here's how the loop works:
Signals: PostHog collects signals from all products and external sources — error patterns, frustration in session recordings, experiment results, survey responses, insight thresholds, support tickets, Slack threads, and more. These signals represent real problems or opportunities.
Enrichment: PostHog processes and enriches these signals, deduplicating across data sources and adding context. A vague signal like "users seem frustrated during checkout" becomes a concrete, contextualized finding.
Plans: The enriched signals are transformed into structured plans — similar to how Claude Code works, but driven by data rather than human prompts. Each plan describes what needs to happen, why, and what evidence supports it.
Execution: A sandboxed coding agent takes these plans and acts on them. Today, we're focused on automatically creating pull requests. The agent also handles instrumentation automatically — adding tracking events, feature flags, and experiments as part of the code it ships. Better instrumentation produces better signals, making the entire loop smarter over time. In the future, other artifact types will be supported — decks, growth reviews, and more.
Review: Product engineers review, iterate on, and merge (or decline) the proposed changes.
Feedback: Once a change ships, a new signal is created so the system can evaluate what happened after the PR was merged. Did the metric improve? Did new errors appear? This feeds back into step 1.
Loop: The cycle continues until the agent finds an exit condition — low actionability, non-important signals, noisy signals, de-prioritized work, etc.
graph LR
Signals[Signals<br/>Internal: errors, recordings, experiments<br/>External: support tickets, Slack] --> Enrichment[Enrichment<br/>ML & agentic pipelines<br/>deduplicate, contextualize, prioritize]
Enrichment --> Plans[Plans<br/>Structured, data-driven<br/>action items]
Plans --> Execution[Execution<br/>Coding agent creates<br/>PRs and artifacts]
Execution --> Review[Review<br/>Human oversight,<br/>iterate or merge]
Review --> Feedback[Feedback<br/>New signal created<br/>from shipped changes]
Feedback --> Signals
This vision connects all the individual AI products. PostHog products and external sources (support tickets, Slack) generate signals, ML and agentic pipelines enrich them into structured plans, background and local coding agents execute on those plans, and product engineers review and collaborate on the changes. The loop closes when shipped changes generate new signals that feed back into the cycle.
Your primary interface for working with PostHog. Instead of clicking through forms and menus, describe what you want in natural language. PostHog AI can create dashboards, write SQL queries, set up surveys, and answer questions about your data — all through conversation.
Best for: Quick answers, creating resources, learning PostHog, iterative exploration Status: Beta | Pricing: Paid with free tier
When you need to investigate complex, open-ended problems, Deep research digs deep. It systematically explores your data — session recordings, analytics, error logs — and produces comprehensive research reports that would take a human analyst hours to create.
Best for: Understanding why metrics changed, investigating user behavior patterns, root cause analysis Status: Under development | Pricing: Paid with free tier
Analyze hundreds of session recordings in minutes instead of hours. Session summaries finds patterns, clusters similar issues, and shows you what's actually happening across your user sessions — not just what you caught in the first few recordings you watched.
An agent development environment that solves the messy workflow problem of engineering with coding agents. Each task gets its own isolated workspace where an agent works — you can guide the agent, review changes, and switch between workspaces, with everything related to a task in one place instead of across your terminal, editor, and GitHub.
Best for: Product engineers who work on multiple tasks simultaneously and already use agents heavily Status: Beta | Pricing: Usage-based (AI credits, no markup) with free tier
Get PostHog set up in minutes instead of hours. The Wizard detects your tech stack, generates integration code, verifies the installation, and gets you collecting data with minimal manual work.
Best for: New PostHog users, setting up new projects, quick integration Status: General availability | Pricing: Free
Bring PostHog into your development environment. The MCP server makes PostHog AI's features available to Claude Code, VS Code, and other MCP-compatible tools, so you never have to leave your editor to check analytics or create insights.
Best for: Engineers who prefer editor-based workflows, combining PostHog with other data sources Status: General availability | Pricing: Free
For a list of key concepts definitions, see the Glossary.
Getting started
For users
Want to try PostHog AI? Open the chat interface in PostHog and start asking questions. See user documentation.
Prefer working in your editor or coding agent? Set up the MCP server in Claude Code or VS Code.
Need deep investigation? Toggle to Deep research feature in PostHog AI.
For engineers building AI features
Not sure where to start? See Integration vectors for product teams for the different ways your team can contribute — MCP tools, skills, signals, and more.
The agent uses dynamic modes: The single-loop agent architecture uses dynamically loadable modes that expose PostHog capabilities.
MCP provides universal access: The MCP server makes agent features accessible to any MCP-compatible client. PostHog AI, PostHog Desktop, Session Summaries, Wizard, and third-party tools like Claude Code all consume the same MCP server.
Task generation feeds PostHog Desktop: Signals from PostHog data, PostHog AI conversations, and Deep Research investigations are processed into structured tasks that PostHog Desktop can execute.
Shared features: Every surface consumes the same agent features through the MCP, ensuring consistency across the platform.
Single-loop agent architecture
Mode switching
PostHog AI is based on a single-loop agent architecture, heavily inspired by Claude Code, with some PostHog unique flavour. The core insight is simple: instead of routing between multiple specialized agents that act as black boxes, we have one agent that maintains full conversation context and can dynamically load expertise as needed.
The single-loop agent has direct access to all tools, uses a todo-list pattern to track progress across long-running tasks (just like Claude Code), and provides complete visibility into every step it takes. When it needs specialized knowledge, it doesn't delegate to a sub-agent — it switches its own mode to become an expert in that domain.
How the single-loop agent works
sequenceDiagram
participant User
participant Agent as Single-Loop Agent<br/>(Full Context)
participant Tools
User->>Agent: "Create a funnel for signup flow"
Agent->>Tools: Call read_taxonomy<br/>(check what events exist)
Tools-->>Agent: Returns actual events:<br/>'user_signed_up', 'account_created'
Agent->>Tools: Call enable_mode("Analytics")<br/>(load funnel creation tools)
Tools-->>Agent: Analytics mode enabled<br/>with insight creation tools
Agent->>Tools: Create funnel with correct events:<br/>'user_signed_up' → 'account_created'
Tools-->>Agent: Funnel created successfully
Agent-->>User: "I've created a funnel tracking your signup flow.<br/>It shows 45% conversion from 'user_signed_up'<br/>to 'account_created'"
The key differences from older architectures:
No hallucination: Agent checks read_taxonomy before assuming event names exist
Full visibility: All tool calls are visible to the agent throughout the conversation
Maintained context: The agent remembers every decision it made and can build on them
Explainable: The agent can justify every choice because it has complete visibility
Core tools: Always available
No matter what mode the agent is in, it always has access to a core set of tools:
The search tool is unified search with a kind discriminator. You can search documentation (kind=docs), search existing insights (kind=insights), or search other resources as we add them. This replaced having separate search_docs and search_insights tools.
The read_data tool lets the agent read database schema and billing information. The read_taxonomy tool is how the agent explores your events, entities, actions, and properties. These are crucial for avoiding hallucination problems we had before — the agent can always check what data actually exists before making assumptions.
The enable_mode tool is how the agent switches between different areas of expertise, which we'll discuss in detail next.
Finally, todo_write is the tool that lets the agent manage long-running tasks. When you ask for something complex, the agent can write out a plan, track its progress, and make sure it doesn't lose context.
Agent modes: Dynamic expertise
Here's the key innovation: instead of having specialized sub-agents, we have a single agent that can "switch gear" by switching modes. Each mode gives the agent new tools, a new system prompt with domain expertise, and example workflows (which we call "trajectories") to follow.
It works in two stages. First, a small model router analyzes the user's request and enables some default modes. Then, during the conversation, the agent can call enable_mode("SQL") to switch into SQL expert mode, gaining SQL-specific tools and knowledge. The agent knows which tools it had before, which new ones it gained, and can switch back or switch to a completely different mode at any time.
Each mode is defined by three things:
A routing prompt that explains when to activate this mode and lists the available tools. This is what the small model router and the main agent use to decide when to switch modes.
A system prompt that contains expert instructions for this domain. When the agent switches to CDP mode, for example, it gets a system prompt explaining how CDP destinations work, what Hog functions are, and how transformations should be structured.
Workflow trajectories that give the agent examples of how to accomplish tasks. We inject example workflows into the todo_write tool description. For instance, the CDP mode might include a trajectory like: "Setting up CDP destination: 1. Write HogQL transformation code, 2. Define input variables, 3. Set event/property filters, 4. Test with sample data before activating."
This architecture allows product teams to create their own modes without touching the core agent. Modes can be composed and nested. Think of it as "thousands of agents" through mode combinations, rather than a fixed set of AI products.
When do black-box sub-agents still make sense?
There are exceptions. Some processes benefit from being hidden from the main agent — usually when the logic is completely detached from the conversation context, or when you want to use strategies or optimizations that would confuse the main agent if exposed. Our agentic RAG system for insight search is a good example: it iteratively searches through insights and cherry-picks the best ones using a complex scoring system. The main agent doesn't need to see all that — it just needs the final result.
The problem we needed to solve: PostHog AI and the MCP server were developed by different teams, didn't offer the same tools, and had completely different architectures. Users would find features in PostHog AI that didn't exist in the MCP, and vice versa.
The solution is an abstraction layer. Agent modes expose both high-level LLM tools (like "create a funnel with these parameters") and low-level API endpoint tools (like "call POST /api/projects/{id}/insights"). Both PostHog AI and the MCP have access to the same features, just through different interfaces.
How PostHog Desktop and Wizard fit in
Both PostHog Desktop and the Wizard currently consume the MCP. This integration gives them access to all the agent modes we're building. If Claude Code (which PostHog Desktop uses for code generation) ever becomes a bottleneck, we could swap in PostHog's own single-loop agent since they share the same mental model. We'd need to copy over Claude Code's terminal and file system tools (bash, grep, etc.) and add them as core tools.
We could also tag modes for specific interfaces. For example, a CodingMode(tags=["posthog-code"]) would only be exposed to the PostHog Desktop agent, not to PostHog AI, because it's specific to code generation workflows.
Glossary
Agent: An autonomous AI process that can reason about what to do, plan multiple steps, and take actions by calling tools. PostHog is an agent. Claude is an agent.
Single-loop architecture: An agent architecture that maintains full context throughout a conversation without delegating to black-box sub-agents. The agent can see all tools, all previous messages, and all decisions it's made.
Feature: Any Agent capability we expose to the user. Creating insights, summarizing sessions, performing a Deep research, all of these are features.
Tool: A capability the agent can call to perform actions — search docs, create insights, write SQL queries, etc.
Agent mode: A specialized configuration of an agent that gives it domain-specific tools, expert knowledge (via system prompts), and workflow examples. When PostHog AI switches to "SQL mode," it becomes an expert in writing and debugging SQL queries.
Trajectory: An example workflow showing the sequence of steps to accomplish a specific task. We use trajectories instead of the heavier "jobs-to-be-done" framework to teach agents how to use tools together effectively.
MCP (Model Context Protocol): A standard protocol for connecting AI models to external tools and data sources in a structured, secure way. Think of it like an API, but specifically designed for AI agents.
MCP Server: The component that exposes tools and data sources following the MCP specification. PostHog's MCP server makes our analytics data available to any MCP-compatible client.
MCP Client: The component that connects to MCP servers to discover and use tools. Claude Code, VS Code with AI extensions, and other tools can act as MCP clients.
This page provides implementation guidance for building AI features at PostHog. For a high-level overview, see the AI platform overview.
How PostHog AI works across surfaces
PostHog AI isn't a single product – it's a platform that works wherever customers work. Through a combination of MCP tools and skills, PostHog AI is available across any agent of the customer's choice: PostHog AI in the web, PostHog Desktop, Claude Code, Cursor, Codex, and others.
All of these surfaces share the same underlying capabilities. The MCP server exposes PostHog's API as atomic tools, and skills teach agents how to compose those tools into workflows. When a product team adds a new MCP tool or writes a new skill, every surface benefits automatically.
PostHog AI renders its own interface in several places. The one that matters most for product teams is the side panel, which opens beside whatever page the user is already on:
| Surface | What it is | | --- | --- | | The side panel | Opens anywhere in the PostHog app, next to the page the user is working on. | | /ai | The full-page scene. /max redirects here, and /ai/history lists past threads. | | /home | The AI-first project homepage embeds an instance. | | /tasks | The standalone agent-run scene. | | Signals inbox | Read-only embeds of a finished run. | | PostHog Desktop | A separate app that runs the same agent implementation on top of tasks. It has its own interface, so it needs its own UI integration. |
The first five are the PostHog web app, and the frontend seams described below apply to all of them. PostHog Desktop shares the agent but not the frontend, so an integration there is separate work.
PostHog AI in the web
PostHog AI in the web is a sandboxed coding agent built on the Agents SDK (Claude Code's harness). It runs in a controlled environment with access to PostHog's full API surface and unlocks use cases that go beyond what a simple chat interface can offer:
Better coverage of existing products – the agent can navigate across product boundaries, combining data from analytics, session recordings, feature flags, and more in a single workflow.
Advanced SQL writing and analysis – the agent writes HogQL queries, executes them, and reasons over large result sets to answer complex analytical questions.
Automatic instrumentation for non-technical users – users who aren't engineers can describe what they want to track and the agent generates instrumentation code.
User-created custom skills and capabilities – customers can create their own skills to teach the agent domain-specific workflows.
PostHog Desktop
PostHog Desktop is a desktop agent that turns PostHog signals into shipped code. It watches PostHog for problems (errors, frustration patterns, user feedback) and automatically creates tasks, generates fixes, and opens pull requests with human oversight at key decision points.
Third-party agents
Engineers who prefer to work in Claude Code, Cursor, Codex, or any other MCP-compatible tool get access to the same PostHog capabilities.
Headless first, then wire up the UI you have, then build one the agent renders
Product teams must think about AI features as headless (UI-less) workflows. Agents don't need UI – they compose tools and follow skills to accomplish goals. But customers do need UI, and there are two different things that can mean.
The rule of thumb: headless first, then wire up the UI you already have, then build a new one the agent renders.
Build the capability headless – expose your product's API as MCP tools and write skills that teach agents how to use them. This makes the capability available across all surfaces immediately.
Wire up the UI you already have – tell the agent what the user has open, and update the page when the agent changes something. This is a small amount of frontend work on the product you already have, and it's what makes the side panel feel like part of your product instead of a chat window next to it. See integrating your product's UI below.
Then build a UI the agent renders – if a persona (product manager, engineer, analyst) needs an experience of their own, build an MCP App. That UI lives in the agent client, not in the PostHog app.
This order matters because headless capabilities are reusable across every surface, while UI is specific to one. If you build UI first, you've created something that only works in one place. If you build headless first, you've created something that works everywhere, and you can always add UI later.
Step 2 is the one teams skip. It's cheap, it applies to the product you already shipped, and without it a user watching PostHog AI edit their feature flag sees a stale form.
MCP tools vs skills
Understanding the distinction between tools and skills is essential for building effective AI features.
MCP tools are atomic capabilities – CRUD operations and simple actions. They answer "what can I do?" (list feature flags, execute SQL, create a survey, summarize a session recording). Tools should be basic primitives that agents compose into higher-level workflows.
Skills answer "how do I accomplish X?" They combine tools, domain knowledge, query patterns, and step-by-step workflows into a template that agents follow to solve a class of problems. A skill might reference multiple tools, include HogQL query examples, explain what data to verify before querying, and describe the desired outcome for the customer.
This separation matters because agents are good at composing simple tools but need guidance on _which_ tools to use, in _what order_, with _what constraints_.
Everything in this section is frontend work in the PostHog app. There is no backend integration API – nothing you build here talks to a PostHog AI backend. The agent reads and writes your entities through your MCP tools, so an integration always has two halves, and the frontend half depends on the backend half.
Injected context carries _references_, not data. A reference the agent can't resolve with a tool is a dead end, so ship the tool first.
The seams live in the PostHog AI product's frontend, and the full detail is in its integration README. In the monorepo, the /integrating-with-posthog-ai skill walks an agent through the same material.
The import rule
Import from a domain-scoped api/<module> entry. Don't reach into internal paths, and note there's deliberately no root barrel:
Pick the narrowest module that does the job. api/logics and api/types are headless, api/primitives pulls in markdown rendering and virtualization, and api/tools registers built-ins at module load, so importing it is a side effect that isn't tree-shaken. A status badge that imports the wrong tier doubles its chunk.
Seam 1: inject context
Register what the user is looking at. While it's registered, every message sent from the surface is silently prefixed with a context block describing it. The user only ever sees their own text.
Items are abstract. type is any string you like ('insight', 'trace', 'text', 'hog_flow_editor_state') and never an enum, plus optional key, label, value, hidden, and dismissGroup. JSX-only call sites can render ` instead. From a kea logic, register through a disposable with pauseOnPageHidden: false` – the default hide-pause would silently drop context from a follow-up that flushes while the tab is hidden.
Three rules:
Inject identifiers, not object shapes. The context block rides on _every_ message in the conversation, so a serialized entity is a per-turn cost that never goes away. Send the reference and let the agent fetch details through your MCP tools.
This context is untrusted, by design. It lands in a <posthog_untrusted_context> block behind hardening prose that tells the agent it's data, not direction. That's what makes it safe to inject whatever the user typed – and you should, because their unsaved work is usually the most useful thing you have. Don't sanitize user text into blandness.
Strip secrets before you serialize. Saved secrets never reach the frontend, but a secret typed into a form and not yet saved sits in cleartext in your live form state.
The exception to the first rule is unsaved progress the agent can't fetch: live editor or form state. When you send that, budget it. The Workflows editor caps its state at 64,000 characters and _elides_ the heavy nested parts, replacing them with a marker telling the agent which tool to call for the full value. Elision keeps the JSON parseable, and blind truncation doesn't.
Deduping is automatic and scoped to the task, covering the whole chain of runs. text items are the exception and always resend.
Seam 2: inject custom instructions
type: 'instructions' is the one reserved item type. Its value lands in a <posthog_trusted_context> block – guidance the agent is told to follow. Use it to say what the user has open and which tools to prefer:
const ISSUES_QUERY_TOOL_CONTEXT_ITEM: AttachedContextItem = {
type: 'instructions',
hidden: true,
value:
'The user has the error tracking issue list open. When you call query-error-tracking-issues-list, the filters ' +
'from your query (filter group, status, date range, search, ordering, assignee) are also applied to the open ' +
'page, so the user sees matching issues both in this chat and on screen.',
}
Trusted means static. Instructions must only ever carry your own build-time strings. Never a user-entered name, an ingested value, or a string interpolated from one. Trusted context is direction the agent follows, so a crafted entity name there is a prompt injection against whoever reads the thread next, including other users on a shared task.
If an instruction needs to point at something that varies – which record is open, which step is selected – don't interpolate it. Put the pointer on an ordinary untrusted item and have the static instruction refer to it by field name. There's a second reason to do this: instructions dedupe by exact text, so a varying ID inside an instruction gets pruned on a reopen, leaving a stale pointer as the newest surviving text.
The richest use of trusted context is handing the agent everything it needs up front, so it doesn't spend turns discovering tools or reading skill files. The Workflows editor attaches a preamble, the full text of its skill, one item per MCP tool, and a visible chip the user can detach. All of it comes from a generated module that pulls the skill markdown and tool descriptions out of the repo at build time – which is what makes them safe as trusted strings. Don't hand-copy skill text into a component, because it will drift from the skill it claims to be.
Seam 3: react to what the agent does
A global event bus publishes tool-call lifecycle events with resolved tool names. Two consumer APIs use it.
Reload after the agent changes something, with useToolStreamListener. The bus is global, so an event about some other record still reaches you – parse the inner arguments and check the call was actually about the thing you're showing.
Apply an agent edit back into an open form, with useMcpToolApplyBack. This is the one to reach for when the side panel is open next to your editor: the user asks PostHog AI to change a feature flag, and the open form updates instead of going stale.
It's a hardened wrapper over the bus, not a convenience alias. It only fires for the run rendered in the panel the user is watching, so a background task can't rewrite the page under them. It snapshots the active registration when the prompt is sent, so navigating to a different editor mid-run can't hand the response to the new one. And it fails closed when more than one target claims the same tool.
Two caveats bite people:
Replay events are suppressed by default. A page reload replays the run's history through the same code path. Without suppression every handler would re-fire on every reload, creating things twice or re-applying stale edits.
The tool name is unreliable when a call starts. For PostHog tools wrapped in an exec call, the command streams in through later updates. Match on completion whenever correctness depends on knowing which tool ran.
Pair an apply-back with a trusted instruction telling the agent its tool calls are reflected on the open page. Otherwise it doesn't know the user can see the result, and may narrate the change instead of making it.
Seam 4: render your own tool cards
Register a renderer and your product's tool calls display as a real card in the thread instead of the generic MCP fallback. Registration is a module-level side effect – call it once from your scene's entrypoint:
An entry can draw the result card, the approval prompt shown _before_ a write runs, or both. Set requiresPostHogOrigin on anything that renders PostHog entities, so a same-named tool from another MCP server can't render through your card.
A tool card is two header lines plus an accordion. You get a title and one subtitle – the single most salient input. Everything else your tool produces goes in the collapsible body, so a thread with twenty tool calls stays scannable and a reader expands only the cards they care about. Reserve the always-visible area for something the user must act on. Output is never that.
MCP Apps are a different mechanism. Those render tool results in _external_ clients such as Claude Desktop, and don't appear in PostHog AI threads. "Make our results look good in Claude Desktop" is an MCP App. "Make our results look good in PostHog AI" is this seam.
Seam 5: build a custom UI on the run primitives
The same facade exposes the machinery for rendering and driving an agent run yourself: a read-only embed, a compound surface with thread and composer slots, the whole /tasks product inline, and the thread and composer primitives underneath.
Avoid this unless you know exactly what you're doing. The four seams above are what a product integration needs. This one means owning stream binding, composer and queue state, permission routing, and the choice that decides whether your surface doubles someone's bundle. There's no default layout, so you compose one. If you need it, copy one of the two reference implementations rather than composing from scratch.
Shortcut for a whole scene
useSceneAgentPanel bundles context, contextual welcome headlines, and gated auto-open of the side panel into one call. Start there for a scene, and drop to the individual hooks for a single component.
What not to use
The LangGraph runtime is frozen. Don't add useMaxTool registrations, MaxUIContext fields, or maxContext selectors on scene logics. New integrations use the seams above.
Implementation recommendations
For engineers adding AI features
Expose your product's API as MCP tools. Every product should be accessible through the MCP server. Scaffold a YAML definition, enable the operations that make sense, and add a HogQL system table for data access. See Adding tools to the MCP server.
Write skills for jobs to be done. If your product has jobs that require domain knowledge – specific tool ordering, constraints, query patterns, or reasoning about what data to check – write a skill that teaches agents how to accomplish that job well. See Writing skills.
Wire up the UI you already have. Attach the entity the user has open, add a trusted instruction describing what this page is for, and update when the agent changes something you're displaying. Each of these is a hook call on a component you already have, and together they're what makes the side panel useful on your product. See integrating your product's UI.
Build a UI the agent renders only when a specific persona needs it. Don't start with a UI-specific AI feature. Start headless, validate that agents can accomplish the workflow, then add an MCP App if a persona needs an experience of their own.
Product teams should type and describe their serializer fields. These descriptions are what agents read to understand tool parameters – vague or missing descriptions lead to worse agent behavior.
Tips:
Use help_text on serializer fields – it becomes the OpenAPI description.
Use param_overrides in YAML definitions to override generated descriptions with imperative instructions.
Be specific about formats, constraints, and valid values.
Avoid jargon that an LLM wouldn't understand without context.
We charge usage-based instead of a flat subscription
The unit that matches usage the closest is token consumption. This means to fix a SQL query with AI, the user would pay very little, analysing hundreds of session recordings will cost more. Since token costs differ based on token type & model, we are passing on our own costs to our users, with a small markup, instead of having a fixed price per token.
To keep our AI pricing simple, this pricing applies to all AI features once they are in general availability, that means per-product AI features as well as Session summaries and Deep research.
So that users can learn how to use PostHog without worrying about being charged, we are keeping chats that refer to our documentation free without a limit.
How users should think about our products
PostHog AI is the main PostHog product for AI interactions. You can use it in the web for the richest experience, through PostHog Desktop for code-generation workflows, or through any third-party agent via MCP. The web UX is best for sharing, navigation, and linking between AI results and PostHog artifacts. PostHog AI is also trained on PostHog-specific patterns and your actual usage data, so it provides higher quality, more contextual results than a general-purpose AI.
Deep research is a feature available within PostHog AI, but also accessible through its own dedicated UI if you want to jump straight into research. Use it for open-ended investigative work where you're trying to understand a complex problem.
Session summaries is callable from PostHog AI and Deep research, and also has its own UI. Use it when you need to analyze many session recordings and extract patterns or issues.
PostHog Desktop is a desktop product for single-engineer use. It's separate from PostHog AI because the workflow is different – you're not asking questions, you're letting an AI agent watch PostHog for problems and automatically fix them in your codebase. Think of it as an AI assistant that lives in your development environment.
MCP is for users who prefer to work in third-party tools like Claude Code, Cursor, or Codex. You get access to PostHog's data and can combine it with other MCP servers (like Hubspot or Zendesk). The trade-off is you don't get PostHog AI's polished UX or PostHog-specific optimizations.
How to develop and test
Set up the MCP stack locally. Run hogli dev:setup and add the MCP stack to your local environment.
Write YAML configs and skills. Use the monorepo skills to scaffold and shape the work: /implementing-mcp-tools for tool definitions, /writing-skills for skills, and /integrating-with-posthog-ai for the frontend seams.
Build skills and pick them up locally. Run hogli build:skills to render all skills, then hogli sync:skill -- --name <skill-name> to copy one into .agents/skills/ so Claude Code discovers it. hogli unsync:skill -- --name <skill-name> removes it again.
Test with headless agents, not UIs. Forget about UIs – that's for humans. Test your tools and skills by talking to Claude Code or another headless agent. If the agent can accomplish the job, the capability works.
Test with PostHog Desktop. Sign in to a local environment in PostHog Desktop and verify the end-to-end workflow.
Alternatively, add the local MCP server to Claude Code. Run claude mcp add --transport http posthog-local http://localhost:8787/mcp to point Claude Code at your local MCP server.
Test a UI integration in the app. Attached context is invisible by design, so check it landed: an item that isn't hidden shows as a chip in the composer, and the agent should answer a question about the thing you attached without being told its ID. For a reactivity seam, ask the agent to make the change and confirm the open page updates, then reload the page and confirm your handler does _not_ fire again.
Future directions
Third-party context integration
We want to connect PostHog AI to third-party tools for additional context. Imagine PostHog AI analyzing data across PostHog, Slack messages, and Zendesk tickets to understand not just what users are doing, but what they're saying and reporting. This data could also generate signals for PostHog Desktop – if users are complaining about a bug in Slack and PostHog sees errors in the same area, that's a strong signal to investigate and potentially fix automatically.
Continuous instrumentation
The Wizard's future evolution involves continuous instrumentation – watching your codebase and suggesting event tracking for new features, filling gaps in existing tracking, and standardizing event patterns. This could integrate with PostHog Desktop to automatically handle PostHog instrumentation when generating code.
Research improvements
Deep research is being refined with better research strategies, improved denoising algorithms, and more sophisticated pattern recognition. The goal is to reduce rabbit holes and improve data interpretation accuracy.
Contact and resources
For questions about working with PostHog AI, ask in the #team-posthog-ai Slack channel.
This page provides detailed information about each user-facing product in the PostHog AI platform. For a high-level overview, see the AI platform overview.
PostHog AI [Beta]
PostHog AI is our primary in-app agent, accessible through a chat interface embedded directly into the product. Think of PostHog AI as a fundamentally different way to interact with PostHog — instead of clicking buttons and filling out forms, you ask questions and make requests in natural language.
The problem we're solving
PostHog has grown incredibly powerful, but that power comes with complexity. New users face a learning curve: Which insight type should I use? How do I filter for the data I need? What's the right SQL syntax for this query? Even experienced users spend time navigating through menus and forms to accomplish what they already know they want to do.
PostHog AI eliminates this friction. You don't need to know where a feature lives or how to configure it — you just describe what you want, and PostHog AI handles the details.
Who uses PostHog AI
Everyone. PostHog AI is designed to be useful whether you're:
A new user learning PostHog for the first time (PostHog AI explains terminology and walks you through setup)
An engineer who knows exactly what they want and just wants to say it instead of clicking through the UI
A product manager who wants quick answers without learning technical details
A data analyst who needs to write complex SQL queries with help
How it works
PostHog AI is built on a single-loop agent architecture with dynamic mode switching. When you send a message, PostHog AI analyzes your request, determines which specialized "modes" it needs to activate, and dynamically loads the appropriate tools and expertise. For example, if you ask PostHog AI to "create a funnel tracking the signup flow," it might:
Use the read_taxonomy tool to check which events actually exist
Switch to Analytics mode to access insight creation tools
Switch to SQL mode if you need custom transformations
Switch to CDP mode if you want to set up a destination based on the funnel results
Throughout this entire process, PostHog AI maintains full context — it can see all previous messages, all decisions it's made, and all tools it's used. This is fundamentally different from older architectures we implemented where specialized sub-agents worked in isolation.
For a technical deep dive on how this works, see the Architecture page.
Key capabilities
PostHog AI can do most things you can do through the PostHog UI:
Search and filter: Find insights, filter session recordings, search documentation
Create and modify: Build dashboards, create insights, set up surveys
Write SQL: Generate and debug HogQL queries for custom analysis
Learn PostHog: Ask how features work, get recommendations on best practices, understand terminology
Work with data: Read your taxonomy (events, properties, actions), check database schema, access billing information
PostHog AI is powered by Inkeep for documentation search, which means it can pull from PostHog's entire doc library to answer questions about how to use the platform.
Pricing
PostHog AI is paid platform, with a generous free tier (see Pricing).
Current status & ownership
PostHog AI is currently in beta as we migrate to the new single-loop architecture. Early results show significant improvements in reliability and capability, but we're still ironing out edge cases before moving to general availability.
The owns the architecture, performance, and UX/UI. Product teams are responsible for adding their product-specific tools and capabilities, with the PostHog AI team providing reviews and guidance (see Team Structure for details on collaboration).
Deep research [Under development]
Deep Research is PostHog AI's bigger sibling — where PostHog AI gives you quick answers, Deep Research digs deep to understand complex, open-ended problems.
The problem we're solving
Product analytics often requires real investigative work. You don't just want to know "what's my conversion rate?" — you want to understand why it's dropping, which user segments are affected, where in the flow they're getting stuck, and what patterns exist across multiple data sources. This kind of research is time-consuming. You might spend hours jumping between dashboards, filtering recordings, cross-referencing error logs, and synthesizing findings.
Deep Research automates this investigative work. It can spend minutes or hours (depending on complexity) systematically exploring your data, following leads, and producing a comprehensive research report that would take a human analyst half a day or more.
Who uses Deep research
Deep research is designed for anyone who needs to understand complex problems:
Founders trying to understand why growth is stalling
Engineers debugging issues that span multiple systems
Product managers investigating why a feature isn't performing
Data analysts exploring patterns across customer segments
If you have a vague question that requires digging through multiple data sources to answer, Deep Research is the right tool.
Input: You either start with a templated research notebook (for common research patterns) or describe your question and Deep Research generates a custom notebook structure.
Parallel initialization: Deep research simultaneously creates a draft report (outlining what it expects to find) and a research plan (what questions to investigate).
Iterative research: The agent systematically investigates each part of the research plan. It might filter session recordings, run analytics queries, check error logs, compare cohorts, and more. Each investigation adds findings to the draft report.
Denoising: As research progresses, Deep research "denoises" the draft report — removing speculative parts that turned out to be wrong, strengthening findings that are supported by data, and identifying new questions to investigate.
Loop: Research continues until the draft report is fully denoised — meaning all sections are supported by actual findings rather than speculation.
Final report: Once complete, you get a structured notebook with the findings, including embedded session recordings, charts, and data that support each conclusion.
Notebooks are the perfect format for research because they combine narrative explanation with data visualization. You can see not just the conclusions ("conversion drops 40% at the payment step") but the evidence (charts showing the drop, session recordings showing users struggling, error logs showing timeouts).
We're building customizable notebook templates similar to what Granola does. You'll be able to pick a template or modify one ahead of time, so research results come back in exactly the format you need. This is especially useful for recurring research tasks where you want consistency.
Key differences from PostHog AI
While both PostHog AI and Deep research can answer questions about your data, they're optimized for different use cases:
PostHog AI is fast (seconds to minutes), conversational, and best for specific questions with clear answers
Deep research is thorough (minutes to hours), systematic, and best for open-ended problems that require synthesizing multiple data sources
Think of PostHog AI as your coworker who can quickly pull up data, and Deep Research as the analyst who will spend the afternoon really digging into a problem.
Access and pricing
Access Deep Research by toggling "Research" mode in PostHog AI, or via the dedicated Deep Research UI. It's a paid feature with a generous free tier (see Pricing).
Current status & ownership
Deep Research is under active development. The PostHog AI team owns Deep Research. The architecture is implemented but we're still refining the research strategies and denoising algorithms. Early results show it can find patterns and insights that human analysts miss, but it occasionally goes down rabbit holes or misinterprets data — we're working on improving these edge cases.
Session summaries [Alpha]
Session summaries solves a specific but painful problem: you have dozens or hundreds of session recordings, and you don't have time to watch them all. Instead of spending hours scanning through recordings one by one, Session Summaries analyzes them all at once and gives you a structured report of what it found.
The problem we're solving
Session recordings are incredibly valuable — they show you exactly what users are experiencing. But they're also time-consuming to review. If you have 100 recordings from users reporting checkout issues, do you really want to watch all 100? Most people watch a few, spot some patterns, and hope they caught the important stuff. This means you miss edge cases, low-frequency issues, and patterns that only emerge across many sessions.
Session summaries changes this calculus. You can analyze hundreds of recordings in minutes, with confidence that you're seeing all the significant patterns, not just the ones that happened to appear in the first few recordings you watched.
Who uses session summaries
Session summaries is designed for anyone who needs to understand patterns across multiple user sessions:
Engineers debugging problems that only some users experience
Product managers investigating UX issues
Customer success teams diagnosing why users are struggling
Researchers trying to understand how different cohorts use a feature
If you find yourself thinking "I need to watch a bunch of recordings to understand this," Session Summaries is the right tool.
How it works
You can trigger Session summaries in three ways:
Ask PostHog AI directly: "Summarize the last 50 sessions from company X"
Trigger Session summaries from the Session Replay UI or from other products
Let Deep research invoke it as part of a larger investigation
Here's what happens under the hood:
Collection: Session summaries retrieves all the recordings matching your criteria (time range, company, feature area, etc.)
Analysis: An AI agent "watches" a session recording (right now, analyzing the stream of metadata, and soon enough, by watching video clips), noting significant events: errors, timeouts, rage clicks, confusion indicators (rapid back-and-forth navigation), unexpected user paths, and other behavioral signals.
Clustering: Instead of giving you 50 individual summaries, Session summaries clusters similar issues together. For example, if 15 users all experience timeout errors at checkout, these get grouped into a single issue: "Timeout errors during payment processing (affects 15/50 users)."
Report generation: You get a notebook with:
Issue clusters ranked by frequency and severity
Representative video clips showing each issue
Context about which users/cohorts are affected
Patterns that might not be obvious from individual sessions
What Session summaries finds
Currently, Session Summaries is trained to identify:
Errors: JavaScript errors, failed API calls, broken images
Creative usage patterns: "Show me where users are using the product in ways we didn't expect"
Workarounds: "Find sessions where users had to work around a limitation"
Feature discovery: "Which features do power users rely on that casual users don't know about?"
Delight moments: "Find sessions where users had a particularly smooth experience"
The underlying technology is the same — watch many recordings, find patterns, cluster similar behaviors — but the training and prompts can be tuned for different objectives.
Access and pricing
Access Session Summaries through PostHog AI, Deep Research, or its dedicated UI entry points. It's a paid feature with a generous free tier (see Pricing).
Current status & ownership
Session summaries is in alpha. The PostHog AI team owns Session summaries. It's working well for error and frustration detection, and early users report finding issues they would have missed. We're refining the clustering algorithms (sometimes it groups issues too broadly or too narrowly) and integrating video and GIF analysis to support findings with visual confirmation.
PostHog Desktop [Under development]
PostHog Desktop is our most ambitious bet: an agent development environment that turns PostHog data into shipped code. The vision is to free product engineers from distractions so they can focus on what they love — building great features — by automating all the chores that eat up their day.
The problem we're solving
Today, product engineers spend most of their day managing random inputs: Slack messages, GitHub notifications, tickets, emails, and alerts from various monitoring tools. This work is essential but time-consuming. Experienced AI-native engineers have already evolved a workaround — they practice "structured development," creating PRDs, breaking work into tasks, and shipping incrementally. Tools like Claude Code or Cursor only work well when given clean context and well-defined tasks.
PostHog Desktop aims to productize that discipline, turning chaos into structured, buildable work.
Who we're building for
PostHog Desktop is designed for experienced product engineers who already use AI coding tools regularly. We're explicitly not targeting non-technical "vibe coders" or hobbyist users. Our initial customer profile is early-stage startups with 2-10 engineers and hundreds to low thousands of users. We'll expand to larger startups later as internal workflows and scale requirements become more complex.
How it works: From Signals to shipped code
The core insight is that PostHog collects massive amounts of data across all our products — analytics, session recordings, error tracking, surveys, experiments. All of this data can be transformed into actionable "tasks" that describe real problems to fix or opportunities to pursue.
Here's the flow:
Signal generation: Something happens in PostHog that indicates work needs to be done. This could be a recurring error pattern, frustration signals from session recordings, a survey response indicating a missing feature, or experiment results suggesting an optimization. The Signals team focuses on surfacing this data in useful ways.
Task creation: An LLM-based system receives these signals, deduplicates them across data types, and translates them into concrete tasks with appropriate context. This uses a non-deterministic approach — we use a document store and LLMs to judge how to structure tasks. A vague signal like "users seem frustrated during checkout" becomes a specific task: "Investigate and fix timeout issues in payment processing, affecting 15% of transactions from company X."
Task execution: Once a task is defined, it gets assigned to a workflow. Different tasks need different approaches — a well-defined bug fix might be a one-shot fix with human QA, while a vague feature request might need definition, breaking into chunks, gradual shipping behind a flag, and automated feedback collection.
Coding: PostHog Desktop uses an agent running in a cloud sandbox (though we support local execution too). The agent clones your repo, reads your codebase for context, makes changes, writes tests, and opens a pull request. Changes are automatically wrapped in feature flags when appropriate.
Human oversight: You're always in control. The desktop app shows you what PostHog Desktop is working on, lets you review and edit tasks, and requires your approval before shipping. This "human-in-the-loop" approach means you can trust PostHog Desktop to work in the background while you sleep, but nothing ships without your sign-off.
Why a desktop app?
This is a crucial design decision. We could have built PostHog Desktop directly into the PostHog web app, and it would work. But it wouldn't generate the adoption we need.
Desktop apps win because of bottom-up adoption. Individual engineers can choose tools that make them more productive in a permissionless, frictionless way. A desktop app feels like a personal tool — like VS Code, Cursor, or your terminal — rather than a team product that requires management buy-in. Engineers already make personal choices about vim vs VSCode, which terminal to use, which AI coding assistant to try. PostHog Desktop slots into that category.
The UX also matters more for tools you use all day, not just a few times a week. PostHog Desktop is designed to feel like something between Warp, Ghostty, and Cursor: super fast, keyboard-first with lots of shortcuts, easy to navigate with tabs and split windows. Think of it as having the directness of a CLI but with the richness of a UI when you need it.
The interface
PostHog Desktop is tab-based with the home tab being a task list. You navigate with arrow keys, click a task to open it in a new tab with a two-pane view: task details on the left (title, description, tags, origin, PR link) and a live log of activities on the right. When a task is in progress, it streams output to this log so you can watch the agent work. There's also a workflow builder view where you can see tasks moving through stages kanban-style.
Technical architecture
PostHog Desktop is built as an Electron app for speed, familiarity (React), and cross-platform ease. When a task kicks off, we have two execution options:
Cloud agent (preferred): Tasks execute in a cloud sandbox owned by the PostHog AI team. The agent runs in an isolated environment, clones the repo, does its work, and pushes to a branch. The downside is you need to grant GitHub app access. The upside is truly magical — PostHog Desktop can work on tasks while you sleep, and you wake up to PRs ready for review.
Local agent (more permissionless): We spin up Claude Code-like execution in the background on your local filesystem. This is the most permissionless version, closest to how developers use Claude Code today. We still give it access to the MCP and PostHog tools, and we likely need to proxy through our infrastructure to maintain control and provide a smooth experience.
We support both modes, but push for cloud execution as the optimal experience.
PostHog Desktop isn't just for data-driven bug fixes. The system for shipping a fix is the same as the system for shipping any feature. A vague task needs definition, then breaking into chunks, then shipping with proper releases planned. A small, well-defined task just needs a one-shot fix and QA.
Even inspiration-driven features (not from user data) benefit from PostHog Desktop's workflow: add event tracking, ship behind a flag, automatically message users for feedback, set up an experiment to measure impact. PostHog Desktop productizes best practices for shipping features, not just fixing bugs.
Current status
Right now we're focused on dogfooding — getting the to build everything using PostHog Desktop itself. This lets us refine product quality and identify friction fast.
For engineers not using PostHog Desktop
When PostHog Desktop isn't the right fit (maybe you don't trust AI to ship code automatically, or your workflow is very particular), we offer "copy prompt" features throughout PostHog. In error tracking, for example, you can generate an AI prompt to fix an error and paste it into your own code editor. This bridges the gap for engineers who want AI assistance but prefer to maintain manual control.
Ownership
The dedicated owns the product. The owns the background sandboxed agents. See Team Structure for collaboration details.
The Wizard is PostHog's AI-powered installation assistant that gets you from zero to collecting data in minutes instead of hours. Instead of reading documentation, finding the right SDK, figuring out configuration, and manually integrating PostHog into your codebase, you run one command and the Wizard handles everything.
The problem we're solving
Setting up analytics is tedious. You need to pick the right SDK for your tech stack, install dependencies, configure authentication, add initialization code in the right place, set up your first events, and verify everything works. For a developer who just wants to start tracking user behavior, this feels like unnecessary friction before you even get value from the product.
Even experienced developers waste 15-30 minutes on setup. For new developers or teams trying PostHog for the first time, it can take much longer — and if anything goes wrong, they might give up entirely.
The Wizard eliminates this friction. You run a single command, answer a few questions, and the Wizard writes all the integration code for you.
Who uses Wizard
The Wizard is designed for:
New PostHog users getting started for the first time
Teams trying PostHog on a new project or codebase
Developers who want to add PostHog to an existing application quickly
Anyone who prefers automated setup over manual integration
Basically, anyone who would rather spend time using PostHog than setting it up.
How it works
The Wizard is a CLI tool that runs locally in your development environment. Here's the flow:
Detection: The Wizard scans your codebase to detect your tech stack (React, Next.js, Python, etc.), framework version, and project structure.
Configuration: It asks you a few questions — which PostHog project to connect to, whether you want autocapture enabled, any custom configuration. The questions are contextual based on what it detected.
Code generation: The Wizard writes the integration code. This includes:
Installing the appropriate PostHog SDK via your package manager
Adding initialization code in the right location for your framework
Setting up configuration with your project token
Optionally adding example event tracking code
Verification: The Wizard verifies the integration works by sending a test event to PostHog and confirming it arrives.
Next steps: It suggests what to do next — track your first custom event, set up a dashboard, or explore session recordings.
The entire experience uses Clack.cc for a polished CLI interface with clear prompts, progress indicators, and helpful error messages.
Current capabilities
Right now, the Wizard handles installation and basic setup across PostHog's supported SDKs. It's particularly good at:
Detecting complex framework setups (like Next.js with app router vs pages router)
Handling different package managers (npm, yarn, pnpm)
Placing initialization code in the right location based on framework conventions
Configuring autocapture and basic options
Future direction
The Wizard's long-term vision is much broader than one-time setup. Imagine:
Continuous instrumentation: The Wizard could watch your codebase and suggest event tracking for new features. "I noticed you added a new checkout flow — want me to add tracking events?"
Instrumentation improvements: "Your signup flow isn't tracking all the steps — I can add events to fill the gaps."
Best practices: "You're tracking events in 5 different ways. I can standardize this for you."
Integration with PostHog Desktop: The Wizard is already integrated into PostHog Desktop, handling PostHog instrumentation automatically when generating code (feature flags, experiments, custom events).
This would turn the Wizard from a one-time setup tool into an ongoing assistant that keeps your PostHog instrumentation clean and comprehensive.
Current status & ownership
The Wizard is in general availability and actively used during customer onboarding. It's currently owned by the .
MCP: PostHog for third-party tools [General availability]
The MCP (Model Context Protocol) server is PostHog's way of meeting engineers where they already are. Not everyone wants to switch to the PostHog UI to analyze data — many prefer to stay in their code editor, terminal, or favorite AI tool. The MCP server makes that possible.
The problem we're solving
Context switching is expensive. If you're deep in debugging code in VS Code and need to check PostHog analytics, opening a browser, navigating to PostHog, finding the right insight, and coming back to your editor breaks your flow. It's even worse when you're using an AI coding assistant — you want to ask "which error is affecting the most users?" or "create a funnel for the checkout flow" without leaving your development environment.
The MCP server solves this by bringing PostHog directly into the tools engineers already use. No context switching, no mental overhead.
Who uses MCP
MCP is designed for engineers who prefer working in their development environment:
Developers using Claude Code or VS Code with AI extensions
Engineers who want PostHog data combined with other data sources (GitHub, Zendesk, Hubspot)
Teams with custom workflows or tooling that can consume MCP servers
Anyone who prefers command-line or editor-based workflows over web UIs
How it works
The Model Context Protocol (MCP) is a standard for connecting AI assistants to external services. Here's what happens when you use PostHog via MCP:
Connection: Your MCP client (like Claude Code) connects to https://mcp.posthog.com/mcp with your PostHog API key for authentication.
Tool discovery: The client asks the MCP server what tools are available. The server returns a list of about 30 tools covering PostHog's API surface — everything from creating insights to filtering session recordings to managing feature flags.
Dynamic filtering: You can control which tools load using query parameters: https://mcp.posthog.com/mcp?features=flags,insights,workspace. This keeps context windows small by only loading relevant tools.
Execution: When you ask the AI assistant to do something with PostHog, it calls the appropriate MCP tools. These tools interface with PostHog's APIs (and eventually dedicated /ai endpoints, under development) to accomplish the task.
Mode switching: The MCP server is being aligned with our mode switching framework. This means AI agents can dynamically enable and disable different modes during a conversation, loading only the expertise they need when they need it. This solves the context window problem — currently, loading all tools takes up about 14% of Claude Code's context window, which we're reducing through dynamic tool discovery.
Key architectural decisions
The MCP server is deployed independently on CloudFlare. This gives us fast iteration, proven reliability, and excellent developer UX with quick deployments. We dogfood PostHog's customer-facing API wherever possible, which gives us good incentive to take care of it.
The MCP server also supports session state (active project ID, org ID, distinct ID), so it can fingerprint sessions and maintain context across multiple requests.
PostHog AI vs. MCP: When to use each
Both PostHog AI and MCP give you access to the same features, but they serve different workflows:
Use PostHog AI when:
You want the best possible UX with sharing, navigation, and linking between AI results and PostHog artifacts
You're doing exploratory analysis and want to iterate quickly
You need Deep Research or Session Summaries features
You want AI specifically trained on PostHog patterns and your actual usage data
Use MCP when:
You prefer to stay in your code editor or terminal
You're combining PostHog data with other MCP servers (GitHub, Zendesk, etc.)
You have custom tooling that can consume MCP servers
Your workflow is already centered around a third-party AI tool
Our goal is to make PostHog AI so good that users want to "own" their workflow in PostHog, while still supporting MCP for engineers who prefer different tools or need to combine multiple data sources.
Current Status & Ownership
MCP is in general availability. The PostHog AI team owns the MCP server, with Josh Snyder as the primary support contact. We're actively working on dynamic tool discovery to reduce context window usage and aligning the server with our mode switching framework to share features with PostHog AI.
This page explains how teams collaborate on AI features at PostHog. For a high-level overview, see the AI platform overview.
Who does what
The PostHog AI team
is responsible for the architecture, performance, and UX/UI of the AI platform. We build and maintain the core infrastructure – the MCP server, skills system, PostHog AI in the web, background sandboxed agents, and shared tooling (search, read_data, read_taxonomy, enable_mode). We're also proactive when we see big opportunities for PostHog or when new capabilities can be used across multiple products, like SQL generation or universal filtering.
The PostHog Desktop team
builds PostHog Desktop, an agent-powered product workspace. Everything you and your team need to build and manage your self-driving product. The product is organized around channels that create a multiplayer experience around working with agents, then augment the agent sessions with PostHog's data and channel context that learns over time
The PostHog Desktop team owns the desktop app and the task execution pipeline.
The Self-driving team
turns PostHog data into tasks that coding agents can work on — suggested improvements from session replays, fixes for errors from error tracking, new experiments based on product analytics data. Signals surfaces something useful, creates a task with context, and the cloud agent works on it.
Product teams
Product teams own their product's AI capabilities end-to-end. The AI platform is designed so that any team can ship MCP tools and skills independently, without needing the PostHog AI team to be involved. This means you can:
Add MCP tools that expose your product's API to agents
Write skills that teach agents how to accomplish jobs in your domain
Build UI for specific personas using MCP Apps when needed
Once you ship a tool or skill, it's automatically available across every surface – PostHog AI in the web, PostHog Desktop, Claude Code, Cursor, and any other MCP-compatible agent.
Signals surfaces useful data from PostHog, creates a task with context, and the cloud agent works on it. You review and iterate in PostHog Desktop.
PostHog AI owns the background sandboxed agents and can start coding agent tasks during chats. These tasks are inspectable in both the web product and PostHog Desktop.
PostHog Desktop is where engineers review, guide, and manage agent work across all their tasks in one place.
Product teams ship their own MCP tools and skills independently. Once shipped, these are automatically available across every surface.
Integration vectors for product teams
There are multiple ways product teams can contribute to PostHog's product autonomy vision. These are listed roughly in order of effort, from easiest to most ambitious.
MCP: Expose your APIs to agents
The most obvious and lowest-effort vector. Expose your product's APIs through the MCP server so agents can interact with your features.
Effort: Low
Consumers: PostHog AI, PostHog Desktop, coding agents (Claude Code, Codex, etc.), Wizard, vibecoding platforms (Lovable, Replit, etc.), ChatGPT & Claude Desktop, and more.
Skills: Teach agents how to do jobs
If you've already exposed your APIs, the next step is explaining how an agent should accomplish typical jobs-to-be-done — analyzing activity in PostHog, debugging why a feature flag was turned off, implementing enterprise features, etc. Skills combine tools, domain knowledge, and step-by-step workflows into templates agents can follow.
Effort: Medium, but the impact is very high.
Consumers: PostHog AI, PostHog Desktop, coding agents (Claude Code, Codex, etc.), ChatGPT & Claude Desktop, and more.
Signals: Feed the autonomy loop
If your product produces actionable or near-actionable signals — an insight threshold reached, a new error-tracking issue, a frustration pattern detected — use the signals API so agents can discover these hints and act on them later. Signals are what enable the product autonomy loop. PostHog Desktop acts on plans generated from these signals.
Effort: Low to medium.
Consumers: PostHog Desktop (local development) and PostHog AI (background agents).
PostHog Desktop: Features for the agentic development environment
PostHog Desktop is an agentic development environment where coding agents work on tasks in isolated workspaces. If your product area can make those agents smarter or the engineer's workflow faster, you can build features directly into it. Think PR reviews that check session recordings for regressions, QA steps that verify instrumentation coverage, or task prioritization that weighs your product's signals. This is the highest-effort vector but also the most deeply integrated.
Effort: High.
Consumers: PostHog Desktop.
Automations & background agents
Run PostHog AI based on triggers from PostHog Workflows, CRON, Temporal, etc., to automate complex workflows. Example use cases: analyze an incoming support ticket based on indexed documentation and respond to the customer, or spawn a new signal like "here is a bug, fix it."
Effort: Medium to high.
Consumers: Your persona using the web browser (UI), PostHog AI, PostHog Desktop, coding agents (Claude Code, Codex, etc.), Wizard, vibecoding platforms (Lovable, Replit, etc.), ChatGPT & Claude Desktop, and more.
How to get started
The AI platform is self-service by design. Follow the implementation guides to add tools and skills for your product area:
Add MCP tools. Scaffold a YAML definition, enable the operations that make sense, and add a HogQL system table for data access.
Write skills. If your product has jobs that require domain knowledge – specific tool ordering, constraints, query patterns, or reasoning about what data to check – write a skill that teaches agents how to accomplish that job well.
Test with headless agents. Validate that agents can accomplish the workflow by talking to Claude Code or another MCP-compatible agent before building any UI.
Tag the PostHog AI team in PRs. We review PRs that touch the AI platform to ensure they meet our quality bar and integrate well with the rest of the system.
You don't need the PostHog AI team to ship tools and skills, but we're always happy to help. Reach out to us in #team-posthog-ai if:
You have an unusual use case that doesn't fit the existing tool or skill patterns
You need something from the AI infrastructure that isn't supported yet
You want design help thinking through how your product should work with agents
You're unsure whether AI is the right approach for a problem – sometimes what seems like an AI problem is better solved another way
Don't hesitate to reach out early, even if it's just a vague idea. We'd rather help you think through the approach upfront than have you discover a dead end after building.
Best practices
Start headless, then UI
Build your product's AI capabilities as headless workflows first – expose the API as MCP tools, write skills for the key jobs. This makes the capability available across all surfaces immediately. Only add dedicated UI when a specific persona needs it. See Implementing AI features for more on this approach.
Start small
Begin with simple tools and iterate based on user feedback. It's better to ship something that works reliably for one workflow than to build something ambitious that works unreliably for ten workflows.
Describe your API fields
API field descriptions flow through the entire pipeline and become what agents read to understand tool parameters. Vague or missing descriptions lead to worse agent behavior. See Adding tools to the MCP server for details.
When bugs are reported it's critical to properly gauge the extent and impact to be able to prioritize and respond accordingly. These are the priorities we use across the entire engineering org, along with the relevant labels to quickly identify them in GitHub.
Please always remember to tag your issues with the relevant priority.
<td><span class="tag-label" style="background:#f0a000;">P1</span></td> <td>Urgent, non-breaking (no crash but low usability)</td>
<td ><span class="tag-label"style="background:#ffe000;">P2</span></td> <td>Semi-urgent, non-breaking, affects UX but functional</td>
<td><span class="tag-label" style="background:#1d76db; color: white;">P3</span></td> <td>Icebox, address when possible</td>
Security issues
Security issues, due to their nature, have a different prioritization schema. This schema is also in line with our internal SOC 2 related policies (Vulnerability Management Policy). When filing security-related GitHub issues, remember to attach label security and the appropriate priority label. More details on filing can be found in the README of the product-internal repo.
Security issue information should not be made public until a fix is live and sufficiently (ideally completely) adopted.
PostHog security issues include a priority (severity) level. This level is based on our self-calculated CVSS score for each specific vulnerability. CVSS is an industry standard vulnerability metric. You can learn more about CVSS at FIRST.org and calculate it using the FIRST.org calculator.
| GitHub Label | Priority Level | CVSS V3 Score Range | Definition | Examples | |---|---|---|---|---| |security-P0|Critical|9.0 - 10.0|Vulnerabilities that cause a privilege escalation on the platform from unprivileged to admin, allows remote code execution, financial theft, unauthorized access to/extraction of sensitive data, etc.|Vulnerabilities that result in Remote Code Execution such as Vertical Authentication bypass, SSRF, XXE, SQL Injection, User authentication bypass| |security-P1|High|7.0 - 8.9|Vulnerabilities that affect the security of the platform including the processes it supports.|Lateral authentication bypass, Stored XSS, some CSRF depending on impact| |security-P2|Medium|4.0 - 6.9|Vulnerabilities that affect multiple users, and require little or no user interaction to trigger.|Reflective XSS, Direct object reference, URL Redirect, some CSRF depending on impact| |security-P3|Low|0.1 - 3.9|Issues that affect singular users and require interaction or significant prerequisites (MitM) to trigger.|Common flaws, Debug information, Mixed Content|
ClickHouse powers nearly every analytical feature in PostHog: trends, funnels, retention, paths, session replay, error tracking, logs, data warehouse queries, and more. This page describes how we operate it, and the patterns that let us run analytics over very large datasets while keeping interactive queries fast and ingestion reliable.
Workload isolation
The most important idea in our setup is that we don't run one giant cluster. We run a fleet of clusters, each dedicated to a class of workload.
Early on we ran a single cluster and quickly learned that mixing workloads on shared hardware creates unpredictable performance. A heavy background job, such as a large export, a cohort recalculation, or a backfill, would contend for CPU, memory, and disk I/O with the interactive queries a user was waiting on, and query latency would spike. Any one expensive query or misbehaving job could slow down the entire product.
So we split ClickHouse up by workload. Interactive product queries run on clusters tuned for low-latency reads. Ingestion runs on its own clusters sized for sustained write throughput. Session replay, logs, batch exports, API-style endpoints, and internal operational tooling each get dedicated capacity. Because these clusters are separate, a spike in one workload can't degrade another, and we can size, tune, and scale each one for the specific access pattern it serves.
A unified query experience over separated data
Splitting data across many clusters and shards would be painful if every product engineer had to know where each piece of data physically lived. They don't. Data is sharded and replicated underneath, but queries are written against a logical view of it. ClickHouse's distributed table engine fans a query out to the shards that hold the relevant data, each shard does the selective work of finding and filtering its portion, and the results are combined. Product code asks for "events for this team in this time range" and the topology stays an operational detail rather than an application concern.
Storage tiers
Our data has a convenient property: it's overwhelmingly time-ordered, and recent data is by far the hottest for both reads and writes. That's a good fit for tiered storage.
We keep hot, recent data on fast local NVMe, where the throughput ceiling is high enough to absorb both live ingestion and the merge activity ClickHouse does in the background. As data ages and cools, it moves down to larger, cheaper volumes. This gives us speed where it matters without paying top-tier storage prices for data that's rarely touched. Keeping the hottest data on instance-local disk also frees up the network storage throughput budget for the colder tiers.
The main tension here is durability. Local disk is fast but ephemeral, so tiered storage only works alongside solid replication (below).
Ingestion
We ingest into ClickHouse through Kafka rather than by writing to it directly. Every event already flows through Kafka elsewhere in PostHog, and routing ingestion through it gives us resilience. Kafka absorbs sudden spikes and rides out brief periods of ClickHouse unavailability without dropping data, and we can pause or resume ingestion cleanly. ClickHouse consumes from Kafka and materializes the data into its storage tables. The data ingestion page covers the mechanics of this in detail.
Reliability
Data is replicated across multiple copies so that losing a node doesn't lose data or take a workload offline. Because ingestion is decoupled through Kafka, recent data has a durable source of truth we can replay from rather than depending on ClickHouse alone.
We run the US and EU as independent, mirrored deployments. Each region is fully self-contained for data residency, and the same architectural patterns apply in both. That also means improvements we make to one region's operations transfer directly to the other.
The trade-offs that shape the design
Several ClickHouse characteristics drive the choices above, and they're worth understanding because they're where most of the interesting engineering lives.
Updates and deletes are expensive. ClickHouse is built to ingest and query immutable, append-heavy data, so mutating existing rows means rewriting large amounts of data on disk. That single fact ripples outward. It pushes us toward local-NVMe hardware that can sustain the I/O, toward schema patterns that model change as new rows rather than in-place edits, and toward batching operations like data deletions instead of doing them one at a time. The data storage and operations pages go deep on this.
Protecting shared clusters from any single query means imposing resource limits, but some legitimate queries are genuinely large. Reconciling those two needs, guardrails for the common case and headroom for the heavy case, is part of what pushes us toward workload isolation in the first place.
Upgrades are non-trivial. ClickHouse moves fast, and changes between versions can affect query results or syntax, so we hold development, CI, and production on matched versions and validate upgrades against our real query patterns before rolling them out. The payoff of staying current is a steady stream of performance and storage improvements from the ClickHouse project.
Why this is interesting to work on
Running ClickHouse at this scale is a continuous exercise in the fundamentals: isolating workloads so they don't interfere, presenting a simple query surface over data that's physically spread across a fleet, matching storage tiers to access patterns, and getting the most out of hardware by understanding exactly how the database uses disk, memory, and network. The architecture isn't static. As PostHog grows and adds products, the shape of the workload changes and the clusters evolve with it. If problems like these are interesting to you, the ClickHouse team is a good place to be. See our careers page.
Different options for ingesting data into MergeTree tables and trade-offs involved
How the Kafka table engine works
What are materialized views?
Examples of a full schema setup
Using INSERTs for ingestion
As any database system, ClickHouse allows using INSERTs to load data.
Each INSERT creates a new part in ClickHouse, which comes with a lot of overhead and, in a busy system, will lead to errors due to exceeding parts_to_throw MergeTree table setting (default 300).
ClickHouse provides a bunch of options to make INSERTs still work. For example:
These come with their own trade-offs, consistency problems, and require the ClickHouse cluster to always be accessible.
Why we ingest via Kafka tables
We instead rely on the Kafka table engine to handle ingestion into ClickHouse.
The benefits are:
Resiliency: Kafka handles sudden spikes in traffic and ClickHouse cluster unavailability gracefully
PostHog already uses Kafka throughout the app, making it a safe technical choice
It also has minimal overhead in terms of memory used and allows us to always temporarily stop ingestion by removing the tables in question.
How Kafka tables work
Kafka engine tables act as Kafka consumers in a given consumer group. Selecting from that table advances the consumer offsets.
A Kafka table on its own does nothing beyond allowing querying data from Kafka – it needs to be paired with other tables for ingestion to work.
Important note: Given Kafka engine tables operate like consumers, querying data from them moves the offsets for the consumer group forward. Doing this while ingesting data may cause data loss, and has been disallowed by default on the latest ClickHouse versions.
It is important to send correctly formatted messages to the topic you're selecting from. When selecting from a Kafka table, ClickHouse assumes messages in the topic are formatted correctly. If not, this may stall the consumer depending on the value of kafka_skip_broken_messages, breaking ingestion.
Beyond just skipping broken messages, it's also possible to set up a dead letter queue system for these in ClickHouse. You can read more about doing so in this Altinity blog post.
Materialized views
Materialized views in ClickHouse can be thought of as triggers – they react to new blocks being INSERTed into source tables and allow transforming and piping that data to other tables.
Materialized views come with a lot of gotchas. A great resource for learning more about them is this presentation.
Example schema – reading and writing ingestion events
Consider the following sharded table schema together with kafka_ingestion_warnings:
CREATE TABLE sharded_ingestion_warnings
(
team_id Int64,
source LowCardinality(VARCHAR),
type VARCHAR,
details VARCHAR CODEC(ZSTD(3)),
timestamp DateTime64(6, 'UTC'),
_timestamp DateTime,
_offset UInt64,
_partition UInt64
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/posthog.sharded_ingestion_warnings', '{replica}')
PARTITION BY toYYYYMMDD(timestamp)
ORDER BY (team_id, toHour(timestamp), type, source, timestamp)
CREATE TABLE ingestion_warnings ON CLUSTER 'posthog'
(
team_id Int64,
source LowCardinality(VARCHAR),
type VARCHAR,
details VARCHAR CODEC(ZSTD(3)),
timestamp DateTime64(6, 'UTC'),
_timestamp DateTime,
_offset UInt64,
_partition UInt64
)
ENGINE = Distributed('posthog', 'posthog', 'sharded_ingestion_warnings', rand())
CREATE MATERIALIZED VIEW ingestion_warnings_mv
TO posthog.ingestion_warnings
AS SELECT
team_id,
source,
type,
details,
timestamp,
_timestamp,
_offset,
_partition
FROM posthog.kafka_ingestion_warnings
In this schema:
sharded_ingestion_warnings MergeTree is responsible for storing the ingested data
ingestion_warnings table is responsible for fielding queries and distributing writes to sharded_ingestion_warnings tables across shards
ingestion_warnings_mv regularly polls kafka_ingestion_warnings and pushes the data to ingestion_warnings distributed table
Note: it also forwards _timestamp, _offset, and _partition virtual columns containing Kafka message metadata so they can be stored and used during debugging.
Example schema visualized
This is the same schema visualized in a ClickHouse cluster with 2 shards and 1 replica each:
Data for this table would be stored in parts, each part a separate directory on disk. Data for a given part is always sorted by the order set in ORDER BY statement and compressed.
Parts can be Wide or Compact depending on its size. We'll be mostly dealing with Wide parts as part of day-to-day operations.
Wide parts are large and store each column in a separate binary data file, which are sorted and compressed.
ClickHouse also stores a sparse index for the part. A collection of rows with size equal to the index_granularity setting is called a granule. For every granule, the primary index stores a mark containing the value of the ORDER BY statement as well as a pointer to where that mark is located in each data file.
💡 For better performance when running queries, it is not recommended to set index_granularity too low. The default value for engines in the MergeTree family is 8192. An implication of this is that accessing data by primary key (in this case the ORDER BY clause is equivalent to the primary key) will not read just one row, but rather up to index_granularity number of rows. This is acceptable given ClickHouse is meant to perform well with aggregations, rather than point lookups.
<details><summary>Diving deeper into data-on-disk for a Wide part</summary>
This assumes you're using a docker-based ClickHouse installation and have clickhouse-client running
Seeding data
INSERT INTO sensor_values
SELECT *
FROM generateRandom('timestamp DateTime, site_id UInt8, event VARCHAR, uuid UUID, metric_value Int32', NULL, 10)
LIMIT 200000000
Looking at part data
system.parts table contains a lot of metadata about every part.
To find out what type each part is, its size, and where on disk it's located, you can run the following query:
SELECT
name,
part_type,
rows,
marks,
formatReadableSize(bytes_on_disk),
formatReadableSize(data_compressed_bytes),
formatReadableSize(data_uncompressed_bytes),
formatReadableSize(marks_bytes),
path
FROM system.parts
WHERE active and table = 'sensor_values'
FORMAT Vertical
⟩ docker exec -it posthog_clickhouse_1 ls -lhS /var/lib/clickhouse/store/267/267cd730-33ca-4e43-8a84-e4f0786e364b/all_12_17_1/
total 477M
-rw-r----- 1 clickhouse clickhouse 308M Nov 2 07:33 event.bin
-rw-r----- 1 clickhouse clickhouse 97M Nov 2 07:33 uuid.bin
-rw-r----- 1 clickhouse clickhouse 25M Nov 2 07:33 metric_value.bin
-rw-r----- 1 clickhouse clickhouse 25M Nov 2 07:33 timestamp.bin
-rw-r----- 1 clickhouse clickhouse 25M Nov 2 07:33 site_id.bin
-rw-r----- 1 clickhouse clickhouse 58K Nov 2 07:33 primary.idx
-rw-r----- 1 clickhouse clickhouse 19K Nov 2 07:33 event.mrk2
-rw-r----- 1 clickhouse clickhouse 19K Nov 2 07:33 metric_value.mrk2
-rw-r----- 1 clickhouse clickhouse 19K Nov 2 07:33 site_id.mrk2
-rw-r----- 1 clickhouse clickhouse 19K Nov 2 07:33 timestamp.mrk2
-rw-r----- 1 clickhouse clickhouse 19K Nov 2 07:33 uuid.mrk2
-rw-r----- 1 clickhouse clickhouse 494 Nov 2 07:33 checksums.txt
-rw-r----- 1 clickhouse clickhouse 123 Nov 2 07:33 columns.txt
-rw-r----- 1 clickhouse clickhouse 10 Nov 2 07:33 default_compression_codec.txt
-rw-r----- 1 clickhouse clickhouse 7 Nov 2 07:33 count.txt
What are these files?
For every column, there's a {column_name}.bin file, containing the compressed (LZ4 compression by default) data for that column. These take up most of the space.
For every column, there's a {column_name}.mrk2 file, contains an index with data to locate each granule in {column_name}.bin file
primary.idx contains information on ORDER BY column values for each granule. This is loaded into memory during queries.
checksums.txt, columns.txt, default_compression_codec.txt and count.txt contain metadata about this part.
In every system, data must be ingested and kept up-to-date somehow. When data is inserted into MergeTree tables, each insert creates one or multiple parts for the data inserted.
As having a lot of small files would be disadvantageous for many reasons from query performance to storage, ClickHouse regularly merges small parts together until they reach a maximum size.
The merge combines the two parts into a new one. This is similar to how merge sort works and atomically replaces the two source parts.
Our sensor_values table is set up in a way that queries similar to the following are really fast to execute.
SELECT
toStartOfDay(timestamp),
event,
sum(metric_value) as total_metric_value
FROM sensor_values
WHERE site_id = 233 AND timestamp > '2010-01-01' and timestamp < '2023-01-01'
GROUP BY toStartOfDay(timestamp), event
ORDER BY total_metric_value DESC
LIMIT 20
Executing this reports:
20 rows in set. Elapsed: 0.042 sec. Processed 90.11 thousand rows, 3.54 MB (2.13 million rows/s., 83.60 MB/s.)
Why can it be fast? Because ClickHouse:
leverages the table ORDER BY clause (ORDER BY (site_id, toStartOfDay(timestamp), event, uuid)) to skip reading a lot of data
is fast and efficient about I/O and aggregation
Let's dig into how the primary index for this query is used by using EXPLAIN.
EXPLAIN indexes=1, header=1 SELECT
toStartOfDay(timestamp),
event,
sum(metric_value) as total_metric_value
FROM sensor_values
WHERE site_id = 233 AND timestamp > '2010-01-01' and timestamp < '2023-01-01'
GROUP BY toStartOfDay(timestamp), event
ORDER BY total_metric_value DESC
LIMIT 20
FORMAT LineAsString
<details><summary>Show full EXPLAIN output</summary>
The full output of explain is obtuse, but the most important part is also the most deeply nested one:
ReadFromMergeTree
Header: and(greater(timestamp, '2010-01-01'), less(timestamp, '2023-01-01')) UInt8
timestamp DateTime
site_id UInt32
event String
metric_value Int32
Indexes:
PrimaryKey
Keys:
site_id
toStartOfDay(timestamp)
Condition: and(and((toStartOfDay(timestamp) in (-Inf, 1672531200]), (toStartOfDay(timestamp) in [1262304000, +Inf))), and((site_id in [233, 233]), and((toStartOfDay(timestamp) in (-Inf, 1672531200]), (toStartOfDay(timestamp) in [1262304000, +Inf)))))
Parts: 2/2
Granules: 11/24415
At the start of the query, ClickHouse loaded the primary index of each part into memory. From this output, we know that the query first used the primary key to filter based on site_id and timestamp values stored in the index. This allowed it to know that only 11 out of 24415 granules (0.05%) contained any relevant data.
From there it read those 11 granules (11 * 8192 rows) worth of data from timestamp, side_id, event and metric_value columns and did the rest of filtering and aggregation on that data alone.
SELECT * FROM sensor_values WHERE uuid = '69028f26-768f-afef-1816-521b22d281ca'
Executing this query reports:
1 row in set. Elapsed: 0.703 sec. Processed 200.00 million rows, 3.20 GB (304.43 million rows/s., 4.87 GB/s.)
While the overall execution time of this query is not bad thanks to fast I/O, it needed to read 2200x the amount of data from disk. As the dataset size or column sizes increase, this performance would get dramatically worse.
Why is this query slower? Because our ORDER BY does not support fast filtering by uuid and ClickHouse needs to read the whole table to find a single record _and_ read all columns.
ClickHouse provides some ways to make this faster (e.g. Projections) but in general these require extra disk space or have other trade-offs.
Thus, it's important to make sure the ClickHouse schema is aligned with queries that are being executed.
PARTITION BY
Another tool to make queries faster is PARTITION BY. Consider the updated table definition:
Here, ClickHouse would generate one partition per 10 years of data, allowing to skip reading even the primary index in some cases.
In the underlying data, each part would belong to a single partition and only parts within a partition would get merged.
One additional benefit of partitioning by a derivate of timestamp is that if most queries touch recent data, you can also set up rules to automatically move older parts and partitions to cheaper storage or drop them entirely.
Query analysis
Let's use an identical query as before to explain with the new dataset:
SELECT
toStartOfDay(timestamp),
event,
sum(metric_value) as total_metric_value
FROM sensor_values
WHERE site_id = 233 AND timestamp > '2010-01-01' and timestamp < '2023-01-01'
GROUP BY toStartOfDay(timestamp), event
ORDER BY total_metric_value DESC
LIMIT 20
<details><summary>Show full EXPLAIN output</summary>
Expression (Projection)
Header: toStartOfDay(timestamp) DateTime
event String
total_metric_value Int64
Limit (preliminary LIMIT (without OFFSET))
Header: toStartOfDay(timestamp) DateTime
event String
sum(metric_value) Int64
Sorting (Sorting for ORDER BY)
Header: toStartOfDay(timestamp) DateTime
event String
sum(metric_value) Int64
Expression (Before ORDER BY)
Header: toStartOfDay(timestamp) DateTime
event String
sum(metric_value) Int64
Aggregating
Header: toStartOfDay(timestamp) DateTime
event String
sum(metric_value) Int64
Expression (Before GROUP BY)
Header: event String
metric_value Int32
toStartOfDay(timestamp) DateTime
Filter (WHERE)
Header: timestamp DateTime
event String
metric_value Int32
SettingQuotaAndLimits (Set limits and quota after reading from storage)
Header: and(greater(timestamp, '2010-01-01'), less(timestamp, '2023-01-01')) UInt8
timestamp DateTime
site_id UInt32
event String
metric_value Int32
ReadFromMergeTree
Header: and(greater(timestamp, '2010-01-01'), less(timestamp, '2023-01-01')) UInt8
timestamp DateTime
site_id UInt32
event String
metric_value Int32
Indexes:
MinMax
Keys:
timestamp
Condition: and(and((timestamp in (-Inf, 1672531199]), (timestamp in [1262304001, +Inf))), and((timestamp in (-Inf, 1672531199]), (timestamp in [1262304001, +Inf))))
Parts: 2/14
Granules: 3589/24421
Partition
Keys:
intDiv(toYear(timestamp), 10)
Condition: and(and((intDiv(toYear(timestamp), 10) in (-Inf, 202]), (intDiv(toYear(timestamp), 10) in [201, +Inf))), and((intDiv(toYear(timestamp), 10) in (-Inf, 202]), (intDiv(toYear(timestamp), 10) in [201, +Inf))))
Parts: 2/2
Granules: 3589/3589
PrimaryKey
Keys:
site_id
toStartOfDay(timestamp)
Condition: and(and((toStartOfDay(timestamp) in (-Inf, 1672531200]), (toStartOfDay(timestamp) in [1262304000, +Inf))), and((site_id in [233, 233]), and((toStartOfDay(timestamp) in (-Inf, 1672531200]), (toStartOfDay(timestamp) in [1262304000, +Inf)))))
Parts: 2/2
Granules: 12/3589
The relevant part of EXPLAIN is again nested deep within:
ReadFromMergeTree
Header: and(greater(timestamp, '2010-01-01'), less(timestamp, '2023-01-01')) UInt8
timestamp DateTime
site_id UInt32
event String
metric_value Int32
Indexes:
MinMax
Keys:
timestamp
Condition: and(and((timestamp in (-Inf, 1672531199]), (timestamp in [1262304001, +Inf))), and((timestamp in (-Inf, 1672531199]), (timestamp in [1262304001, +Inf))))
Parts: 2/14
Granules: 3589/24421
Partition
Keys:
intDiv(toYear(timestamp), 10)
Condition: and(and((intDiv(toYear(timestamp), 10) in (-Inf, 202]), (intDiv(toYear(timestamp), 10) in [201, +Inf))), and((intDiv(toYear(timestamp), 10) in (-Inf, 202]), (intDiv(toYear(timestamp), 10) in [201, +Inf))))
Parts: 2/2
Granules: 3589/3589
PrimaryKey
Keys:
site_id
toStartOfDay(timestamp)
Condition: and(and((toStartOfDay(timestamp) in (-Inf, 1672531200]), (toStartOfDay(timestamp) in [1262304000, +Inf))), and((site_id in [233, 233]), and((toStartOfDay(timestamp) in (-Inf, 1672531200]), (toStartOfDay(timestamp) in [1262304000, +Inf)))))
Parts: 2/2
Granules: 12/3589
What this tells us is that ClickHouse:
First leverages an internal MinMax index on timestamp to whittle down the number of parts to 2/14 and granules to 3589/24421
Then it tries to filter via the partition key but this doesn't narrow things down further
Then, it loads and leverages the Primary key as before to narrow data down to 12 granules.
Lastly reads, filters and aggregates data in those 12 granules
The benefit here is that it could skip reading the primary key index for most of the parts that did not contain relevant data. If and how much this speeds up the query however depends on the size of the dataset.
Choosing a good PARTITION BY
Use partitions wisely - each INSERT should ideally only touch 1-2 partitions and too many partitions will cause issues around replication or prove useless for filtering.
Loading the primary index/marks file might not be the bottleneck you expect, so be sure to benchmark different schemas against each other.
See the following Altinity documentation for more guidance:
Updating data in ClickHouse is expensive and analogous to a schema migration.
For example, to update an event's properties, ClickHouse frequently needs to:
Scan all the data to find what parts contain the relevant data. This isn't often covered by ORDER BY and thus quite expensive.
Rewrite the _whole_ part (including any columns) - this could be potentially up to 150GB of data rewritten for a single update.
This makes things operationally hard. We mitigate this by:
Writing duplicated rows for new data, using other table engines (e.g. ReplacingMergeTree) and accounting for this duplication in our queries.
Batching up GDPR or other data deletions and doing them on a schedule rather than immediately.
No query planner
ClickHouse doesn't have a query planner in the sense PostgreSQL or other databases do.
On the one hand, you often end up fighting the query planner in other databases. If we know how ClickHouse works internally and can develop that into intuition for how SQL is executed, we're well-equipped to deal with performance issues as they arise.
On the other, this means that we'll need to be careful writing SQL as small changes can have huge performance implications.
Examples:
For best performance, ClickHouse requires you "push" predicates in WHERE clauses into sub-queries rather than filtering at the outermost query.
In the sensor_values queries above, the execution plan would have been _slightly_ more optimal if the filter condition on toYear(timestamp) rather than timestamp.
One notable exception to "no query planner" is that ClickHouse often pushes predicates from WHERE into PREWHERE. Filters in PREWHERE are executed first and ClickHouse moves columns it thinks are "cheaper" or "more selective" into it. However putting the wrong column (e.g. a fat column containing JSON) in PREWHERE can cause performance to tank.
Compression means that if subsequent column values of a given column are often similar or identical, the data compresses really well. At PostHog we frequently see uncompressed / compressed ratios of 20x-40x for JSON columns and 300x-2000x for sparse small columns.
Compression ratios have direct impact on query performance: I/O is often the bottleneck, meaning that highly compressed data can be read faster from disk at the cost of more CPU work for decompression.
By default columns are compressed by the LZ4 algorithm. We've found good success using ZSTD(3) for storing JSON columns - see benchmarks for more information.
Another tip is to use ClickHouse's LowCardinality data type modifier on schemas where a given column will store values with low cardinality i.e. the total number of values is low. An example of this would be "country name".
Weak JOIN support
ClickHouse excels at aggregating data from a single table at a time. If you however have a query with JOINs or subqueries, the right-hand-side of the JOIN would be loaded into memory first. Thus, you should always have the bigger table on the left side of left-hand-side!
This means that at scale JOINs can kill performance. Read more on the effect of removing JOINs from our events database here:
We don't use ClickHouse dictionaries very often, and there are a few aspects to them that have caused headaches in production.
Using a ClickHouse table as a source
If you don't provide a PASSWORD when creating a dictionary, you will likely get errors like this with calling getDictOrNull:
Code: 516. DB::Exception: default: Authentication failed: password is incorrect, or there is no user with such name. If
you have installed ClickHouse and forgot password you can reset it in the configuration file. The password for default
user is typically located at /etc/clickhouse-server/users.d/default-password.xml and deleting this file will reset the
password. See also /etc/clickhouse-server/users.xml on the server where ClickHouse is installed. : while executing '...'
You could provide one in the DDL, but the problem with this is that if the password is ever rotated, you will need to re-run the migration, or you'll start getting auth errors again.
Here's an example of providing this section in the DDL:
CREATE DICTIONARY posthog.my_dict
(
`a` String,
`b` String,
`c` Nullable(String),
`d` Nullable(String),
`e` Nullable(String)
)
PRIMARY KEY a, b
SOURCE(CLICKHOUSE(TABLE 'my_table' PASSWORD 'hunter42'))
LIFETIME(MIN 3000 MAX 3600)
LAYOUT(COMPLEX_KEY_HASHED())
PostHog uses ClickHouse to power our data analytics tooling and we've learned a lot about it over the years. The goal of this manual is to share that knowledge externally and raise the average level of ClickHouse understanding for people starting work with ClickHouse.
If you have extensive ClickHouse experience, and want to contribute thoughts or tips of your own, please do by opening an PR or issue on GitHub!
Consider this manual a companion to other great resources out there:
In 2020, we had launched PostHog for the first time, were getting great early traction, but were struggling with scaling.
To solve this problem we looked at a wide range of OLAP solutions, including Pinot, Presto, Druid, TimescaleDB, CitusDB, and ClickHouse. Some of our team had used these tools before at other companies, such as Uber where Pinot and Presto are both used extensively.
While assessing each tool, we looked at three main factors:
_Speed:_ Our users want results in real-time, so our new database needed to scale well and give fast results. Ideally, it wouldn’t be too expensive either.
_Complexity:_ PostHog users can self-host and install our product themselves, so we didn’t want it to be too complicated for users to manage or deploy. We didn’t want users to have to install an entire Hadoop stack, for example.
_Query interface:_ We like standardized tools. We eliminated tools such as Druid because, while it does have a SQL wrapper around it, it’s not _exactly_ SQL. That can get messy.
ClickHouse was a good fit for all of these factors, so we started doing a more thorough investigation. We read up on benchmarks and researched the experience of companies such as Cloudflare that uses ClickHouse to process 6m requests per second. Eventually, we set up a test cluster to run our own benchmarks.
ClickHouse repeatedly performed an order of magnitude better than other tools we considered. We also discovered other perks, such as the fact that it is column-oriented and written in C++. We found these to be the key benefits of ClickHouse:
_Compression:_ ClickHouse has _excellent_ compression and the size-on-disk was incredible. ClickHouse even beat out serialization formats such as ORC and Parquet.
_Process from disk:_ Some OLAP solutions, like Presto, require data to live in memory. That’s fast, but you need to have a _lot_ of memory for big datasets. ClickHouse processes from disk, which is better for smaller instances too.
_Real-time data updates:_ ClickHouse processes data as it arrives, so there’s no need to pre-aggregate data. It’s faster for us, and our users.
Eventually, we decided we knew enough to proceed and so we spun our test cluster out into an actual production cluster. It’s just part of how we like to bias for speed.
Now, ClickHouse powers all of our analytics features and we're happy with the path taken.
However knowledge on how to build on it and maintain it is more important than ever, bringing us to this manual.
This document gives an overview of the kitchen side of ClickHouse: how various operations work, what tricky migrations we have experience with as well as various settings and tips.
System tables
ClickHouse exposes a lot of information about its internals in system tables.
ClickHouse provides daunting amounts of configuration on all levels. This section provides information on the different kind of settings and how to configure them.
Query settings
Query settings allow to manipulate the behavior of queries, for example setting limits on query execution time and resource usage or toggling specific behaviors on-and-off.
ClickHouse allows creating different profiles and users with their own set of settings. This can be useful to grant read-only access to some users or otherwise limit resource use.
While not currently the case, all PostHog products and features that query ClickHouse _should_ use a specific ClickHouse user for the use case. We have a bunch of product-specific ClickHouse users that are specified when running a query with the ClickHouse client. For example, see this.
When developing a new product or feature, using a dedicated ClickHouse user is important for multiple reasons:
we need to be able to monitor different workloads and see what queries are potentially hurting our ClickHouse clusters
we should be able to set appropriate resource constraints for different products and avoid hurting other products' performance by cheekily using a random user that already exists
we should be able to scope privileges on the ClickHouse user to what it really needs, limiting the blast radius of a compromised credential
Mutations
ALTER TABLE ... UPDATE and ALTER TABLE ... DELETE operations which mutate data require ClickHouse to rewrite whole data via special merge operations. These are frequently expensive operations and require monitoring.
You can monitor progress of mutations via the following system tables:
As explained previously, merges are the lifeblood of ClickHouse, responsible for optimizing how data is laid out on disk as well as for deduplicating data.
Note: not all parts are guaranteed to be merged if the size of parts exceeds maximum limits or if data is already in a single part. In this case adding a FINAL modifier forces the merge regardless.
SYSTEM STOP MERGES
SYSTEM STOP MERGES statement can stop background merges from occurring temporarily for a table or the whole database. This can be useful during trickier schema migrations when copying data.
Note unless ingestion is paused during this time, this can easily lead to too many parts errors.
server settings control how many merges are executed in parallel
Undocumented max_replicated_mutations_in_queue and max_replicated_merges_in_queue settings control how many merges are processed at once
Simple schema changes
As in any other database, schema changes are done via ALTER TABLE statements.
One area where ClickHouse differs from other databases is that schema changes are generally lazy and apply to only new data or merged parts. This applies to:
Adding or removing columns, changing default values
Changing compression of columns
Updating table settings
You can generally force these changes onto old data by forcing data to be merged via OPTIMIZE TABLE FINAL statement, but this can be expensive.
TTLs
ClickHouse TTLs allow dropping old rows or columns after expiry.
It's suggested to set up your table to partition by timestamp as well, so old files can be dropped completely instead of needing to be rewritten as a result of TTL.
Tricky schema changes
Some schema changes are deceptively hard and frequently requires rewriting the whole table or re-creating the tables.
Make sure to never re-use Zookeeper paths when re-creating replicated table!
At PostHog, we've developed Async Migrations for executing these long-running operations in the background without affecting availability.
You can learn more about Async Migrations in our blog, handbook, and runbook.
Pausing ingestion
This is frequently a prerequisite of any large-scale schema change as new data may get lost when you are copying data from one place to another.
If you're using Kafka engine tables for ingestion, you can pause ingestion by dropping materialized view(s) attached to Kafka engine tables.
To restart ingestion, recreate the dropped table(s).
Note that you can also detach the materialized views instead of dropping them (DETACH TABLE my_mv), but be aware that detached views have some weird behaviors, such as being re-attached on node restarts, "existing in a limbo" (they do not show up on system.tables and cannot be dropped but SHOW CREATE TABLE my_mv will return results), as well as potentially causing naming clashes.
Changing table engines
When changing table engines, you can leverage ATTACH PARTITION commands to move data between tables.
Note: ATTACH PARTITION commands only work if the two tables have identical structure: same columns and ORDER BY/PARTITION BY. It works by creating hard links between partitions, so the operation does not require any extra disk space until merges happen.
Thus it's important to stop ingesting new data and merges during this operation.
PostHog needed to implement this kind of operation to move to a sharded schema: 0004_replicated_schema.py.
Changing ORDER BY or PARTITION BY
Changing ORDER BY and PARTITION BY affects how data is stored on disk and requires rewriting this data.
In the case of ORDER BY, you can modify it with ALTER TABLE my_table MODIFY ORDER BY, but only to add a new column expression. Other changes require using the approaches below.
Suggested procedure if using ReplacingMergeTree:
Create a new table with correct ORDER BY
Create a new materialized view table, writing new data to new table.
At PostHog, we've haven't had to reshard data (yet), but the process would look similar to changing ORDER BY or PARTITION BY, requiring either to pause data or deduplicate at the end.
Storing/restoring parts of data from backups might also simplify this process.
Denormalizing columns via dictionaries
A powerful tool in the arsenal of performance is de-normalization of data.
At PostHog, we eliminated some JOINs for person data by storing information on person identities and properties directly on events.
Backfilling this data was implemented via ALTER TABLE UPDATE populating new columns. The column data was pulled in using dictionaries which allowed to query and store data from other tables in memory during the update.
An alternative approach might have been to create a new table and populate it similar to changing ORDER BY, but this would have required expensive deduplication, a lot of extra space and even more memory usage.
If you ever DETACH a materialized view, it's important to keep in mind that the view now exists in a "limbo" state that can be confusing and cause issues.
Detached views don't show up on system.tables, but you can assert that a view exists by running SHOW CREATE TABLE <detached_mv>.
In addition, detached views (except if DETACH was executed with PERMANENTLY) will be reattached on server restarts!
As an example of how this has been problematic for us in the past, we once detached views to handle ingestion problems, and then on rebooting the nodes we got confused as to why ingestion hadn't stopped!
Orphan Zookeeper records
Prior to ClickHouse 22.3, bugs in ClickHouse meant that reasonably often Zookeeper would end up with "orphan records". These are references to things like parts in ClickHouse that no longer exist, but remain referenced. While orphan records were common prior to 22.3, it's still possible that such records come to exist on newer ClickHouse versions as well, as an expected consequence of distributed systems.
Orphan records pose a problem because they may cause ClickHouse to use resources and try to perform operations on e.g. non-existent parts. For instance, we've seen mutations hang for months due to ClickHouse expecting it still needs to modify a part but the part no longer existing.
As a result, it's important to clean these up.
Orphan parts
Orphaned parts are perhaps the most common type of orphan record, so much so that Altinity has written a guide to help identify and delete them, as well as they recommended everyone do so when upgrading past 22.3.
To do this cleanup properly, you should:
Check if you have any orphan parts (this should be run per node in your cluster, or you could modify the query to use clusterAllReplicas):
select zoo.p_path as part_zoo, zoo.ctime, zoo.mtime, disk.p_path as part_disk
from
(
select concat(path,'/',name) as p_path, ctime, mtime
from system.zookeeper where path in (select concat(replica_path,'/parts') from system.replicas)
) zoo
left join
(
select concat(replica_path,'/parts/',name) as p_path
from system.parts inner join system.replicas using (database, table)
) disk on zoo.p_path = disk.p_path
where part_disk=''
order by part_zoo
Generate delete statements for each record that needs to be removed from Zookeeper:
clickhouse-client --password <password> --query "select 'delete '||part_zoo
from (
select zoo.p_path as part_zoo, zoo.ctime, zoo.mtime, disk.p_path as part_disk
from
(
select concat(path,'/',name) as p_path, ctime, mtime
from system.zookeeper where path in (select concat(replica_path,'/parts') from system.replicas)
) zoo
left join
(
select concat(replica_path,'/parts/',name) as p_path
from system.parts inner join system.replicas using (database, table)
) disk on zoo.p_path = disk.p_path
where part_disk='' and zoo.mtime <= now() - interval 30 day
order by part_zoo) format TSVRaw" > tmp_zk_orphans
SSH into _one_ of your Zookeeper nodes
Start up the ZK CLI (zkCli.sh) and paste the delete statements
Check that the query from step 1 no longer returns anything
Orphan replication queue records
A more confusing issue can also happen when the replication queue contains operations that reference inexistent parts.
This is harder to notice proactively but may manifest itself in a migration that hangs indefinitely because it still has parts it needs to operate on but those parts don't exist.
If you spot a migration that doesn't seem to be progressing after a long time, it's worth checking if the parts in the parts_to_do column of the system.mutations table contains any parts that don't exist.
You can also spot this by looking at the replication queue for long-running operations. You could run the following query, for example:
select * from clusterAllReplicas('<cluster_name>', system.replication_queue) order by create_time
And check if any operations were created a long time ago, particularly simple ones like GET_PART.
Finally, another symptom you can look out for are recurrent logs that look like the following:
Checking part 137_0_27780_19674
Checking if anyone has a part 137_0_27780_19674 or covering part.
If the server has been looking for a part for days and hasn't found it anywhere, there's probably something wrong.
Having established this problem, the way to fix it is as follows:
Get the node_name of the hanging queue record
SSH into a Zookeeper node and using ZK CLI, delete the record. Note that for this you will need the full Zookeeper path of the record. You can use ls within the Zookeeper CLI to understand the storage structure if necessary. The path should look something like this: /clickhouse/tables/<shard_number>/<database_name>.<table_name>/replicas/<replica_name>/queue/<node_name> but will also vary for replicated and non-replicated tables.
Having deleted the record, you should run SYSTEM RESTART REPLICA <table_name> on the ClickHouse node with the orphan queue item. This command will fetch the updated metadata from Zookeeper. It's also worth running it across your cluster for good measure.
Learn more
More information for ClickHouse operations can be found in:
What tools are available to understand and measure query performance
Importance of page cache
General tips and tricks for performant queries
Tooling
clickhouse-client
clickhouse-client is a command-line application for running queries against ClickHouse.
When executing queries, it details progress, execution time, how many rows and gigabytes of data were processed, and how much CPU was used.
Image: clickhouse-client progress reporting
You can get additional logging from ClickHouse by setting SET send_logs_level = 'trace' before running a query.
system.query_log
ClickHouse saves all queries it runs into system.query_log table.
It includes information on:
What query was run and when
How long did it take to execute
How many resources did it take up: memory, rows/bytes read
In case of errors, exception information
Some tips for querying the query_log:
For distributed queries, filter by is_initial_query to disambiguate distributed queries i.e. is_initial_query = 1 denotes the query sent to the coordinator node, whereas is_initial_query = 0 denotes internally-generated queries sent to gather data from other shards
Use clusterAllReplicas('<cluster_name>', system.query_log) to query all nodes
Filter on type = 'QueryFinish' if you only want data on queries that completed successfully. Forgetting to do so can skew averages since the results will include QueryStart events, which have columns such as query_duration_ms set to 0.
ProfileEvents column contains a lot of useful performance data on each query, not all of which is documented. Check the source for a full list all measurements.
At PostHog, we also add metadata to each query via the log_comment setting to make results easier to analyze. This includes information on the source of the query and how it was constructed. See this runbook for more details.
An example query to get recent slow queries:
SELECT
query_duration_ms,
query,
event_time,
read_rows,
formatReadableSize(read_bytes) as read_size,
result_rows,
formatReadableSize(result_bytes) as result_size,
formatReadableSize(memory_usage) as memory,
columns,
query_id
FROM system.query_log
WHERE
query NOT LIKE '%query_log%'
AND type = 'QueryFinish'
AND event_time > now() - toIntervalDay(3)
AND query_duration_ms > 30000
/* If using log_comment, consider including something like:
AND JSONExtract(log_comment, 'kind') = 'request'
*/
ORDER BY query_duration_ms desc
LIMIT 10
Note that this table is not distributed - on a cluster setting you might need to run query against each node separately or do ad-hoc distributed queries.
EXPLAIN
Previous pages in this manual showed various examples of using the ClickHouse EXPLAIN statement to your advantage.
Various forms of explain can detail:
If and how much data ClickHouse was able to avoid processing thanks to schema setup
If and how ClickHouse "optimizes" the query by moving columns to PREWHERE
We've built flamegraph support into PostHog. You can find tools to generate flamegraphs for queries under PostHog instance settings.
Importance of the page cache
When running queries, you might encounter an odd artifact: the first time you run a query, it's really slow but it speeds up significantly when run again.
This behavior is due to the Linux page cache. In broad terms, the operating system caches recently read files into memory, speeding up subsequent reads of the same data.
As most queries in ClickHouse are dependent on fast I/O to execute fast, this can have a significant effect on query performance. It is a reason why at PostHog our ClickHouse nodes have a lot of memory available.
Effect on benchmarking
This behavior can be a problem for profiling: users constructing new queries might not hit the page cache and receive a worse experience than benchmarking may show.
This means it's often important to wipe page cache on ClickHouse when doing queries. This can be achieved with the following command on a ClickHouse node:
sudo sh -c "/usr/bin/echo 3 > /proc/sys/vm/drop_caches"
Note that the above will only drop the cache on the given node, but distributed queries might still be affected from the page cache on nodes in the other shards.
When set to a value greater than 0, ClickHouse will use O_DIRECT for disk reads whenever the total data to be read exceeds the threshold (in bytes).
SETTINGS min_bytes_to_use_direct_io = 1;
Join algorithms
JOINs are expensive in ClickHouse, so any opportunities to speed them up are welcome.
One of the quickest possible wins on that front is by benchmarking different join algorithms.
Newer ClickHouse versions have added more algorithms, and it's worth keeping an eye on the ones that come out and check if they help improve query performance.
In PostHog's case, we have moved away from the default algorithm (alias for direct,hash) in favor of direct,parallel_hash. parallel_hash is effectively the same as hash, but it does the computation in multiple buckets. It aims to be faster by consuming a bit more resources.
In our extensive benchmarking (including in our production environment), we've found that across the board using parallel_hash over hash provided us with the following speed improvements:
Average: parallel_hash was 1.23x faster
p95: parallel_hash was 1.49x faster
p99: parallel_hash was 1.37x faster
This came at a cost of up to 1.5x more memory usage, as well as a bit more CPU usage, which were acceptable tradeoffs in our case.
Benchmark different join algorithms on queries that use JOINs. From our testing, parallel_hash can help speed up most types of queries with JOINs at the expense of a bit more memory and CPU usage. grace_hash is also a promising new algorithm introduced in ClickHouse 22.12.
Also always do your benchmarking in a realistic setting: on large datasets on powerful machines.
A guideline for making the ClickHouse queries attribute correctly.
Current state
We don't fully understand why our ClickHouse get sometimes overloaded. We extensively use query's SETTING: log_comment to put JSON with bunch of metadata inside it.
A bit more background
We process thousands queries per second, historically it used to be mostly the traffic from our application us.posthog.com / eu.posthog.com and using only one default ClickHouse user. Recently, it has been a mix of different query issuers (Temporal, Celery, and services cut out from Django), with most of the queries still using default user.
We've managed to separate batch_export, app and api traffic to use separate ClickHouse users and tune the settings to not fully starve any of those use cases of capacity.
Most ClickHouse queries made as a result of HTTP request to Django app contains the proper http_request_id, route_id and id.
This allow us to do basic analysis.
Where we want to be
We want to know:
why was a query started,
what/who initiated the query,
how much resources it consumed.
This will allow us to better manage the ClickHouse load and understand which products and features require the most compute resources and how they are correlated. Especially, how one request to an API may end up multiple queries to ClickHouse.
Tags
In Python, there is a tag_queries helper function one may use, be aware that it tags all queries issued from within a Python thread (it uses thread local memory).
Alternatively, you may consider tags_context for localized tags.
Each query send to ClickHouse must have the following tags:
team_id: ?Int64 - team id,
user_id: ?Int64 - query run initiated by a user,
access_method: ?String - the only value we use is: personal_api_key,
product - NEW PostHog product name,
org_id - NEW organization id - we don't have it now, but it may make analyzing data a easier,
kind: ?String - detect kind of query, almost all queries have it, only 4 values seen: ["celery", "cohort_calculation", "batch_export", "request"],
id - it used to have a id of a workload (e.g. celery job name: posthog.tasks.calculate_cohort.calculate_cohort_ch, or exact path of request: /api/projects/2/insights/trend),
query: JSON - contains a query object that QueryRunner run, literally the whole query object.
route_id: ?String - route_id in api (e.g. api/projects/(?P<parent_lookup_team_id>[^/.]+)/insights/trend/?$),
workload: ?String - for now only: ONLINE / OFFLINE are used, it suppose to designate whether a query is part of ONLINE workload,
dashboard_id: ?Int64 - if query executes to render part of dashboard,
insight_id: ?Int64 - if query is run to show insight,
chargeable: ?byte - set to 1 for queries we intend to charge,
name: ?String - you can name your queries,
http_request_id: ?String - HTTP request that initiated a query, set only if is a proper UUID.
Types were reverse engineered from our ClickHouse system.query_log.log_comment column.
SELECT
arrayJoin(JSONExtractKeys(log_comment)) AS tag_key,
count() AS occurrences
FROM clusterAllReplicas(posthog, system.query_log)
WHERE
event_date = '2025-06-06'
AND is_initial_query
AND type = 'QueryStart'
AND log_comment != ''
GROUP BY tag_key
ORDER BY occurrences DESC;
Get tag type, number of occurrences and values
SELECT
{{tag_name}} AS tag_name,
JSONType(log_comment, {{tag_name}}) AS value_type,
count() AS occurrences,
count(distinct JSONExtractRaw(log_comment, {{tag_name}})) AS distinct_values,
groupUniqArray(20)(JSONExtractRaw(log_comment, {{tag_name}})) AS example_value -- Get an example
FROM clusterAllReplicas(posthog, system.query_log)
WHERE
event_date >= '2025-06-06'
AND is_initial_query
AND type = 'QueryStart'
AND JSONHas(log_comment, {{tag_name}})
GROUP BY value_type
ORDER BY occurrences DESC;
PostHog provides Apps for data imports, exports and transformation purposes.
App metrics helps users of apps want to know whether the apps are reliable and have tooling to debug errors.
When designing the schema, we needed ingestion of these stats to be as 'cheap' as possible. On the flip side, queries against the data did not need to support much beyond time-range filtering.
Decision: Store errors in the same table as metrics
Error tracking is fundamentally different from metrics, but we wanted to avoid "failure counts" and errors we have data on going out of sync.
For this reason, the two are stored in the same table, with error_details column containing JSON-encoded metadata about the error including the relevant event payload, stack trace.
This runs the risk of data storage increasing significantly if a lot of large errors occur.
For this reason error_details column uses ZSTD(3) codec.
Sorting by error_type also has a significance: error_details of a given error type should be similar and compress well.
In the future, we might introduce TTLs for the error columns if storage becomes a problem or periodically wipe error data in other ways.
Decision: pre-aggregate metrics in app in memory
Apps act on events as they're processed and users might have dozens of apps installed at the same time.
For this reason, emitting a Kafka message per app per event ingested ends up being too expensive. We instead aggregate metrics (and errors) in memory and only periodically flush data to Kafka.
This runs the trade-off of counts being subtly off after deploys or restarts. If this becomes a significant user concern, we may reduce the precision of the numbers shown in the UI.
Decision: using AggregatingMergeTree
To make ingesting and storing this data cheaper, AggregatingMergeTree is used.
Each time two parts are merged, rows with identical ORDER BY values are collapsed into a single row in the new part.
In this setup, this means that:
we aggregate data up to an hours granularity (since toStartOfHour(timestamp) is in the ORDER BY)
successes, successes_on_retry and failures columns get summed up for each unique value of ORDER BY
errors are not aggregated at all (since error_uuid is in the ORDER BY)
Even with all of this we still need to sum values in queries as merges may never occur.
Decision: sharding
To make data cheaper to store, this table is sharded.
Results
On US Cloud, the disk size of this table was 6 MB after aggregating nearly 2 billion metrics. For comparison, storage similar number of events can require hundreds of gigabytes.
Queries against this schema are also usually measured in milliseconds.
The reason we were able to leverage pre-aggregation to this extent was since we only needed to answer a few questions:
What is the number of successes and failures in a given time range per day or hour, diced by plugin, method and job?
How many errors of each type did we see in that time range?
What are some examples of specific errors we saw?
These queries all lend itself well to pre-aggregation, meaning an expert schema could store this data very cheaply at the cost of some flexibility.
When designing a schema for ClickHouse, there are dozens of large and small decisions engineers need to make to design a well-performing solution fit for the problem being solved.
The following documents outline various schemas we have at PostHog, examining why they are designed this way, what are some good parts about them, and mistakes that were made.
person_distinct_id table makes for an interesting case study on how initial schema design flaws were exposed over time and how they were fixed.
Problem being solved
PostHog needs to know who are the users associated with each event.
In frontend libraries like posthog-js, when persons land on a site they're initially anonymous with a random distinct ID. As persons log in or sign up, posthog.identify should be called to signal that the anonymous person is actually some logged in person and their prior events should be grouped together.
The semantics of this have changed significantly with person-on-events project.
The is_deleted column is not actually being written to, it is dynamically calculated based on the _sign column.
This table was queried often joined with events table along the following lines:
SELECT avg(count())
FROM events
INNER JOIN (
SELECT distinct_id, argMax(person_id, _timestamp) as person_id
FROM (
SELECT distinct_id, person_id, max(_timestamp) as _timestamp
FROM person_distinct_id
WHERE team_id = 2
GROUP BY person_id, distinct_id, team_id
HAVING max(is_deleted) = 0
)
GROUP BY distinct_id
) AS pdi ON (pdi.distinct_id = events.distinct_id)
WHERE team_id = 2
GROUP BY pdi.person_id
Design decision: no sharding
Since this table was almost always joined against the events table, this table was not sharded.
Sharding it means that each shard would need to send back all the events and person_distinct_id sub-query result rows to coordinator node to execute queries, which would be expensive and slow.
Design decision: CollapsingMergeTree
The given distinct_id belonging to a person can change over time as posthog.identify or posthog.alias are called.
For this reason the data needs to be constantly updated, yet updating data in ClickHouse requires rewriting large chunks of data.
Rather than rewriting data, we opted to use CollapsingMergeTree. CollapsingMergeTree adds special behavior to ClickHouse merge operation: if on a merge rows with identical ORDER BY values are seen, they are collapsed according to _sign column:
If sum of signs _sign was positive, new row has _sign of 1.
Otherwise, the row was removed.
This was used to update-via-insert:
On a change, the old person_id was discarded via emitting a row _sign of -1
On a change, the new person_id row was emitted with _sign of 1
At query-time, the resulting rows were aggregated together to find the current state of the world
Due to this logic, both person_id and distinct_id needed to be in the ORDER BY key.
Problem: CollapsingMergeTree for updates
CollapsingMergeTree is not ideal for frequently updating a single row as merges occur in an non-deterministic order and that will cause trouble if subsequent rows signifying deletes get discarded before being merged with an "insert" row.
When updating columns ReplacingMergeTree engine tables with an explicit version column has proven to be reliable.
SELECT avg(count())
FROM events
INNER JOIN (
SELECT distinct_id,
argMax(person_id, version) as person_id
FROM person_distinct_id2
WHERE team_id = 2
GROUP BY distinct_id
HAVING argMax(is_deleted, version) = 0
) AS pdi ON e.distinct_id = pdi.distinct_id
WHERE team_id = 2
GROUP BY pdi.person_id
This schema:
Was over 2x faster to query for large teams while requiring less memory
Had explicit versioning logic built in
Required fewer Kafka messages and traffic
Lowered index_granularity for faster point queries
Leveraged ReplacingMergeTree to ensure data consistency
Closing notes
Even with improvements JOINs still are expensive and after the person-on-events project we were able to store person_id column on the events table to great effect.
All analytics queries filter by timestamp and recent data is much more frequently accessed.
Partitioning this way allows us to skip reading a lot of parts and to move older data to cheaper (but older) storage.
Evaluation: 👍 Critical to PostHog functioning well.
person columns
Prior to having person_id, person_properties, person_created_at columns, when calculating funnels, unique users or filtering by persons or cohorts, queries always needed to JOIN one or two tables.
JOINs in ClickHouse are expensive and this frequently caused memory errors for our largest users, so a lot of effort was put into being able to denormalize that data and for it to be stored in events table.
Evaluation: 👍 Removes a fundamental bottleneck for scaling queries and allows for more efficient sharding in the future.
properties column and materialized columns
A lot of queries touch JSON properties or person_properties columns, meaning performance on them is critical. On the other hand, JSON properties columns are the biggest ones we have and filtering on them is frequently slow due to I/O and parsing overheads.
Some developments have helped speed this expensive operation up significantly:
The biggest unrealized win here is also allowing to skip reading rows via indexing or ORDER BY, but it's unclear on how that might be achieved.
Read more on working with JSON data and materialized columns in the ClickHouse JSON guide.
Evaluation: 🤷 A lot better than could be, but also a lot of unrealized potential.
SAMPLE BY cityHash64(distinct_id)
Allowing data to be sampled helps speed up queries at the expense of having less accurate results. This can be helpful for allowing a fast data exploration experience.
We should now be sampling by person_id column as analytics-by-person is _likely_ the most important thing.
At the time of writing (November 2022), sampling is not yet supported by the PostHog app.
ReplacingMergeTree with uuid as sort key
ReplacingMergeTree allows "replacing" old data with new given identical ORDER BY values. In our case, since we have a uuid column in ORDER BY, in theory users should be able to "fix" past data by re-emitting events with same event, date, and uuid but improved data.
However this does not work as ReplacingMergeTree only does work at merge-time and:
merges are not guaranteed to occur
we're not accounting for duplicate-uuid data in queries and it would be prohibitively expensive to do so
The only way to use this is to regularly use OPTIMIZE TABLE sharded_events FINAL, but that could make operations harder and require a lot of I/O due to needing to rewrite data.
Sending data with custom uuids is also undocumented and prone to bugs on our end.
Evaluation: 🚫 This design decision is a mistake.
elements_chain column
PostHog's JavaScript library has an autocapture feature, where we store actions users do on pages and DOM elements these actions are done against.
elements_chain column contains the DOM hierarchy autocaptured events were done against. In queries we match against this using regular expressions.
Evaluation: 🤷 Potentially suspect, but hasn't become an obvious performance bottleneck so far.
No pre-aggregation / precalculation
Every time an insight query is made that doesn't hit the cache, PostHog needs to re-calculate the result off of the whole dataset.
This is likely inevitable during exploration, but when working with dashboards that are refreshed every few hours or with common queries this is needlessly inefficient.
There are several unproven ideas on how to could optimize this:
1. Combine with previous results
Due to person columns now being stored on sharded_events table, historical data in the table can be considered immutable.
This means PostHog could store every query result after queries. On subsequent queries only query data ingested after previous query and combine results with the previous query results.
In theory this works well with line graphs but harder to do with e.g. funnels and requires extensive in-app logic to build out.
2. Projections
Similarly, due to immutable data PostHog could calculate some frequent insights ahead of time.
The projections feature could feasibly help do this at a per-part level for consistency without special application logic.
At PostHog, we store arbitrary payloads users send us for further analysis as JSON. As such, it's critical we do a good job at storing and analyzing this data.
This document covers:
Storing JSON in Strings and operations on them
Why and how to compress this data
Materialized columns
Alternative solutions: JSON data type, arrays
JSON Strings
At PostHog, we store JSON data as VARCHAR (or String) columns.
Relevant properties are then parsed out from the String columns at query-time using JSONExtract functions.
This has the following problems:
These columns end up really large even after compression, meaning slow I/O
It requires CPU to parse properties
Data is not stored optimally. As an example, JSON keys are frequently repeated and numbers are stored as strings.
Compressing JSON
Luckily, JSON compresses really well, speeding up reading this data from disk.
By default our JSON columns are compressed by the LZ4 algorithm. See benchmarks for more information and benchmarks.
Materialized columns
ClickHouse has support for Materialized columns which are columns calculated dynamically based off of other columns.
We leverage them to dynamically create new columns for frequently-queried JSON keys to speed up queries as each materialized column is stored the same way as normal columns and requires less resources to read and parse.
Read more in our blog and in this guide for PostHog specific details.
Operational notes
After adding a materialized column, it is only populated for new data and on merges. When querying old data, this can introduce performance regressions, so forcing the column to be written to disk, even for historical data, is recommended.
Materialized columns may cause issues during operations - e.g. they can make copying data between tables painful. It's sometimes worth considering dropping them before large operations.
However after testing we encountered several fundamental problems which make this feature unusable in our case until they are resolved: 1, 2, 3, 4, and 5
Add the new user to the cloud infra repo (see link above)
Use their email address as their username
Add them to the "Developers" and "DevelopersRO" groups (just use groups = local.default_groups)
Add team infra as reviewer.
Once this is merged, tell them to use http://go/aws to log in
Elevating permissions via #aws-access
To access the dev AWS environment, use the /awsaccess slash command in the #aws-access Slack channel and fill out the form that appears. Make sure to set up your AWS config file as described in our docs.
A dedicated secrets-editor role is available for managing secrets. Use this role across all AWS environments.
EKS access via #aws-access is currently in development. In the near future, expect all AWS access to be managed through the #aws-access channel.
Permissions errors using AWS CLI
If you see something like:
<my-user> is not authorized to perform: <action> on resource: <resource> with an explicit deny
Note the "with an explicit deny" in the end which likely is due to the fact that we force Multi-Factor Authentication (MFA). Follow this guide to use a session token.
TLDR:
Look up your security credential MFA device name from AWS console from https://console.aws.amazon.com/iam/home#/users/<user-name>?section=security_credentials
Run aws sts get-session-token --serial-number <arn-of-the-mfa-device> --token-code <code-from-token> --duration 129600 where code-from-token is the same code you'd use to login to the AWS console (e.g. from Authy app).
Run the following code, replacing the placeholder values with the appropriate ones:
Ask in the #support-infrastructure Slack channel for someone to add you.
To give someone access: Navigate to PostHog project IAM and use the +Add button at the top to add their PostHog email address and toggle Basic -> Editor role.
PostHog has 235 (at the time of writing) public repositories. Each of these repositories has a unique way to get the project up and running locally. To limit the friction of this we adapt GitHub's approach of scripts to rule them all. As they say:
Being able to get from git clone to an up-and-running project in a development environment is imperative for fast, reliable contributions.
Not every repository will need every script. Some repositories will need scripts custom to the environment (for example, make files). That's all fine. The goal is to have a baseline set of scripts that we can use to get a development environment up and a known location to look for those scripts.
Standard scripts at PostHog
When starting a new project, create a bin directory and include the following scripts (when relevant):
bin/setup - Install or upgrade dependencies (Ex. npm packages, brew packages, etc. Usually run once after cloning the repository and occasionally to upgrade packages).
bin/update - Updates dependencies after a pull. This could simply call bin/setup.
bin/build - Build the project, for projects that are compiled such as C#, Java, etc.
bin/start - Start the project. For SDKs, this might start an example server.
bin/test - Run tests (Ex. npm test, bundle exec rspec, etc.). Also includes linting, formatting, etc.
bin/fmt - Optional: Format/lint code. This can be called by test.
bin/docs - Optional: Generate documentation artifacts like API and SDK references.
Warning: Some environments add bin to the .gitignore file by default because that's where they compile binaries to.
Example scripts are available in the PostHog/scripts repository.
Got a service change you need to email customers about — an API deprecation, a new quota limit, a breaking SDK change, a migration deadline? Loop in Joe. He owns customer comms and will handle the copy and the send via Customer.io.
All you need to bring:
A rough draft of what you want to say and why
The audience: a PostHog cohort or a list of org_ids
Prior art to mirror: the feature-flags quota-limit rollout in product-internal#720.
For the underlying email infrastructure (Customer.io tags, categories, unsubscribe behavior), see the email comms handbook page. For incidents specifically, see engineering incidents — Marketing handles those comms too.
Staying on top of what ships
If you write or coordinate customer comms, join the #changelog internal Slack channel — it's the lowest-friction way to know what's just shipped. It's owned by the Wizard & Docs team and updated constantly as PRs merge.
The channel is populated by agentic workflows that scan merged PRs and feature flag changes in posthog/posthog and summarize them into it. You can opt a PR in or out via the Publish to changelog? checkbox on the PR template, or via the @posthog Slack app. See how to publish changelog for the full flow.
If you're the week's support hero or you are providing support for a customer and they have questions about their self-hosted deployment, follow this guide to provide initial support before looping in someone from the Infrastructure team.
Gather basic information
Here's a sample message that should help gather the relevant information up-front (appropriate for #community-support, but if working in a private channel with a paid customer, remove some of the obvious questions).
👋 Are you self-hosting or on PostHog Cloud? (if self-hosting please answer below)
1. What have you tried to solve the issue so far? How did that go?
2. Which cloud provider are you using? How many nodes are you running?
3. Are you using our Helm chart to deploy PostHog? Have you make any customisations? Can you please share your values.yaml file?
4. If you have any pod(s) erroring/restarting, can you please share the logs?
5. Do you have any kind of monitoring configured? (if not, can you please enable at least Grafana and Prometheus in the values.yaml of the Helm chart?)
6. How many events are in ClickHouse, and how many were ingested last month?
When they send you the output from the command in step 1, if any of the pods has a status other than Running, ask them for the output of kubectl logs pod-name -n posthog
The output from the previous step may or may not be familiar to you. Sometimes the logs will be something you've seen before. If that's the case, try to reproduce the issue locally and come up with a fix. If things are cryptic to you, loop in someone from the Infrastructure team.
If a pod is listed as Failed, suggest that they try an upgrade with helm upgrade -f values.yaml -n posthog
Common issues
Some common issues you might encounter are:
PostHog is stuck migrating/the migrate job has an issue
Tell them to run the following:
kubectl -n posthog delete job $(kubectl -n posthog get jobs --no-headers -o custom-columns=NAME:.metadata.name)
helm upgrade -f values.yaml -n posthog
The app/plugin server has an issue
The first thing that you can safely try here is to tell them to restart the apps pod:
# terminate the running plugins pod
kubectl scale deployment posthog-plugins --replicas=0 -n posthog
# start a new plugins pod
kubectl scale deployment posthog-plugins --replicas=1 -n posthog
Before looping in someone, ask them to check that DNS records are correctly set and have propagated with this command:
nslookup <your-hostname> 1.1.1.1
Other issues
Check out our Troubleshooting page for other common issues and how you might be able to provide "first aid" before looping in someone.
All is lost
The idea of this doc is to cover some basic support that you can provide in order to either help the customer solve their issue or gather basic info before someone from the Infrastructure team shows up.
However, never hesitate to call us! We're more than happy to help.
Also, if things seem very serious and/or relate to a paying customer, do reach out to us right away.
The DevEx team owns the shared developer tooling and workflows that cut across all product teams: local dev, CI, builds, framework upgrades, codebase structure, type systems, migration safety, and more. If it affects how fast and safely engineers can work on code and ship it, it's probably this team's thing.
Scope
| Area | What's owned | |------|------------| | Local dev | Local stack, hogli CLI, startup time, worktrees, Docker Compose, cloud envs | | CI | Pipeline speed, cost, reliability, flaky test triage, PR previews | | Build & tooling | Frontend/backend build pipelines, formatters, linters | | Type system | Backend/frontend type sync, OpenAPI generation, schema integrity | | Upgrades | Framework/language upgrades (Django, React, TS), dependency & security updates | | Architecture | Product folder structure, isolation model, legacy migration | | Migrations | Safe migration tooling, migration checkers, squashing |
Things you can use
Local dev
hogli CLI — start the stack, run tests, format, lint, generate types. hogli start
phrocs TUI — manage local services, restart, view logs
Intent system — only start the services you need hogli dev:setup
CI
Turborepo product tests — fast per-product CI instead of full suite
Hobby PR previews — full-stack preview environment for any PR
Visual review — visual regression testing with approval flow
PR approval agent — auto-approve low-risk changes
Code quality
Auto-generated TS types — OpenAPI from Django serializers via Orval, always in sync
Formatting & linting — oxfmt, oxlint, ruff, markdownlint in CI
Claude Code skills — agent guidance for hogli, migrations, DRF endpoints
Product isolation — tach-enforced boundaries between products
How to work with this team
Report what's slowing you down — flaky tests, slow builds, local dev friction, tooling that doesn't work right. A lot of it is known but there might be stuff that's been missed.
Loop the team into conversations early — if your team is making decisions that touch shared tooling, CI, code architecture, or conventions, bring DevEx in. Better to be in the discussion than clean up after it. Think: new products, services, big refactors, dependency changes, CI workflow tweaks.
Any process is a balance between speed and control. If we have a long process that requires extensive QA and 10 approvals, we will never make mistakes because we will never release anything.
However, if we have no checks in place, we will release quickly but everything will be broken. For this reason we have some best practices for releasing things, and guidelines on how to ship.
How to decide what to build
Set milestones
To start, Product and Engineering should align on major milestones (e.g. Collaboration) which we have strong conviction will drive our success metrics for a feature.
There are two types of goals.
Moonshots: These are big, scary goals where we expect to fail 50% of the time. If we fail we expect to learn something equally as valuable as if we succeed. Just scraping the goal counts as a success.
Roofshots: These might also be big, but we expect to achieve them 100% of the time. These can be goals where we cannot afford to fail (e.g. Launch feature to keep us compliant with new regulation), or where we are confident in our approach and don’t foresee unexpected risks or issues.
Goals should be time-bound, but since we primarily use goals for our two-weekly sprint planning we should consider them generally timebound to two weeks.
Use the following principles:
Clear: Anyone with general context can read it and instantly know what specifically it means to achieve it (i.e. NOT “refactor components”)
Finite: There should be an obvious end to the goal and cannot go on forever (i.e. NOT “improve dashboards”)
Assessable: You can validate whether or not you’ve achieved the goal - it doesn’t need to be a metric (e.g. Increased signups by 20% or Events can be ingested in any order)
Meaningful: If we achieve this goal it will solve a real need for our customers (i.e. a 10x improvement in performance sounds great as a goal - but it's not meaningful if our customers are happy with the current performance)
Challenging: It should too big for one person to solve on their own and require creativity or brute force to achieve in the proposed time-frame (e.g. ship correlation analysis with a killer feature no one else has)
Homogenous: The goal should be all about achieving a single meaningful thing and not a collection of unconnected things (i.e. NOT ‘Improve query performance and launch collaboration MVP’)
Assign an owner
A single engineer should be accountable for a milestone partnering closely with other functions to ensure it’s successful.
Think about other teams
Most things won't cause issues for other teams. However, if it will, don't "align teams" or write a huge RFC (unless that'd help you). Do a quick 1:1 with the most relevant person on another team.
Consider:
The scale of the customer you're building for
If you can get from your hacky MVP to production-ready easily. It's OK to start with basic, but be mindful of making it harder to fully roll something out in future.
If you know what you're doing or need someone from another team's expertise to get the right architecture or overall approach. We have lots of experienced people, get their help if you would benefit from it.
If this is a big feature which will need an announcement, content, or other marketing support then it's _never_ too early for the owner to let the Developer Marketing team know. Drop a post in their Slack channel or tagging them on an issue.
Break up goals
The owner turns the ambiguous milestone into a roadmap of ambitious, meaningful, sprint-sized goals, thinking 2 - 3 sprints ahead to give other functions time. Goal principles still apply.
Iterate through the work
We used to have company-wide sprint planning sessions but as we've grown there were so many teams that it started being plan-reading and not planning.
PostHog works in two week iterations. Each team plans their work together and adds their sprint plan to a pinned issue in GitHub. If the issue for the next iteration doesn't exist when you come to comment on it then you create it.
When planning your work you should also have a retrospective for the previous iteration. Like most things at PostHog this can be a very low ceremony retro and ideally checking the team is working on the right things in the right way is a frequent thing not a once a fortnight thing.
Work in the iteration should:
be concrete and probably achievable in 2 weeks
have a clear owner in the team
have a clear link to the team or company goals
As one of our values is Why not now?, during the iteration you might come across something that should be much higher priority than what was already planned. It's up to you to then decide to work on that as opposed to what was agreed in the planning session.
Evaluate success
Review impact of each major milestone and feedback into the planning process.
When we review the status of goals we classify them as follows:
Nailed it: We hit the goal spectacularly. High fives all round.
Scraped it: We _almost_ hit the goal, but we'll need to do a little bit more next sprint to tidy up. We should adjust our workload to have fewer resources on big goals during the next sprint to comfortably get this finished.
Failed it: We were nowhere near hitting the goal, but we learned some valuable lessons. We're going to go back to the drawing board. Maybe the goal wasn't right or maybe there's a different way to approach it?
What about the small stuff?
Not everything directly contributes to a company level goal. It’s important that the small stuff also gets done for us to succeed. Use the following principles:
Yes, and: Be encouraging and helpful with others who are innovating. All of our biggest wins have looked like bad ideas early on.
Dogfooding: Use the product yourself. When you see something that annoys you, fix it.
Side quests: Smaller projects you are passionate about but may not shoot up our metrics (e.g. turbo mode).
Support hero: Support hero dedicates all of their time to customers, solving the wild and wonderful issues our customers find each week.
Sizing tasks and reducing WIP
Efficient engineering organizations actively reduce Work In Progress (WIP) to avoid negative feedback loops that drive down productivity.
Hence, a PR should be optimized for two things:
Quality of implementation
The speed with which we can merge it in
PRs should ideally be sized to be doable in one day, including code review and QA. If it's not, you should break it down into smaller chunks until it fits into a day. Tasks of this size are easy to test, easy to deploy, easy to review and less likely to cause merge conflicts.
Sometimes, tasks need a few review cycles to get resolved, and PRs remain open for days. This is not ideal, but it happens. What else can you do to make sure your code gets merged quickly?
First, start your own day by responding to review requests from colleagues, and unblocking their work. This builds goodwill and encourages them to also review your code in priority. Otherwise, if everybody jumps to implement new features before reviewing WIP, we will end up with three, different, PRs, all for the same thing.
Test your code. Always read through your PR's changed lines, and test everything yourself, before handing it over for review. Remember that your colleagues are busy people, and you must do what you can to save their time. There's nothing more annoying than an extra 30 min review cycle that starts with _"Almost there, just it's all black now, and remove that console.log please"_.
Help your reviewer by leaving comments that help them review trickier bits. Better yet, write these directly into the code, either as comments or by clearly labelling your variables.
It's always good to put new features behind feature flags. It's even better to develop partial features behind feature flags. As long as it's clear what needs to be done before a flag can be lifted, you can usually get the smallest bit of any new feature out in a day this way.
Don't be afraid to restart from scratch if the PR gets out of hand. It's a bit of time lost for you, but a lot of time saved for the reviewer if they get a clean PR to review.
Push your code out as a draft PR early on, so everyone can see the work in progress, and comment on the validity of the general approach when needed.
Remember that PRs can be reverted as easily as they can be merged. Don't be afraid to get stuff in early if it makes things better. Why not now?.
We're big fans of Test Driven Development (TDD). We've tried to create test infrastructure that helps you rather than annoys you. If that isn't the case, please raise an issue! Keeping tests on point is a high priority to keep developer productivity high.
Other than that, you know what to do.
Creating PRs
When you have a piece of code ready to be reviewed, create a PR. Link the PR to the issue it solves, and add a clear description of what the PR does and how to test it. Follow PR templates if they exist for the area you're working on.
All PRs should be attributable to a human author as far as possible, even if they were assisted by an agent.
Fully automatically generated PRs might come from an agent like PostHog Desktop or from systems like Dependabot. These PRs are fine, but they should be clearly labelled as such and include a clear description of the changes being made and any relevant context about the generation process. These PRs should in turn never be attributed to a human author, as the changes were not directly or indirectly made by a human.
For external contributors, our AI contributions policy covers expectations around AI-assisted PRs.
To make sure our issues are linked correctly to the PRs, you can tag the issue in your commit.
git commit -m "Closes #289 add posthog logo to website"
In our CI pipeline, we use Playwright to load our Storybook stories and take snapshots. If any changes are detected, the updated snapshots are automatically committed to the PR. This helps you quickly verify whether you've introduced unexpected changes or if the UI has been altered in the intended way.
Check the test-runner.ts file to see how this is configured. We use the @storybook/test-runner package; you can find more details in the official Storybook documentation.
Running Tests Locally
Start Storybook in one terminal:
pnpm storybook
# or
pnpm --filter=@posthog/storybook
Install Playwright and run the visual tests in debug mode in another terminal:
It happens often that your PR will show conflics with our snapshots, as our CI pipeline will run test-runner.ts on every push, generating and pushing to your PR any significant visual changes.
Github does not allow for conflict resolution inside their website, so you must do it manually.
The following is done on your branch in question.
Bring your branch up to date with master.
git fetch origin
Rebase master into your branch
git rebase master
Rebase your upstream into your local branch
git pull --rebase <your branch>
In your terminal, it should show you the conflicts mimicking what you see in your Github PR.
warning: Cannot merge binary files: frontend/__snapshots__/<conflicted_file_1>.png (HEAD vs. xxx (Update UI snapshots for `chromium` (1)))
Auto-merging frontend/__snapshots__/<conflicted_file_1>.png
CONFLICT (content): Merge conflict in frontend/__snapshots__/<conflicted_file_1>.png
error: could not apply xxx... Update UI snapshots for `chromium` (1)
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
If all your conflicts are only snapshots, you can simply skip it.
git rebase --skip
If all conflicts go away, then
git push origin --force <your branch>
Why does this work? As we mentioned earlier, our CI runs test-runner.ts on every push, so we don't really care if these images are conflicted as they are regenerated after you push to your branch.
Deployed Preview
You can spin up a real deployed PostHog instance to test your branch by adding the hobby-preview label to your PR. This uses the hobby (Docker Compose) self-hosted setup under the hood.
How it works:
Add the hobby-preview label to your PR
CI creates a DigitalOcean droplet and deploys PostHog with your branch
A comment is posted to the PR with the preview URL (e.g., https://hobby-pr-12345.posthog.dev)
The droplet persists across commits so you can iterate
Remove the label or close the PR to clean up the droplet
When to use it:
Testing changes in a real deployed environment
Manual QA before merging
Verifying Docker Compose or deployment script changes
The workflow also runs a smoke test (health check) automatically on PRs that touch deployment-related files.
Reviewing code
For review requirements, checklists, and conventions, see How we review PRs.
Merging
Merge anytime. Friday afternoon? Merge.
Our testing, reviewing and building process should be good enough that we're comfortable merging any time.
Always request a review on your pull request (or leave unassigned for anyone to pick up when available). We avoid merging without any review unless it's an emergency fix and no one else is available (especially for posthog.com). During an incident, the Force-merge a PR Slack app is the sanctioned break-glass way to merge a PR that branch protection would otherwise block.
Once you merge a pull request, it will automatically deploy to all environments. The deployment process is documented in our charts repository. Check out the #platform-bots Slack channel to see how your deploy is progressing.
We're managing deployments with ArgoCD where you can also see individual resources and their status.
Break-glass: force-merge a PR
Branch protection on the posthog repo requires a review and green CI before anyone can merge. In exceptional cases — almost always during an incident — the Force-merge a PR Slack app lets any PostHog employee merge a PR that would otherwise be blocked. It bypasses required reviews and checks through a tightly-scoped GitHub App. Take great care: this is a break-glass tool, not a shortcut around code review.
To use it: in #dev, open the shortcuts menu (or type /force-), pick Force-merge a PR, and fill in the repo, the PR number or URL, and a reason.
What it enforces. The app refuses the merge unless:
The repo is one it's configured for (today, just posthog).
The PR is open, not a draft, not already merged, on an allow-listed base branch, and carries no blocking label (e.g. do-not-merge).
The PR author is a member of the PostHog GitHub org (no fork PRs from external contributors).
You're a full Slack workspace member with a @posthog.com email.
It bypasses required reviews and checks, but notcommit signing. A PR carrying an unsigned commit can't be force-merged, so sign your commits before reaching for this during an incident.
Everything is audited. Each force-merge posts an audit message to Slack, comments on the PR recording who triggered it and the reason, and writes a tamper-proof (object-locked) record, alongside an EventBridge event and a CloudWatch metric that alarms on unusual volume. Accountability is after the fact, so expect to justify any force-merge — and cover it in the post-mortem if it was part of an incident.
Deploy notification bot
After your PR is deployed to an environment, a bot automatically comments on the merged PR with the deployment status. The dev deployment triggers the initial comment. As prod-us and prod-eu finish deploying, the bot updates the same comment in-place rather than posting new ones.
If you don't see a comment on your PR after a deploy, give it a few minutes -- the notification runs after ArgoCD finishes syncing. If it still hasn't appeared, check the deploy workflow in PostHog/charts for failures.
Verifying your deployment
After merging, your code should deploy automatically. If you need to verify your changes are live (or troubleshoot why they're not), here's how:
1. Check state.yaml (what should be deployed)
The charts repository state.yaml is the source of truth for what ArgoCD is trying to deploy. Find your service (e.g., ingestion, posthog) and check the commit SHA listed.
# Find your service's pods
kubectl -n posthog get pods | grep <service-name>
# Get the image/commit running on a pod
kubectl -n posthog get pod <pod-name> -o jsonpath='{.spec.containers[0].image}'
3. Verify your commit is included
Use git merge-base to check if your commit is an ancestor of the deployed commit:
If state.yaml shows a newer commit than what's running on pods, check ArgoCD:
Find the specific app - Don't just look at the parent grouping (e.g., ingestion). Drill down to the specific environment app like ingestion-events-prod-us or posthog-prod-eu.
Check sync status - Is it "Synced" or "OutOfSync"? When was the last successful sync?
Check if auto-sync is enabled - Some apps may have auto-sync disabled and require manual syncing.
Look at the diff - Click "DIFF" to see what's different between desired and live state.
Common deployment issues
| Symptom | Likely cause | Solution | |---------|--------------|----------| | App shows "OutOfSync" | Auto-sync disabled or sync error | Check if auto-sync is enabled; try manual sync | | state.yaml updated but pods unchanged | ArgoCD hasn't synced yet | Check ArgoCD app status; may need manual intervention | | Pods running old commit | Rollout stuck or image not built | Check deployment rollout status; verify CI built the image | | Can't find your service in ArgoCD | Looking at wrong app grouping | Search for your specific service + environment (e.g., ingestion-events-prod-us) |
If a deployment appears stuck, reach out in #support-infrastructure or ping @infra-folks.
Documenting
If you build it, document it. You're in the best position to do this, and it forces you to think things through from a user perspective.
It's not the responsibility of either or teams to document features.
There are a few different ways to release code here:
just release the code change directly
when you have hign confidence the change is safe
release it behind a flag and slowly roll it out
when you don't need to run an AB test but want to be sure you can check the impact of the change
release it behind a flag and roll it out on demand (we call this a closed beta)
when you want to slowly release this to people who know they'll likely need to give feedback
you know it isn't complete and you need early feedback
release it behind a flag and run it with an AB experiment
you don't know what impact it will have and want to measure it
release it behind a flag and put it in a feature preview (we call this an open beta)
when you want to slowly release this to people who know they'll likely need to give feedback
you know it isn't 100% and you need feedback
run old and new at the same time
sometimes called the strangler fig https://martinfowler.com/bliki/StranglerFigApplication.html
run both old and new and compare the output / effect
you can then cut across (sometimes in stages) before removing the old code
Best practices for full releases
Opt-in betas can have rough edges, but public betas and full releases should be more polished and user friendly.
Engineers should apply the following best practices for _all_ new releases:
Ensure Marketing is aware of the launch, so a launch plan can be created.
Ensure docs are updated to reflect the new release.
Ensure all new features include at least one pre-made template (or equivalent) for users.
When to A/B test
There are two broad categories of things we A/B test:
Changes intended to move a metric (eg. changing CTAs to see if it improves click-through)
Changes that could impact large swaths of users and their behavior, to make sure there is no negative impact (eg. moving all items in the left nav into a drawer)
The former is an optimization scheme; the latter makes sure we don't break things. Just like we create tests in our codebase to make sure new code doesn't disrupt existing features, we also need to do behavioral testing to make sure our new features aren't disrupting existing user behaviors.
A/B tests make sense when:
There is sufficient traffic to give results in 1-2 weeks
The change isn't simply adding a new feature (eg adding a totally new feature and A/B testing if people use the feature isn't exactly informative, though you _should_ be looking at metrics for features you ship to see if anyone uses them)
If the feature is designed to improve some other metric like retention or stickiness, then test away!
The change impacts user behavior (eg most backend changes should have code tests - not behavioral A/B tests)
If you're not sure something should be A/B tested, run one anyway. Feature flags (which experiments run on top of) are a great kill-switch for rolling back features in case something goes sidwways. And it's always nice to know how your changes might move the numbers!
It's easy to just think "this makes more sense, let's just roll it out." Sometimes that's okay, sometimes it has unintended consequences. We obviously can't and shouldn't test everything, but running A/B tests frequently gets you comfortable with being wrong, which is a _very_ handy skill to have.
A/B test metrics
Experiment design is a bit of an art. There are different types of metrics you can use in PostHog experiments. Another benefit of running experiments is forcing yourself to think through what other things your change might impact, which oftentimes doesn't happen in the regular release cycle!
Generally, a good pattern is to set up 1-2 primary metrics that you anticipate might be impacted by the A/B test, as well as 3+ secondary metrics that might also be good to keep an eye on, just in case. If you aren't sure what metrics to be testing, just ask! Lots of people are excited to help think this through (especially #team-growth and Raquel!).
It's always worth letting Marketing know about new betas so they can help raise awareness. The owner should tag them on an issue, or drop a message in the Marketing Slack channel.
Betas are usually announced as milestones on the public roadmap and included in the changelog by Marketing.
Product announcements
Announcements, whether for beta or final updates, are a Marketing responsibility. See: Product announcements.
In order to ensure a smooth launch the owner should tell Marketing about upcoming updates as soon as possible, or include them in an All-Hands update.
It's _never_ too early to give Marketing a heads-up about something by tagging them in an issue or via the Marketing Slack channel.
The deploy-hobby script allows you to set a POSTHOG_APP_TAG environment variable and fix your docker-compose deployed version of PostHog. Or you can edit your docker-compose file to replace each instance of image: posthog/posthog:$POSTHOG_APP_TAG with a specific tag e.g. image: posthog/posthog:9c68581779c78489cfe737cfa965b73f7fc5503c
Each feature at PostHog has an Engineering owner. This owner is responsible for maintaining the feature (keep the lights on), championing any efforts to improve it (e.g. by bringing up improvements in sprint planning), planning launches for new parts of it, and making sure it is well documented.
For shared developer tooling and infrastructure that cuts across product teams (CI, local dev, builds, migrations, etc.), see the Developer Experience page.
When a bug or feature request comes in, we tag it with the relevant label (see labels below). The owner is responsible for then prioritizing any bug/request that comes in for each feature. This does not mean working on every bug/request, an owner can make the deliberate decision that working on something is not the best thing to work on, but every request should be looked at.
Who can contribute to owned features?
Feature ownership does not mean that the owner is the only person/team who can contribute to the feature. If another team requires something from an existing feature that isn't supported, that non-owning team should build it. The owner team is responsible for reviewing PRs to make sure the code patterns and UX makes sense for the feature overall. After the change is merged, the owner team then owns it (assuming no major bugs from the initial implementation).
For example, web analytics wanted a heatmap insight type to see what times of day people were active. Javier Bahamondes from web analytics opened up the necessary PRs to build this feature. It was reviewed by the , owner of all insight types, who then took responsibility for it after it was merged.
This process does four things:
It prevents people feeling like they need to wait on another team to build out necessary functionality for them
It ensures that features built by another team get proper review, because reviewers know they will have to own it eventually.
It makes sure no feature is left "orphaned" with no real owner.
Some of the features we are building may exist in other products already. It is fine for us to be inspired by them - there's no need to reinvent the wheel when there is already a standard way our users expect things to work. However, it is not ok for us to say 'let's copy how X does it', or to ship something with the exact same look and feel as another product. This is bad for two reasons:
We're highly unlikely to overtake everyone else if we just build the open source version of everything that is already out there.
We may expose ourselves to legal risk/challenges from those companies, especially if they can point to a public issue where we have said 'let's copy X'.
In an ideal world, Posthog's pricing enables users and organizations to:
Use PostHog with generous free allowances if they are hobbyists or pre-PMF.
Experience the product before paying for it.
Start paying when they are ready, on their own, with few hurdles.
Transparently pay for the value they receive.
e.g. Usage-based pricing on events, recordings.
e.g. Paying per product, so they only pay for what they use.
Make it a no-brainer to pick PostHog over other competitors.
Our goals with these principles are to:
Keep the engineers at PostHog as close to our customers as possible, so they can build new products or improve existing products in ways that are most impactful for them.
Maintain low barriers to entry for our customers, so they can see value in PostHog quickly.
Ensure transparency around the value we provide to our customers.
Tightly couple our success with that of our customers'. The more we can help them succeed, the more we will succeed.
It's important we evaluate all new features, and shifts in our pricing plans, to ensure they align with our pricing values.
In the real world
Sometimes these principles still leave room for questions – what, if anything, should be available in the free tier? What about enterprise customers?
For these types of questions, we've defined a runbook for deciding which plans, and at what limits, features should be assigned to.
Usage-based pricing as the default
The more a customer uses a product, generally the higher their bill should be. This has several benefits:
A customer only pays for what they use, not more, not less
As our costs for providing a product scale through increased usage, so does our revenue
A customer's bill, and therefore our revenue, scales with their success (more users, more usage of our platform, etc.). This means our incentives are aligned
The main exception to this rule are our platform packages, which are flat-fee monthly add-ons. These are designed to give our larger customers additional flexibility & controls (e.g. RBAC), without hindering individual user adoption (vs. a per-seat price). Flat-fee add-ons should be reserved for functionality where cost _doesn't_ scale with usage, e.g. extended retention should be charged usage-based, not as a flat-fee add-on.
Each product should have a path to pay for itself
When picking the pricing for a new product, we should ensure we pick a pricing that allows the product to pay for itself in the mid term.
While we don't have loss leaders, we accept that we might not fully understand our cost base and make money on every product on day one. We welcome this pressure to do things more efficiently and get the costs down over time.
A good pricing structure allows us to bring costs down over time with pricing staying fixed, thus increasing our margins.
For products in an established market, we should roughly match the cheapest competitor
In general, we should roughly match the pricing of the cheapest big competitor for that product, so long as the unit economics make sense, to make it a no-brainer to use PostHog. To qualify for this, a competitor must be _making actual revenue_ at significant scale – we won't match the pricing random startups or new products at existing competitors offer, since these products and GTMs aren't mature yet.
We can do this because we can upsell customers multiple of our other products. The total ACV is higher even if the per-product ACV is lower.
It's better for customers because they get all these products that are well integrated for the cheapest possible price.
For innovative products where there is no established market, we are also the innovator on price. For such products, pricing should match our pricing principles, but we shouldn't be afraid to experiment. This includes changing pricing early if it doesn't work out (e.g. if the product fails to pay for itself, or the usage-based unit we picked is unappealing to customers).
Every product should be priced separately
Whenever we build a product, like feature flags, or product experimentation, we should have a specific price for that product by itself. Being consistent here is less confusing than randomly combining products for example, even though it will sometimes mean more items to explain to a customer.
It means that customers who want just one product can compare each of our products to our competitors', seeing that we are cheaper everywhere, improving our self-serve top-of-funnel.
This also makes the value of each product more tangible. Usage and value are not the same thing – willingness to pay is the best indicator of the value our customers are getting from each product.
However, when one of our products has a fundamental dependency on another of our products, we should aim to bundle the cost of the dependencies in with the product's pricing so customers only pay once for using a given product.
For example, when someone calls a feature flag, we send a $feature_flag_called event so we can have stats. In this case, we don't charge for those events, as the events are solely related to feature flags.
Products or features that are core to interacting with our platform, or increase our stickiness, should be free, or priced close to cost
Interaction example: PostHog AI allows users to explore data in ways that weren't possible before, or interact with products more naturally through chat. While our costs of providing an agentic experience are high, we should charge close to cost, so we don't put users off using it.
Stickiness example: If someone were to consider moving from PostHog to some other provider, cohorts would need to be manually recreated in the other provider, which would be tedious. Since the costs of cohorts are partially covered through other products (e.g. product analytics), this allows us to provide cohorts to our users for free.
Products should work independently but shine together
Each product should be usable on its own. For example, session replay can be enabled independently of other products. But to get the most value out of it, it's best to use it together with our other products. This enables users to have rich filters using the data from the other parts of PostHog. Similarly, you can use error tracking on its own, but it's a lot more powerful if you also use session replay, enabling you to easily click through to the recording of a session where the error occurred.
Other guidelines
We accept pricing complexity for the benefit of the users. Usage-based pricing is inherently more complex (for users and for us) than e.g. flat rates, but it ensures that users only pay for what they use, and allows us to understand the true value that they're getting out of each product.
We should always ask ourselves how newly released features should be priced, even if it's launching as a free product. A default behavior is good, but it shouldn't be used as a replacement for critically thinking about where something fits into our pricing scheme.
For products we are expecting to have high costs or low margins (e.g. AI products), we should consider launching them with pricing even during beta, to not have our costs spiral out of control.
Our default assumption for new features is that full usage is only available on the paid plans.
Features that need to be experienced in order to demonstrate value should be available on the free plan but with a reasonable limit.
Features that have the potential to grow our word-of-mouth should be free – e.g. we shouldn't (and don't) charge for extra users in an organization because the more people we get inside PostHog, the better.
Features that are focused around extra security, permissioning, compliance, or other enterprise-style upgrades should be reserved for our enterprise pricing tier.
Grandfathering is expensive for us to maintain, so we don't do it by default for everyone and follow these guidelines:
Free users don't get legacy pricing. Once they start to pay, they pay our current prices.
Self-serve paid customers get a limited transition period (e.g. three months) with grandfathered pricing. This ensures that there's a clear deadline for the new pricing taking effect, while showing goodwill to customers who were already paying us. This also applies to customers who have a contract with us.
Nobody gets legacy pricing forever. If you think a customer needs an exception, that should be a time-boxed decision, and not the default.
Deciding on a free volume, and making changes to it
When choosing a free volume for a new product, we should choose a value that is in line with our pricing principles: It should give customers the opportunity to experience the product before paying for it, and we should roughly match our competitors if they offer a free tier.
Keep in mind: It's easy to increase the free tier for existing customers, but it's very painful to decrease it (since we don't want existing customers to pay more).
If we decide to lower the free tier as part of a wider pricing change (primarily when we lower our prices), in principle we should roll out the new pricing and the new free tier to existing customers, because they will likely save money. An exception should be made for customers who are forecasted to pay more. In these cases we should enroll them in the new pricing, but grandfather the higher free tier.
Yearly pricing evaluations & raising prices
Each product should run a yearly pricing evaluation. The evaluation should look at:
Competitive market
New features
Costs & margins
etc.
Use the yearly pricing evaluation template to do this, and submit it as an RFC for others to review.
The goal with the pricing evaluation is to make sure we are not undercharging or overcharging. Though we aim to be generous, things like inflation, increasing provider costs, and new features can mean that our margins get thinner and that PostHog becomes less healthy as a business. Business health is critical to making sure we can continue to provide great services for our customers.
Pricing evaluations might result in a recommendation to raise prices. This should be done respectfully – customers should always be notified of the price change with plenty of advance warning (e.g. 60 days) and should be given resources for how to maintain their current spend (e.g. tuning event volume).
We've all been there. Something was just merged and now there is a bug that you are having a real hard time pinning down. You hate to do it... but you need to get on a pod or instance to troubleshoot the issue further. _SHAME_
Image: Shame bell
Prerequisite
Make sure you've followed this guide to get AWS access. !!! Please follow the whole document !!!
Connect to a Kubernetes pod
After you got access to the EKS cluster and our internal network:
kubectl -n posthog get pods (get names of pods, you'll want a "web" pod most likely)
kubectl -n posthog exec --stdin --tty <POD_NAME> -- /bin/bash (get a shell to the running container)
kubectl -n posthog exec <POD_NAME> env (run individual commands in a container)
Note: if you need a Django shell, just run the following after connecting:
python manage.py shell_plus
Connect to an EC2 instance
Please follow this guide to connect via AWS Systems Manager Agent (SSM).
<!-- Canonical "how to review a PR" reference: review requirements, review checklists, turnaround, partial reviews, and comment conventions live here. Shipping/release process lives in development-process.md, link to this page from there, don't duplicate review guidance. -->
Almost all PRs made to PostHog repositories need a review before merging. We do this because, almost every time we review a PR, we find a bug, a performance issue, unnecessary code, or UX that could have been confusing. Here's how we do it:
Review requirements
PRs can be written by humans or by agents (like PostHog Desktop). See Creating PRs for how we distinguish AI-assisted human-authored PRs from fully automatically generated agent-authored PRs. Either way, the normal rule is that every PR needs a review before merging, and a human always merges. If you need an urgent review, ask in the #dev-stamp-exchange Slack channel. For true emergencies where no one else is available, an admin can bypass review requirements.
Who should review depends on who wrote the code:
Human-authored PRs can be reviewed by a team member or by Stamphog, our AI approval agent (see Enabling Stamphog on a repo). Stamphog runs deterministic checks first (size, file ownership, tier) and then does an LLM review for approval eligibility and suggestions. Stamphog is the only AI approval agent whose approval can satisfy the review requirement, and only for eligible human-authored PRs, so a team member can merge.
Agent-authored PRs always require a human review since we want at least one human in the loop. A team member must review the PR and approve it before merging.
We encourage the use of AI review agents (Codex, Copilot, Greptile, etc.) on PRs. Run them when they're useful, whether before opening a PR, while iterating, or before requesting a human review, and respond to or resolve meaningful comments. Other AI review agent comments and suggestions do not count as approval, but they catch things humans miss and speed up the review process. Avoid adding more agent reviews when the PR already has automated feedback. Three agents arguing with each other is noisy, unless the extra agent has a niche focus like security.
Enabling Stamphog on a repo
Stamphog is off for a repo until someone turns it on. Repos opt in one at a time, in two steps:
Add the repo to the Stamphog GitHub App installation on the PostHog org's installed apps page. The install flow syncs the repo into Stamphog. You need org owner rights, or an org owner has to approve the request.
Turn reviews on for the repo in the Stamphog scene, and pick the review mode. In label mode a review starts when someone adds the stamphog label to a PR, which is what every repo uses today. In auto mode every PR is reviewed. The daily Slack digest of Stamphog-approved merges is a separate toggle, and it needs reviews on.
Repo-level policy is optional. Stamphog reads .stamphog/policy.yml and .stamphog/review-guidance.md from the repo's default branch and layers them over hosted defaults, so a repo with no .stamphog/ directory gets the defaults. Stamphog can never approve a change to those files. It reads them from the default branch and never from the PR head, and every edit to them routes to a human reviewer.
What reviews are for
Automated reviewers are useful for cheap, repetitive checks: obvious bugs, missing tests, typo-level mistakes, suspicious edge cases, and things that look like lint or static analysis. They reduce noise for humans, but they don't replace human judgment.
Human reviewers should focus on things agents are bad at:
Does this solve the right problem for customers?
Is this the right thing to build at all?
Does it fit the team's direction and the surrounding product context?
Is the UX clear?
Is the approach simple, maintainable, secure, and scalable?
Reviews also build shared context and collective ownership. They are a chance to teach, learn, and make sure more than one person understands important changes. The author still owns correctness: reviewers help reduce risk, but approval does not move responsibility away from the person responsible for the PR.
If a change has long-term impact, such as architecture, schema, API, dependency, framework, or build changes, ask or pair with someone who has deeper context before merging. The goal is not to gatekeep, but to understand the tradeoffs and avoid surprising the team later.
If a change affects public behavior, docs, examples, changelogs, APIs, configuration, or defaults, review those as part of the PR too. Changes that need human judgment should get human review rather than relying on agents alone. This is especially important for SDK changes. Our SDK guidelines call out that public APIs, configuration, defaults, and behavior that affects customers need human review for ergonomics, platform fit, and long-term support cost.
Don't spend human review cycles on syntax formatting or preferences that a formatter, linter, or agent should catch.
The one sanctioned exception is the break-glass Force-merge a PR Slack app, used in exceptional cases (almost always during an incident) to merge a PR without the normal review and checks. Every use is audited.
Before requesting a review
The best way to get a fast, useful review is to make your PR easy to review.
Keep PRs small. If your change touches many files or mixes unrelated concerns, break it into a stack of smaller PRs. Smaller PRs get reviewed faster and reviewed better.
Open a draft PR. This keeps notifications quiet and lets you iterate without pinging reviewers.
Use AI reviewers (e.g. Copilot) or your own agent review where useful, and resolve meaningful comments. Iterate until they're only leaving nit-level feedback.
Self-review your own diff. Read through it as if you're seeing it for the first time. You'll catch obvious issues before someone else has to.
Write a clear description. Explain what the change does and why. Link the issue. Explain important tradeoffs or approaches you considered but rejected. If there's context a reviewer needs, put it in the description so they don't have to guess.
Annotate specific lines when useful. Leave comments on non-obvious code, risky tradeoffs, or places where extra context will help the reviewer.
Ask the right person or team. Pick reviewers who have the context needed for the change, but avoid assigning a crowd. If multiple teams need to weigh in, be clear who should review which part.
Add screenshots or GIFs for UI changes. A reviewer shouldn't have to pull the branch and navigate to the right page just to see what a button looks like.
Describe validation. Say what you tested, what manual QA you did, and why tests weren't added if applicable.
Avoid unnecessary rebases once review has started. They can orphan review comments and make it harder for reviewers to see what changed.
Make sure CI is green. Don't ask someone to spend time reviewing code that doesn't pass checks.
Mark it ready for review.
After you make changes, re-request review and leave a short comment when important feedback has been addressed, especially if the fix is not obvious from the diff.
If your repository needs a clearer signal that a PR is ready for review, consider adding a lightweight checklist to your PR template. For example: "I've self-reviewed this PR", "I've run or added AI review and addressed relevant comments", and "This PR was agent-authored and needs human review." Keep this repository-specific and only add it if it reduces confusion.
Have a flick through the code changes
What to look for:
Does the code fit into our coding conventions?
Is the code free of bugs?
How will the solution perform at huge scale?
Are the database queries scalable (do they use the right indexes)?
Are the migrations safe?
Are there tests and do they test the right things?
Do they cover the requirement or defect, not just implementation details?
Do they simulate how a user would call the API or use the UI where possible?
Do they cover permissions and access control where relevant?
If tests were AI-written, do the assertions prove the behavior is correct rather than only passing?
Are the tests simple enough to trust, without unnecessary branching or looping?
Is the solution secure?
Is there no leakage of data between projects/organizations?
Is the code properly instrumented for product analytics?
Is there logging for changes potentially affecting infrastructure?
Are analytics query changes covered by snapshot tests? Does the SQL generated make sense?
What _not_ to look for:
Syntax formatting. If we're arguing about syntax, that means we should be using a formatter or linter rule.
Run the code yourself
What to look for:
Does the PR actually solve an issue?
Are we building the right thing? (We should be willing to throw away PRs or start over)
Is there anything here we should not build?
Does the change offer a good user experience?
Does the UI of the change fit into our design system?
Should the code be behind a feature flag?
If the code is behind a feature flag, do all cases work properly? (in particular, make sure the old functionality does not break)
Are all possible paths and inputs covered? (Try to break things!)
What _not_ to look for:
Issues unrelated to this PR. Create new, separate issues for those.
The emphasis should be on getting something out quickly. Endless review cycles sap energy and enthusiasm.
Turnaround
Aim to respond to review requests within one working day. You don't have to finish the review. Even a quick "I'll look at this properly tomorrow" or "this needs someone from [@team-name] to review" unblocks the author and sets expectations. Leaving a PR in limbo for days is worse than a fast "I can't review this."
Requesting a review outside your team
Not every team has someone available to review your PR right away. Posting in #dev-stamp-exchange is a way to ask for a quick-turnaround review from someone outside your team. This is fine, but quick turnaround doesn't mean lower standards.
When this is appropriate:
The PR is small and self-contained (think single-digit files changed)
It doesn't require deep product or architectural context to understand
CI is green and any automated review comments are addressed
What's still expected from the reviewer:
Actually read the diff. Don't just hit approve
Consider using AI-assisted review tools (e.g. add Copilot as a reviewer) to catch things you might miss
If your approval is intentionally low-context to unblock someone, say that in the review so the author knows to seek deeper help if needed
Flag anything that looks off, even if you're not deeply familiar with the area
When to push back instead of approving:
The PR is too large or complex to review without context
There are no tests, no description, or no visual evidence of the change working
You're not confident the change is safe. Say so. "I can't meaningfully review this. You need someone with more context" is always valid feedback
Partial reviews
If you were asked to review only one aspect of a PR (e.g. copy, design, infra, security), submit your review as Comment, not Approve. An Approve from any reviewer clears the review requirement and marks the PR mergeable, so it should mean "I reviewed this against the full checklist above." Reserve Approve for when you actually did.
If multiple reviewers are splitting aspects of a PR, the author is responsible for making sure at least one Approve came from someone who reviewed the code. CODEOWNERS can enforce this on a per-path basis where it matters.
Choosing a GitHub review state
Use Comment for thoughts, questions, suggestions, partial reviews, or feedback where the author can use their judgment.
Use Approve when you think the PR is safe to merge. It's fine to approve with nits or suggestions.
Use Request changes only when you believe merging the PR as-is would be seriously unsafe and you can keep the feedback loop moving. Examples include security or privacy risks, data loss or corruption, migrations that are unsafe or hard to roll back, unexpected breaking changes to public APIs or contracts, or changes likely to materially harm customers or the company.
Remember that Request changes blocks the PR until you approve a later revision or the state is dismissed. A blocking: comment can be submitted with Comment, especially when something must be fixed but you cannot own prompt follow-up. Authors and mergers should not merge while unresolved blocking: comments remain, even if those comments were submitted with Comment. If you use Request changes, make the required change explicit, watch for the author's response, and re-review promptly. If you won't be available, prefer Comment or hand off to someone who can follow through.
Review comment conventions
Use prefixes on your review comments so the author knows what actually needs to change before merging:
blocking: This must be fixed before merge. Use sparingly, and reserve it for bugs, security issues, or things that will break. A blocking: comment does not require Request changes; use Comment if Request changes would unnecessarily block the feedback loop.
nit: A minor style or naming suggestion. Take it or leave it. If only nits remain, consider approving rather than forcing another review cycle.
suggestion: A different approach worth considering, but the author's call.
question: You don't understand something. Not necessarily a problem, but you'd like clarification.
If a comment doesn't have a prefix, assume it's a suggestion. This avoids the "is this a blocker or just a thought?" ambiguity that slows reviews down.
Anyone can declare an incident and, when in doubt, you should always raise an incident. We'd much rather have declared an incident which turned out not to be an incident. Many incidents take too long to get called, or are missed completely because someone didn't ring the alarm when they had a suspicion something was wrong. It's _always_ better to sound an alarm than not.
To declare an incident, type /incident anywhere in Slack. This creates a new dedicated channel for the incident and add a few stakeholders. It will trigger an alert in the #incidents channel so everyone else can be aware. Declaring an incident doesn't trigger any external notifications.
Once an incident is raised an automatic workflow begins that will help you summarize the issue and escalate it appropriately.
Some things that should definitely be an incident
us.posthog.com (PostHog Cloud US) or eu.posthog.com (PostHog Cloud EU) being completely unavailable (not just for you)
No insights can be created
Feature flags are not being returned at all, or /flags is down
Any feature is 'down' and users are unable to access their existing data through it (this can be a bug and doesn't have to be an infra incident)
Various alerts defined as critical, such as disk space full, OOM or >5 minute ingestion lag
Things that _shouldn’t_ be an incident
Insights returning incorrect data
Events being < 5-10 minutes behind (E2E ingestion lag)
Unable to save insights, create feature flags
Expected disruption which happens as part of scheduled maintenance
Planning some maintenance? Check the announcements section instead.
Security-specific guidance
Security incidents can have far-reaching consequences and should always be treated with urgency. Some examples of security-related issues that warrant raising an incident include:
Unauthorized access to systems, data, or user accounts
Detection of malware, ransomware, or other malicious software on company systems
Suspicious activity on production infrastructure, such as unexpected user logins, privilege escalations, or resource consumption spikes
Discovery of exposed credentials, sensitive data, or secrets in logs, repositories, or public forums
Receiving a credible report of a vulnerability or exploit affecting company systems
When in doubt, err on the side of caution and raise the incident and escalate early! Better to be safe than sorry.
Please refer to the following guidance when choosing the severity for your incident. If you are unsure, it's usually better to over-estimate than under-estimate!
Minor
A minor-severity incident does not usually require paging people, and can be addressed within normal working hours. It is higher priority than any bugs however, and should come before sprint work.
Examples
Broken non-critical functionality, with no workaround. Not on the critical path for customers.
Performance degradation. Not an outage, but our app is not performing as it should. For instance, growing (but not yet critical) ingestion lag.
A memory leak in a database or feature. With time, this could cause a major/critical incident, but does not usually require _immediate_ attention.
A low-risk security vulnerability or non-critical misconfiguration, such as overly permissive access on a non-sensitive resource
If not dealt with, minor incidents can often become major incidents. Minor incidents are usually OK to have open for a few days, whereas anything more severe we would be trying to resolve ASAP.
Major
A major incident usually requires paging people, and should be dealt with _immediately_. They are usually opened when key or critical functionality is not working as expected.
Major incidents often become critical incidents if not resolved in a timely manner.
Examples
Customer signup is broken
Significantly elevated error rate
A Denial of Service (DoS) attack or other malicious activity that affects system availability
Discovery of exposed sensitive data (e.g., credentials, secrets) that could lead to a security breach if not remediated
Critical
An incident with very high impact on customers, and with the potential to existentially affect the company or reduce revenue.
Examples
Posthog Cloud is completely down
A data breach, or loss of data
Event ingestion totally failing - we are losing events
Discovery of an active security exploit, such as a compromised user account or system
Detection of ransomware, malware, or unauthorized modifications to production systems
What happens during an incident?
When an incident is declared, the person who raised the incident is the incident lead. It’s their responsibility to:
Make sure the right people join the call. This includes the current on-call person (@on-call-global in Slack) and the team responsible for the alert (we have a workflow which will try to add these people automatically). Optionally, add people from Infra and the feature owner and Support. Product Marketers can assist in running communications if required.
Take notes in the incident channel. This should include timestamps, and is a brain dump of everything that we know, and everything that we are or have tried. This will give us much more of an opportunity to learn from the incident afterwards.
Update the status page. If the incident happens during business hours, the incident should have a watcher. Support can help review the messaging for clarity. The status page can be updated from:
(recommended) the incident Slack channel using /incident statuspage (/inc sp)
the status page area of the incident.io dashboard (only recommended for corrections/modifications - Slack tooling provides better context)
The incident lead role is not responsible for fixing the incident, they're responsible for managing it. Sometimes that will be the same person. But if it is too much work for one person, hand over the incident lead role to someone else not actively working on the fix.
Sometimes, customer communication is required. In this case, the incident lead can ask for a comms lead to support the responding team. The best way to do this is to ask for support in the incident channel and use the @all-marketers group tag. Don't be shy.
Occasionally the fastest way to stop the bleeding is to ship a fix that can't wait for the normal review and CI gating. The Force-merge a PR Slack app is the sanctioned break-glass way to do this — it merges a PR even when branch protection would otherwise block it.
This is for exceptional cases only. Take great care, and only reach for it when a fix is genuinely time-critical and waiting on required reviews or checks would prolong customer impact. Any PostHog employee can use it.
To force-merge, open the shortcuts menu in #dev (or start typing /force-) and pick Force-merge a PR, then enter the repo, the PR number or URL, and a reason. Every force-merge is fully audited — it posts to Slack, comments on the PR with who triggered it and why, and is recorded in a tamper-proof log — so be ready to account for it in the post-mortem.
Our status page is the central hub for all incident communication. The Incident Lead owns creating status page updates unless they explicitly hand this over to a Comms Lead. You can update it easily using the /incident statuspage (/inc sp) Slack command.
When updating the status page, make sure to mark the affected component appropriately (for example during an ingestion delay, setting US Cloud 🇺🇸 / Event and Data Ingestion to Degraded Performance). This allows PostHog's UI to gently surface incidents with a "System status" warning on the right. Only users in the affected region will see the warning:
Getting help from a comms lead
Significant incidents such as the app being partially or fully non-operational, as well as ingestion delays of 30 minutes or longer should be clearly communicated to our customers. They should get to know what is going on and what we are doing to resolve it. If the incident is minor this can usually be done by updating the status page, but it may be desirable to do additional customer communications, such as sending an email to impacted customers. When this is required, you should involve a Comms Lead and ensure the Sales team are aware.
The best way to ask for support from a Comms Lead is to post in the incident channel and use the @all-marketers group tag. This will alert the all relevant marketing teams.
When handling a security incident, please align with the incident responder team in the incident Slack channel about public communication of security issues. For example, it may not make sense to immediately communicate an attack publicly, as this could make the attacker aware that we are already investigating. This could it make harder for us to stop this attack for good.
When a customer is causing an incident
In the case that we need to update a _specific_ customer, such as when an individual org is causing an incident, we should let them know as soon as possible. Use the following guidelines to ensure smooth communication:
Look up the customer's org in Vitally to see if the org has an Account Exec assigned (PostHog Default Dashboard / righthand column, scroll down to Key Roles.) If so, let the AE know about the situation early.
Ensure you are always contacting the admins of the impacted organization
Communication is best done through PostHog Support. It's usually best for the customer's assigned person (check Vitally), or the Support team, to create tickets and handle the communication for you, but don't wait if it's really urgent.
Before sending any comms, check with the incident lead. Then, share a ticket link in the incident channel.
If action is needed, it's better to take that action and inform the user than to ask the user to do it.
If you're not able to take the required action, give the user deadlines for the changes they need to do and explain what will happen if they don't meet the deadline.
Try to keep all communication on a single ticket, with all relevant parties.
In the case that we need to temporarily limit a _specific_ customer's access to any functionality (e.g. temporarily prevent them from using an endpoint) as a result of certain usage resulting in an incident, we need to make sure that anyone working on a ticket from the org will know what's happening with the org before replying (even if we've already reached out to the org, some folks at the org may not be aware, and so may open a support ticket.)
Post in #team-support with the org name and what's been limited — the support team will make sure tickets from that org are flagged so anyone replying is aware. Once the org's full access has been restored, let #team-support know so the flag can be removed.
When does an incident end?
When we've identified the root cause, implemented a fix, and confirmed all customer-facing services have returned to normal. End the incident by typing /inc close in the incident channel. Make sure to also mark the incident as resolved on the status page.
What happens after an incident?
Once the incident is resolved, the incident lead should step away. Take a walk, go to the gym, have some tea, take a shower. The longer the incident took to resolve, and the more directly customer impacting it was, the more important this is. Bring another team member up to speed, hand off outstanding customer communications, and get your head clear for the post-mortem and followup actions. Anyone else heavily involved in the response should do the same.
In almost all cases, a valid incident will have a post-mortem - check out Post-mortems for more details.
At PostHog, every engineer is responsible for maintaining their team's services and systems. That includes:
Tracking and visualizing key performance metrics
Configuring automated alerting
Documenting runbooks for on-call resolution
First-responder to team-owned services during working hours
In addition, every engineer regardless is part of the global follow-the-sun on-call rotation.
Escalation schedules
Your team's schedules, the escalation paths that page them, and your team's entry in the incident.io Team catalog are all defined in Terraform – one block per team, in one file. Setting a team up, or changing who's on call and when, means editing that block rather than the incident.io dashboard.
Cover for PTO and swaps is the exception: overrides still happen in the dashboard, because Terraform owns the rotations and not what's layered on top of them.
Team schedules
A team has up to three schedules in incident.io, and it gets the ones its Terraform block asks for:
On call: {team}
Working-hours cover, and where alerts routed to the team go. Everyone gets their own rotation, you just set the start of your normal working day, weekdays only
Stagger start times to cover as much of the day as your team can – 08:00 for an EU-based engineer leaves 17:00 onwards for a US-based one
Gaps are fine. Nobody is woken up here: a critical alert that finds nobody on call goes to global on-call instead
The support hero rotation. Everyone takes turns one at a time, handing over every week or two. Nothing pages it
Manual escalation schedules
Teams that own production-critical services also have a Page team (emergency): {team} schedule, triggered by hand by whoever is handling an incident and needs more help. Other teams don't need one. The schedule and the escalation path that pages it share this name – there's exactly one of each per team.
Unlike On call: {team}, this rotation has to cover the clock, every day of the week. You describe it as groups – blocks of the clock with the people covering each one, an EU group and a US group, or however your team is actually spread. Everyone in a group is on call for the whole of its window rather than taking turns, and the page cycles between them one at a time.
Group windows have to tile the full 24 hours between them. If they don't, the Terraform plan fails and names the first uncovered minute – somebody escalating by hand at 3am should never find nobody there.
💡 Don't rearrange this schedule around your own availability, and don't request cover on it. It's best-effort cover rather than a rotation with turns to trade – everyone in a group is on call for the whole window. If you're genuinely unavailable, add an override on yourself and the rest of your group is still there.
When to use manual escalation
Manual escalation should be used when:
The primary on-call person is unresponsive or unavailable
The situation is critical and requires immediate additional expertise
You're the on-call responder and need help from a specific team outside normal working hours
How to trigger manual escalation
From within an incident in incident.io, use the escalation options to page the relevant Page team (emergency): {team}
This pages whoever is on that team's emergency rotation right now, then everyone on it – one person at a time, 10 minutes per level
Any available team member can then respond and assist with the incident
💡 Manual escalation is a safety net, not a shortcut. Always try the normal escalation paths first before manually escalating to an entire team.
💡 You can use @on-call-global in Slack to reach out to whoever is on call! This syncs automatically with the incident.io schedule. This group is also automatically added to all incidents.
PostHog Cloud doesn't shut down at night (_whose_ night anyway?) nor on Sunday. As a 24/7 service, our goal is to be 100% operational 100% of the time. The global on-call is the last line of defense and is escalated to:
if nobody at the On call: {team} level is available
if the alert is critical but has no team assignment (for whatever reason)
It's also the one schedule not defined in Terraform – it changes too often, and by too many hands, for that to be safe.
This schedule has 3 week day layers:
Europe (06:00 to 14:00 UTC) - (8 hours)
Americas East (14:00 to 22:00 UTC) - (8 hours)
Americas West (22:00 to 06:00 UTC) - (8 hours)
And 2 weekend layers:
Europe Weekend (06:00 to 18:00 UTC) - (12 hours)
Americas Weekend (18:00 to 06:00 UTC) - (12 hours)
Why is the on-call rotation spread across all engineers?
If you're in a product team, it's tempting to think that service alerts don't apply to you, or that when you're on call you can just hand everything off to the infrastructure team. That's not the case, because it's important that every engineer has a basic understanding of how our software is deployed, where the weak points in our systems are, and what the failure modes look like. This understanding should be all that's needed to follow the runbooks, and if you follow the causes of alerts, ultimately you'll be less likely to ship code that takes PostHog down.
Besides knowledge, being on call requires availability – including weekends. If teams had their own separate rotations, there would be more people on call in total, and each would have to stand by 24/7 as our teams aren't big enough to follow the sun. This would be more stressful because of availability constraints, while being less productive because of the rare alerts being spread across multiple people.
Escalation paths
A schedule says who's on call. An escalation path says who gets paged, in what order, and how long they have to respond. A team gets the paths that follow from the schedules it has:
On call: {team} – where an alert routed to the team goes, previously named PostHog: {team}
Two more are org-wide rather than owned by a team: Default escalation, for an escalation that's nobody's in particular, which pages global on-call for 30 minutes and then the last-resort rotation alongside it; and the Slack only: ... paths, which post to a Slack channel and page nobody.
Paths are named so that listing them alphabetically – which is what the escalation picker does – puts them in the order you'd reach for them.
The standard on-call path
Every On call: {team} path is the same shape, so paging behavior doesn't vary by team:
Post to the team's own alert channel, whatever the priority
If the alert is critical, page the team's On call: {team} rotation – 10 minutes to ack
Still unacked? Post to #alerts, then page global on-call alongside the team – 15 minutes to ack
Repeat
Non-critical alerts stop at step 1 – the team sees them in Slack, nobody gets woken up. Levels page one person at a time, moving on every two minutes until somebody acks, rather than paging a whole rotation at once.
You supply people and hours – rotation mechanics aren't configurable. Read the existing team blocks in that file for the structure, and the module's README and teams variable for what each field means and the rules they have to follow. Those are the source of truth, so this page doesn't restate them.
Open a PR against posthog-cloud-infra and CI runs the plan. Read it before merging – it names every rotation and paging level that moves. Don't make these changes in the incident.io dashboard, because the next apply puts them back.
Rather than hand-writing the HCL, point your editor's agent at it:
In posthog-cloud-infra, add my team to the incident.io on-call setup.
Read terraform/modules/incidentio-oncall/ first – the README and the `teams`
variable, which document every field and the rules they follow – then add a
block for my team to `teams` in
terraform/environments/incidentio/oncall/terragrunt.hcl, following the existing
team blocks for structure.
Here's who's on call and when, in local time: <people, their working hours, and
who covers escalation out of hours>.
Then run `terragrunt hcl validate` and `terraform fmt`, and show me the plan.
Because the stability of production systems is critical, on-call involves weekends too (unlike Support Hero). More likely than not, nothing will happen over the weekend – but you never know, so the important thing is to keep your laptop at hand.
Before going on call, make sure you have the Incident.io mobile appAndroid / iOS installed and configured. This way it'll be harder to miss an alert.
TRICKY: We use Slack auth for incident.io and Slack really doesn't like you using the mobile web version. Make sure to choose Sign in with Slack and then use your email to login to Slack, not google auth as that seems to cause redirect issues for some people.
To get a calendar with all your on-call shifts from incident.io go to the schedules section, select Sync calendar at the top right and copy the link for the webcal feed. In google calendar, add a new calendar from URL and paste the link in there.
Make sure alerts can break through Do Not Disturb
The incident.io app does not configure these settings for you on install. By default your phone's Do Not Disturb, Sleep, or Focus mode will silence pages. Configure both the incident.io app and phone contact so alerts always come through.
iOS
Save the incident.io On-call contact to your phone. In the incident.io mobile app, go to Settings → Contacts and enable the toggle to add the contact to your address book.
Enable Emergency Bypass for that contact. Open the Contacts app → Lists → All Contacts, find incident.io On-call, tap Edit → Ringtone → toggle on Emergency Bypass. Repeat for Text Tone so SMS pages also break through. On iOS 18+, edit from All Contacts rather than the auto-grouped "incident.io" section to avoid a known Apple bug.
Allow critical notifications.Settings → incident.io → Notifications → enable Critical Alerts. These bypass silent and Focus mode for push notifications.
Allowlist incident.io in every Focus mode.Settings → Focus → for each mode (Sleep, Do Not Disturb, Work, etc.) → Apps → add incident.io to the allowed list.
Optional: Watch for sound redirects. Apple Watch pairing, AirPods Announce Notifications, and Screen Time can route incident.io alerts away from your phone speaker – disable the incident.io app in the Watch app's notification list and add incident.io to Screen Time's "Always Allowed" apps.
Android
Exact menu paths vary by manufacturer (Pixel, Samsung, OnePlus, etc.), but the same setup applies:
Grant Do Not Disturb access to the app. Accept the prompt during incident.io onboarding, or set it manually via Settings → Apps → incident.io → Special app access → Do Not Disturb access.
Disable battery and sleep restrictions for the app.Settings → Apps → incident.io → disable Pause app activity if unused, and set App battery usage to Unrestricted. Otherwise Android may kill the app in the background and you won't get paged.
Allowlist incident.io in each Do Not Disturb / Focus mode. On Pixel/stock Android: Settings → Sound & vibration → Do Not Disturb → Apps → add incident.io. On Samsung: Settings → Modes and routines → each mode → Allowed apps → add incident.io.
Star the incident.io On-call contact and allow starred contacts to bypass DND. Save and star/favorite the contact, then under Do Not Disturb → People (or Exceptions), allow Calls and Messages from Starred contacts. This lets the phone calls and SMS pages ring through.
Consider enabling Alarm-style notifications. In the incident.io app's advanced settings, toggle Alarm style notifications and make sure alarms are allowed during Do Not Disturb – this routes pages through the alarm channel, which most phones treat as un-silenceable.
💡 Test it! Once configured, put your phone into Do Not Disturb / Sleep mode and ask a teammate to send you a test page (or use the Send test notification button in the incident.io app). If you don't hear it, something still isn't right.
Make sure your availability is up-to-date
If you are unavailable for any of your schedules you need to act! Overrides are the one part of a schedule that isn't in Terraform, so do these in the dashboard – an apply won't undo them.
For your On call: {team} schedule simply click on your name in your rotation, click create an override and then remove yourself from the list so it shows No one
For your Support Hero: {team} or On call: Global schedules click Request cover at the top right. This will notify selected team members automatically to find someone to cover you (you should probably do a shout out in #ask-posthog-anything as well). You can trade whole weeks, but also just specific days. Remember not to alter the rotation's core order, as that's an easy way to accidentally shift the schedule for everyone.
For your Page team (emergency): {team} schedule, don't request cover and don't reshuffle the groups – nobody needs to take your turn, because there aren't any. Add an override on yourself for the window you're away, the same way as above, so it's clear you're unavailable. Everyone else in your group is still on call.
Make sure you have all the access you might need
To be ready, make sure you have access to:
PostHog Cloud admin interfaces (🇺🇸 US / 🇪🇺 EU) - post in #ask-posthog-anything to be added
ArgoCD - this is where 99% of cluster operations take place such as restarting pods, scaling things up and down etc.
Metabase (🇺🇸 US / 🇪🇺 EU) - post in #ask-posthog-anything to be invited
More advanced access
If you are part of a team that looks after more critical infrastructure such as infra, ingestion, workflows, error-tracking etc. then you are expected to dive deeper than the usual on-call engineer.
As well as the above access you should ensure you have access and feel comfortable working with:
EKS over kubectl / k9s, in case you need to run Kubernetes cluster operations (such as restarting a pod) – follow this guide to get access
Our tailnet, which gates our internal services (such as Grafana, Metabase, or runbooks) – follow this guide to join
Responding to alerts when on-call
Image: alert-example
Critical alerts trigger the team's On call: {team} escalation path, which pages a member of the team associated with the alert first, then global on-call alongside the team if nobody responds in time.
If at any point you get paged - always respond! Even if you are unavailable you should respond as such (either via the app or the personal Slack notification). That way the escalation can continue to the next available person.
By default if you are being paged, especially as the global on-call, the alert is considered critical, meaning it almost definitely requires attention.
Every alert should have associated Grafana and Runbook links allowing you to quickly get more visual details of what is going on and how to respond.
When an alert fires, find if there's a runbook for it. A runbook tells you what to look at and what fixes exist. In any case, your first priority will be to understand what's going on, and the right starting point will almost always be Grafana.
Sometimes alerts are purposefully overly-sensitive and might already be fixing themselves by the time you see them. Use your best judgement here. If the linked graph has a spike that is clearly coming down, watch it closely and give it time for the alert to auto-resolve.
If you're stumped and no resource is of help, get someone from the relevant team to shadow you while you sort the problem out. The idea is that they can help you understand the issue and where to find how to debug it. The idea is _not_ for them to take over at this point, as otherwise you won't be able to learn from this incident.
At PostHog, we believe that incidents are learning opportunities. Every incident, whether major or minor, provides valuable insights that help us improve our systems, processes, and response capabilities. Post-mortems are our way of capturing these lessons and ensuring we continuously improve.
Why post-mortems matter
Post-mortems serve several critical purposes:
Learning from failures – Understanding what went wrong and why helps prevent similar issues
Process improvement – Identifying gaps in our monitoring, alerting, or response procedures
Knowledge sharing – Ensuring the entire team benefits from lessons learned
Documentation – Creating a historical record of incidents and their resolutions
Post-mortem process
Incidents can be stressful and time consuming but it's equally important that we take the time to learn from them and improve our systems and processes. The longer you wait, the more details you'll forget and the less valuable the post-mortem becomes.
We use incident.io's post-mortem template which helps guide you through the process. They also have hints on what kind of content you should be focusing on in each section.
For major incidents
Major incidents require a team call to discuss and learn together:
Write the post-mortem – Fill out the template in the incident page (you will be prompted to do this when the incident is resolved).
Fill out the Summary and DERP sections in detail – These are the most valuable
Check the timeline is accurate –
Schedule the call – Invite engineering@posthog.com and any key stakeholders related to the incident
Review as a group – Spend the majority of the call reviewing Prevention. There may be details and other ideas people come up with in the call – you should be updating the post-mortem as you go to capture these.
Share outcomes – Post the final summary in #incidents (this should happen automatically when you mark the post-mortem as complete)
For minor incidents
Minor incidents can be handled more simply:
Write the post-mortem – Fill out the template
Focus on the summary and DERP – The timeline here is less important.
Share the summary – Post in #incidents channel for visibility (this should happen automatically when you mark the post-mortem as complete)
For false-positive incidents
Sometimes incidents are raised but turn out to be false-positives. In this case you can usually just close the incident and opt-out of the post-mortem process.
But wait! Before you do this you should consider what could have been done better to prevent the incident from happening in the first place. Clearly there was some false-alert or unclear alerting that caused the incident to be raised in the first place. It might be worth a quick post-mortem just to check that we have follow ups in place
💡 Remember: The goal is not to prevent all incidents, but to learn from them and improve our systems and processes. Every incident is an opportunity to make PostHog more reliable and our team more effective.
Public post-mortems
Some incidents require a public post-mortem. We publish these on our public post-mortems page because we believe transparency builds trust, and the wider engineering community benefits from shared lessons. A public post-mortem is needed when an incident:
Results in permanent impact on user data (such as data loss)
Directly disrupts customers' own services (such as SDK bugs breaking customer sites)
Results in extended unavailability of PostHog services for customers
Process
Public post-mortems go through an internal review before being published. This isn't to hide anything – we're committed to being transparent about what happened and why. The review exists to make sure we don't accidentally expose sensitive information (such as customer data, internal credentials, or infrastructure details that could be exploited) and to ensure the post-mortem is clear and useful to readers.
Write the internal post-mortem first – Complete the normal post-mortem process above. The internal version is where you can freely discuss all details without worrying about what's safe to share publicly.
Get review – Have the draft reviewed by relevant stakeholders. Focus on making sure the root cause, impact, and remediation are explained clearly enough to be useful, while removing anything that could compromise security or expose customer information.
Publish – Once approved, open a PR against posthog.com adding the post-mortem to contents/handbook/company/post-mortems/ and update the list on the public post-mortems page.
Every week, one person in each engineering team is designated the Support Hero. If this is you this week, congratulations!
As Support Hero, your job is to investigate and resolve issues reported by customers. A single case of suspicious data or a show-stopping bug can really undermine one's confidence in a data product, so it's important that we get to the bottom of all issues.
One of the many awesome things about PostHog is that support is dealt with by engineers and they ship fixes and improvements in real-time when you contact them. It is impossible to overstate how valuable it is for customers when they ask a question and get a shipped feature within a day.
You'll see some teams using a term of endearment for Support Hero, examples being "Infra Hero" or… "Luigi". Don't ask – we don't know.
Our support engineers, in the , triage tickets for most teams. They will resolve tickets if possible, and escalate to the engineering team responsible if they need further help.
The schedules consist of contiguous blocks, but that definitely doesn't mean working 24/7 – you should just work your normal hours.
What if I'm scheduled for a week when I won't be available?
Swap with a teammate in advance! Find a volunteer by asking in Slack, then use incident.io schedule overrides. You can trade whole weeks, but also just specific days. Remember not to alter the rotation's core order, as that's an easy way to accidentally shift the schedule for everyone.
What do I do as Support Hero?
Each engineering team has its own list of tickets in PostHog support. Your view will be bookmarked in your #support-<team-name> channel for easy access.
Your job is simple: ship features and fixes, resolve ticket after ticket from your team's list, and respond to open-source PRs assigned to your team.
There are four sources of tickets:
In-app bug reports/feedback/support tickets sent from the Support panel.
If you're ever unsure how to handle a particular ticket, need advice on wording, or anything's unclear, ping #team-support — we're always happy to help!
End of your rotation
By the end of your rotation you should make sure that every ticket in your view tagged top_20, churn_risk, or plan_enterprise is either resolved or handed over to the next support hero — as a minimum.
When handing over, assign any tickets you want the next hero to pick up to your team's role in PostHog Support. Anything left assigned to you personally won't show up in your team's view, so it won't reach them.
Shipping features
Some tickets ask for new features. If the feature is useful for users matching our ICP, then decide whether to just build it. Otherwise, create a feature request issue in GitHub or +1 on an existing one – you can then send a link to the user, giving them a way of tracking progress. Also make sure to let the know, since they will track feature requests for paying customers.
Sometimes a feature already exists, but a user doesn't know about it or how to use it. In this case, you should either send them a link to the relevant docs page or update the docs to make it clearer.
Fixing bugs
Others tickets report bugs or suspected bugs. Get to the bottom of each one - you never know what you'll find. If the issue decidedly affects only that one user under one-in-a-million circumstances, it might not be worth fixing. But if it's far-reaching, a proper fix is in order. And then there are "bugs" which turn out to be pure cases of confusing UX. Try to improve these too.
If not much is happening, feel free to do feature work – but in the case of a backlog in PostHog Support, drop other things and roll up your sleeves. When you're Support Hero, supporting users comes first.
It might be an intense week, but you're also going to solve so many real problems, and that feels great.
Papercuts
Check the #papercuts Slack channel during your rotation and pick up any reports that relate to your team's area. For each one, pick one of the following:
Reply to the reporter acknowledging the papercut, then either get a fix shipped or open a GitHub issue to track it if it needs more scoping. How you get the fix out is up to you – prompting PostHog Desktop is often the fastest path, but feel free to fix it however you like.
React with ❌ to reject the papercut (for example, if the behavior is intentional). A brief reply explaining why is appreciated.
React with ✅ once you've shipped a fix or improvement.
Papercuts are also routed to the Signals inbox, so before you start work, check whether an auto-generated PR is already waiting – it may save you most of the effort.
Security findings
Vulnerabilities in code your team owns are also yours to fix, and the support hero is the person who picks them up alongside the normal support workload. Give critical and high severity findings the same priority as a customer ticket, and fix them as soon as you can.
Findings come from the AI pentesting services we use, currently Veria Labs and Parameter. They are triaged automatically, and the true positives go to the product team that owns the code. Your team's findings are collected in SecurityHog, and your team also gets a weekly post in its Slack channel that lists them.
The support hero is the default owner, but each team decides how to split the work. For example, a team with a lot of findings can share them across more people. Set the Assignee field on each finding in SecurityHog so the team can see who works on it.
Work through the findings for your team during your rotation. If you cannot finish one, hand it over to the next support hero. If you are not sure how serious a finding is, or how to fix it, ask in #team-security.
Responding to external PRs
When capacity allows, the support hero serves as the first point of contact for external (open-source) PRs that affect your team's product. While we want to be good open-source citizens, customer support always takes priority — if you're dealing with a heavy support load, it's acceptable for PR reviews to be delayed or handled more briefly.
How external PRs are assigned
External PRs typically reach your team through one of two methods:
CODEOWNERS automation: If your team has CODEOWNERS configured, PRs modifying your team's files will automatically be assigned to your team
Manual assignment: For teams without CODEOWNERS set up, external PRs may be manually assigned to your team handle by other engineers who spot them
Best practices for handling external PRs
These are guidelines to aim for when you have bandwidth after handling customer support. Adapt them based on your workload:
Initial response (when possible)
Acknowledge the PR with a thank you comment when you can
Quick check: Are there obvious blockers like failed tests or merge conflicts? If so, politely ask the contributor to address them first
If your support queue is overwhelming, it's okay to delay this or keep it brief
Review approach
Be welcoming and constructive - contributors are volunteering their time
Provide actionable feedback when you have time for a thorough review
Consider the effort/reward tradeoff - some PRs may need more work than they're worth
It's better to politely decline quickly than to let a PR sit without feedback for weeks
Communication tips
Set realistic expectations based on your current workload
Remember that external contributors can't ping us directly like teammates can
If you know you won't get to a PR this week, a quick "Thanks for the contribution! Our team is currently focused on customer issues but we'll review this when we can" is better than silence
Common blockers to address upfront (when doing a full review)
Ask contributors to respond to Greptile feedback before your review
Require merge conflicts to be resolved before reviewing
Ensure tests are passing (or understand why they're not)
Check that the PR follows our existing code patterns and conventions
When to escalate or defer
If the PR touches critical infrastructure or security-sensitive code
If you're unsure about the product implications
If your support load is too high to give it proper attention
If a PR requires extensive back-and-forth that you don't have bandwidth for
Consider rewarding with merch
A PR doesn't need to be merged to be reward-able
Someone took time to care about PostHog and merch is a great way to say thank you
Managing expectations
The reality is that support hero weeks vary significantly in intensity across teams and time periods. Some weeks you might have capacity to thoroughly review several PRs; other weeks, you might barely have time to acknowledge them. That's okay. The goal is to engage with external contributions in good faith within your available bandwidth, not to maintain a perfect response rate at the expense of customer support or your well-being.
If you find yourself overwhelmed, remember:
Customer issues come first
A brief acknowledgment is better than nothing
It's acceptable to hand off complex PRs to the next support hero
Teams aren't expected to handle unlimited PRs
The key principle: We want to be responsive to our open-source community when we can, but not at the cost of our primary support responsibilities or team sustainability.
Community questions and Discord
Users on the free plan get community support only. Because of this, many questions and opinions about your product area appear on Community questions and in Discord, and not in PostHog Support.
This is not a ticket queue, and it is not a duty. Nobody has to reply. Look at it as a source of product feedback: it shows you what users ask, what confuses them, and what they say about your product area, in real time.
If you have time between tickets, read your team's community posts. The goal is to spend less than 30 minutes a week. Most teams get one or two questions a week, sometimes none.
Where to find posts relevant to your team
Each post topic is subscribed to one or more teams. When a user makes a post, the post goes to the Slack channel of each subscribed team.
To see which topics are mapped to your team, go to community alerts. Use that page also to find topics that have no team, and teams that have no Slack channel. A team with no Slack channel gets nothing, even when it is subscribed to a topic.
What is a good reply?
A reply from PostHog AI or from another community member is frequently the correct answer for the user. When this is true, no need to reply—you can upvote the existing reply. If you want to chime in with something, check these guidelines for answering questions.
Paid tickets always have a higher priority than community questions.
What about SDK support?
The SDK Support Hero rotation is owned by the . See the dedicated SDK support rotation page for details on how the rotation works, including how to prioritize time and handle mobile SDK issues.
Tips for being a great Support Hero
Don't ask users to do work that you can do!
If folks are asking us for help, then we know the product already didn't meet their needs. Asking them to do leg-work that we could do is adding insult to injury.
For example don't ask them what version of posthog-js they're using or what their posthog config is when you can find out for yourself. Or visit their website and check the console instead of asking them if they had any errors.
If you do then have to ask them to do something, make sure you explain why you need it and what you're going to do with it.
How do I communicate?
There are two valid modes (which overlap!)
excited, like a labrador puppy, to discover a new way to improve the product
clinical and clear
Excited like a labrador puppy
The first is great for when you're talking to someone with feedback or who doesn't seem frustrated. It's important because every single support interaction is an opportunity to ship a fix or an improvement. And the excitement is how we show enough interest to properly hear the feedback.
example: "You can't do that right now, but it sounds super useful. Out of interest what does it unlock for you?"
Clinical and clear
The second is great for when the issue is tricky or the customer seems frustrated. Sometimes this goes as far as communicating in bullet points instead of paragraphs. When something isn't working the person might (quite rightly) have low tolerance for a support interaction.
example: "Ah, I see what you mean, that's not ideal! Sorry. I'll dig in to that now and let you know what I find by the end of tomorrow."
General tone
As an engineer, when answering a question, your first instinct is to give them an answer as quickly as possible. That means we often forget pleasantries, or will ignore a question until we've found the answer. So, the following guidelines:
Always respond to a question within a reasonable timeframe during your working day. Our SLAs are explained here, but you should always try to respond to tickets quickly.
If you're ready to look into the issue, and you think it might take a while/require a fix, just mention that and say you'll get back to them
If you have no idea how to answer or fix their issue, @mention someone in a public Slack channel who does
They need to know we've understood them. And have a clear picture of what their onward journey is. Are they waiting for us? How Long? Or - are we waiting for them? what for?
Start your response with Hey [insert name], ... and make sure you're polite, not everyone you talk to is an engineer and as accepting of terse messages
If they expressed frustration, acknowledging it ("Sorry for the confusion", "Apologies for the trouble" etc.) can earn goodwill quickly.
Be sure to thank them for reporting problems, giving feedback, creating issues, PRs, etc.
Even if you're using the support portal think about whether they'll see the message in Slack or email. A Slack message that reads like an email seems weirdly formal.
Follow up!
Housekeeping. Once a customer issue/question has been addressed, resolve the ticket in PostHog Support to make it easy to identify outstanding conversations.
If a user has been particularly helpful, such as raising a security or bug report, feel free to offer a small credit for the merch store.
If you have any questions about how or when to communicate with users, you can always ask in #team-support for help!
Setting your team up for support
If you're a support hero, there are a few things to make sure are in place so that support works as intended for your team:
Your team name and team membership are correct on the teams page.
You have a Slack channel named #team-<team-name>, in exactly the same format as your team name on the teams page.
You have a Slack channel named #support-<team-name>, in exactly the same format as your team name on the teams page.
The PostHog Slack app is in your #support-<team-name> channel (invite it with /invite @PostHog) — without it, ticket notifications can't be posted there.
Configure a Slack user group for the team's Support Hero: <team> schedule in incident.io. This group always contains the person who is currently on call, so you can mention the current Support Hero from any Slack channel.
Open the schedule, then click Connect Slack group.
Select Create new.
Remove the On call prefix (including the trailing space) from the generated group name and the on-call- prefix from its handle. This keeps it consistent with the other on-call groups. For example, use Support Hero: Query Performance and support-hero-query-performance, not On call Support Hero: Query Performance and on-call-support-hero-query-performance.
Save the group. If the Save button is disabled, incident.io shows who has permission to make this change. Ask one of those people to complete the setup.
A couple more things to make sure of (these may happen magically in future):
Your team shows up with the correct name and membership in roles settings.
You have a view for your team in PostHog Support, and that view is bookmarked in your #support-<team-name> channel.
The oversees the process of completing their website profile so it's ready to go when they start. (The one exception is that the team lead or the Ops team will add the team member to the small team's page which will automatically add the person to the team page the next time the website is rebuilt.)
When a new team member is created in Deel with their new company email, a community profile is automatically generated for them. It should populate with info like their name, role, and start date.
One thing it doesn't automatically add is their profile photo. Here's the typical process for completing their profile, which is handled by the .
Add the team member's photo
Watch for alerts that the new team member has been created (in the #alerts-deel private Slack channel). It's always worth keeping an eye on new hire announcements in #general in case the webhook doesn't fire.
Verify their preferred name in their onboarding issue in posthog/company-internal, as their legal name automatically gets set by default based on the information added to Deel.
Grab their photo from their LinkedIn or other easily publicly-available source. If they've already started, they may have also uploaded a photo to Slack.
Copy photo to clipboard, visit remove.bg, paste the image, and download the resulting photo.
Crop to square, size similarly to existing images, and make sure the arm on the left side of the photo isn't cropped.
Optimize the image
Add to team member's profile
If the person hasn't started yet, this can be done in Strapi
If the person has started, webmasters can add it via the person's community profile on PostHog.com
Set a complementary background color that isn't overly used by other members in the small team
Set their location field to a friendly name or major metropolis if in the US (like "San Francisco, CA") or a major international city (like "Barcelona, Spain") when possible.
Also add the team member's _original_ photo to the Team portraits Figma file where our contract illustrator will pick it up to draw the illustrated version.
Once notified in #portraits that the illustration is ready...
After illustration is drawn...
Ensure proper sizing and positioning in Figma
Export at @2x to PNG
Optimize the image
Add to team member's profile via their profile page
Move the team member's photo to the live page in the Figma file
Notes
If the new team member lives in a country we haven't hired from before, we'll need to add a new flag sticker for their country. Ask the in the #posthogdotcom Slack channel to do this.
We'll use the team member's public photo by default
They have an option to ask the to use a different photo, but if they don't, we'll roll with the public photo
The PostHog API docs are generated using drf-spectacular. It looks at the Django models and djangorestframework serializers.
Note: We don't automatically add new API endpoints to the sidebar. You need to add those to src/navs/index.js
You can add a help_text="Field that does x" attribute to any Model or Serializer field to help users understand what a specific field is used for:
class Insight(models.Model):
last_refresh: models.DateTimeField = models.DateTimeField(blank=True, null=True, help_text="When the cache for the result of this insight was last refreshed.")
class InsightSerializer(TaggedItemSerializerMixin, InsightBasicSerializer):
filters_hash = serializers.CharField(
read_only=True,
help_text="A hash of the filters that generate this insight.",
)
To add a description to the top of a page, add a comment to the viewset class:
class InsightViewSet(TaggedItemViewSetMixin, StructuredViewSetMixin, viewsets.ModelViewSet):
"""
Stores saved insights along with their entire configuration options. Saved insights can be stored as standalone
reports or part of a dashboard.
"""
To check what any changes will roughly look like locally, you can go to http://127.0.0.1:8000/api/schema/redoc/.
To add a description to a specific endpoint, add an MDX file (named after the endpoint ID's name) to the corresponding folder its page would belong to. Then, the content in the MDX file will only appear under the specified endpoint. This is like our MDX setup, except the file name will determine which endpoint the MDX contents appear on.
For example, to add a description to the "list annotations" endpoint, you'd create a new file: contents/docs/api/annotations/annotations_list.mdx
Whatever you add to that file will appear under that endpoint only.
Image: API endpoint description
Insights serializer
The serializer for insight lives here. Each time an insight gets created we check it against these serializers, and we'll send an error to Sentry (but not the user) if it doesn't match, to ensure the API docs are up to date.
Documenting custom endpoints
If you have an @action endpoint or a custom endpoint (that doesn't use DRF) you can still document by providing a serializer for the request and response.
from drf_spectacular.utils import OpenApiResponse
from posthog.api.documentation import extend_schema
@extend_schema(
request=FunnelSerializer,
responses=OpenApiResponse(
response=FunnelStepsResultsSerializer,
description="Note, if funnel_viz_type is set the response will be different.",
),
methods=["POST"],
tags=["funnel"],
operation_id="Funnels",
)
@action(methods=["GET", "POST"], detail=False)
def funnel(self, request: request.Request, *args: Any, **kwargs: Any) -> Response:
Testing API docs locally
To test or develop the API docs locally, you need to create a personal API key (see top of this page) and then export it before running gatsby, in the same terminal window:
We use Cloudinary for asset management (image and video uploads), mainly to reduce website build times (as each image hosted within the repo has to get processed on each build). Offloading assets to Cloudinary saves time and resources.
Uploading assets via the PostHog.com uploader (recommended)
Sign into your PostHog.com account via profile icon in top right corner
Click the account menu, then under Moderator tools choose Upload media
Image: Profile
Open a folder, select, drag, or paste media to upload. This supports images, gifs, and videos. Cloudinary provides optimized links for images, but you'll want to optimize other formats before uploading.
Image: Upload
Copy the file URL and insert wherever you need it
Uploading assets using the Cloudinary website (don't use this option)
_You shouldn't need to login to Cloudinary directly. Use the website uploader instead._
Change the status of an existing roadmap or WIP entry to "Complete"
Create a new changelog entry on the changelog page.
Both options are available when you're signed into posthog.com as a moderator.
For more details on the publishing process, check out the How to publish changelog handbook page by the .
Fill out the proper paperwork
Make sure all fields are filled out correctly before creating an entry.
Date
Set the date to the feature's release date. If updating from a previous roadmap or WIP entry, change the date to the actual release date (rather the date where the team started working on the feature).
Team and author
Select the team that is responsible for the change, and choose the author of the feature. If there's no individual lead on the feature or update, set the author to the team lead.
Categorization
Select the product or product area that the change is relevant to, and set the type of update. These can be used on the front end to filter down to a subset of changes.
Title and description
Be succinct with the title. Check the format of existing entries for inspiration.
Options
The Show on homepage option aggregates the entry to the _"We ship weirdly fast"_ calendar on the homepage. Only select this option if the milestone is impressive enough to be remembered years from now. The point of the calendar is to show the frequency of shipping big features, not to highlight every single update.
Social sharing
The has created an image generator that takes the information from the changelog entry and creates a square image for sharing on social media. Read the blog post to learn how it works.
The customization options are designed to allow you to format the copy and image so it looks as good as it can. If you need suggestions or aren't sure if your changelog image meets our quality standards, don't hesitate to post in #team-website-and-vibes for a second opinion.
Applying to get your jobs listed? The Cool Tech Jobs board exists to help people find jobs at companies with similar perks and culture to PostHog, and a strong engineer-led environment. Applications are approved only at our discretion and moderation can take up to 48 hours. If you have a question about an application, please contact our support team.
Create a company/jobs:
Non-moderator flow
Visit /cool-tech-jobs
Click "Apply to get your jobs listed here." If you're not already signed in, you'll be prompted to sign in
Read the disclaimer and click next
Fill out the required fields (non-moderators have an additional field - "Why is your company cool?")
Click "Submit application"
A message is fired off in the #cool-tech-jobs Slack channel with the details of the application
A moderator approves and publishes the company from /cool-tech-jobs
Moderator flow
Visit /cool-tech-jobs
Click "Add a company"
From here, you can either continue with a pending company (one that has a pending application) or create a company from scratch
Fill out the required fields. If continuing from a pending company, verify the company details are correct before continuing
Click "Publish company"
When a company is created, its jobs are automatically scraped based on the job board URL/slug provided. If no jobs are found, the company is still created (appears semi-transparent for moderators), but a warning message appears that suggests verifying the job board URL.
Edit a company
Login to PostHog.com as a moderator
Navigate to /cool-tech-jobs
Click “Edit” under the desired company
Fill out the fields in the side modal
Click Update company
Jobs will be re-scraped when a company is edited.
Delete a company
Login to PostHog.com as a moderator
Navigate to /cool-tech-jobs
Click “Delete” under the desired company
Confirm that you want to delete that company
All jobs associated with the deleted company will be deleted along with the original company record.
Company fields
Company name
Company website URL - Used for the “Learn more” link
Job board type (Ashby, Greenhouse, Other) - If “Other” is selected, a custom scraper will need to be built. When the company is published, it will be hidden as no jobs will be scraped.
Job board URL (if Job board type is set to “Other”) - we’ll use this to build a custom scraper
Job board slug (if Job board type is not “Other”) - the job board’s slug. This is automatically created as you type the company name, as these usually mirror each other. Must be unique and is checked for uniqueness as you type.
Company perks
Company logos - SVG/PNG only
Unless required conditionally (job board URL/slug), every company field is required.
Scraping
Jobs are scraped hourly based on the provided job board URL/slug. Jobs are individually checked for freshness hourly. If a job URL 404s, it is deleted.
You can contribute to the PostHog documentation, handbook, and blog in two ways:
Create a pull request in GitHub for any page that has an Edit this page link on it. In this situation you must edit the page using the GitHub web editor interface. This method is suitable for text-only edits and basic file manipulation, such as renaming.
Run the posthog.com website in development and make changes there by creating a branch of the master codebase, committing changes to that branch and raising a pull request to merge those changes. This is the recommended method as it allows you to quickly preview your changes, as well as perform more complex changes easily.
Below, we'll explain the two options for option two.
Click the Code button, then the Codespaces tab, then under the ... menu, choose New with options...
Image: New with options...
Under Machine type, choose 4-core.
Image: Configure machine type
When the repo opens in Codespaces, it will install some things automatically.
Image: Codespaces installing dependencies
When completed, press any key.
In terminal, type pnpm install && pnpm start and hit [Enter].
Image: pnpm start
This will take a while. The last step of the process is "Building development bundle" which will take a few minutes on its own.
You may see a dialog that says, "Your application running on port 8001 is available." Don't be enticed by the big green button quite yet.
Once you see <code><span class="text-green">success</span> Writing page-data.json files...</code>, you can click the green Open in browser button which will open the site at http://localhost:8001.
You can also click the Ports tab to access the URL where you can preview the site. Cmd + click the URL seen here.
Image: port
Committing and pushing changes
Use the built-in Git tab in VS Code to commit and push your changes.
From the Git source control ... menu, choose Checkout to... to create a new branch.
Image: Checkout to...
Type a new branch name and press enter.
Image: Branch name
Now you can commit changes to your new branch. Type a commit message and use Cmd + Enter (or push the big green button).
Image: Commit message
If you see the dialog below, choose Always to always stage all files you've changed. (Otherwise, you'll need to hit the + button next to each file you want to commit.)
Image: Stage all
Now that your changes are committed, it's time to publish them to GitHub.
Image: Publish changes
Note: After finishing changes on your branch, be sure to switch back to master so you don't inadvertently make future changes to your current branch.
Image: Checkout to master > Image: Switch to master
Stopping the server
Place your cursor into Terminal and type Cmd+C to stop the server.
In the bottom left corner of the window, click Codespaces: [your codespace name], then Stop current codespace.
Notes
If you plan on using this codespace frequently, disable Auto-delete codespace in the ... menu under the Code > Codespaces dropdown in the repo.
Option 2: Editing posthog.com locally
Before you begin
In order to run the PostHog website locally, you need the following installed:
The posthog.com codebase is on GitHub at https://github.com/PostHog/posthog.com. To work on it locally, first you need to clone it to your disk:
via the command line
You can clone the codebase from the command line using the following command:
git clone git@github.com:PostHog/posthog.com.git
via GitHub Desktop
You can also clone the repository with GitHub Desktop installed, from the posthog.com repository page, click the Code button and select Open with GitHub Desktop from the dropdown that appears.
Image: Open in GitHub Desktop
You will then be prompted by the browser to confirm if you want to open the GitHub Desktop application. Select the affirmative action that has text such as Open GitHub Desktop.
Once GitHub Desktop has opened you will be prompted to confirm the repository that is being cloned and the location on disk where you wish the code to be stored.
Image: GitHub Desktop clone to dialog
Click Clone to clone the posthog.com repository to your local disk.
Image: GitHub Desktop cloning to disk
Once the clone has completed the GitHub Desktop interface will change to the following:
Image: GitHub Desktop cloned successfully
To view the code for the website click Open in Visual Studio Code. Dialogs may appear around permissions and trust as you open Visual Studio Code.
Once you have Visual Studio Code open, select the Terminal menu option. Within the dropdown select New Terminal. This will open a new terminal window within Visual Studio Code:
Image: Visual Studio Code terminal
Don't worry! We only need to run a few commands in the command line.
Running posthog.com locally
If you're using an Apple Silicon Mac (M1+) then you'll need to run the following commands before using pnpm:
rm -rf ./node_modules
brew install vips
Type the following into the command line and press return:
pnpm install
This installs the dependency packages used by posthog.com. This may take a few minutes.
After initial setup, use the following command to start the development server:
pnpm install && pnpm start
This runs the local clone of the website, which you can use to preview changes you make before pushing them live. It takes a bit of time for some file processing and compilation to take place, but once it's completed you can access the locally running version of posthog.com via by visiting http://localhost:8001 in your web browser.
Any time you want to preview changes you are making to the local version of the website, all you have to do is run the pnpm start again, wait for the command to finish running and then open http://localhost:8001 in your web browser.
Troubleshooting
If the server fails to start, the first troubleshooting step is to clear cache. You can do this (and start the server again) by running:
All pages in src/pages/ (product pages, pricing, etc.)
Everything else (apps, CDP, templates, jobs, API docs, SDK references, pagination/category/tag pages) won't exist - they'll 404. Next/previous navigation links and GitHub data for roadmaps/jobs will also be absent. Sourcemap generation is disabled.
PR preview deployments (Cloudflare Pages)
Pull request previews on Cloudflare Pages use the same minimal build as above: the workflow sets GATSBY_MINIMAL=true (see .github/workflows/deploy-preview.yml). That keeps preview builds fast.
Building without cache: If a preview build is broken due to a stale Gatsby cache, add the no-cache label to the PR. This skips cache restore and runs a clean build from scratch. Remove the label when you're done to go back to cached builds.
Implications for content authors:
Post category indexes are not built — Routes like /tutorials, /blog, and /posts are not generated in previews. Opening them can fail or show a broken page (for example a blank or error screen in the site shell). This is expected.
Individual posts and docs still build — Preview the change by opening the direct URL to the MDX page (e.g. /tutorials/your-post-slug, /blog/your-post-slug).
Search and listing data — Post listings and site search rely on full production builds and indexing (e.g. Algolia). Content from a branch typically will not appear in search on the preview until it is merged to master and the production site is built.
Environment variables
Our website uses various APIs to pull in data from sites like GitHub (for contributors) and Ashby (our applicant tracking system). Without setting these environment variables, you may see various errors when building the site. Most of these errors are dismissible, and you can continue to edit the website.
If you need a specific environment development, ask in #posthogdotcom.
Finding the content to edit
Once you have cloned the repo, the contents/ directory contains a few key areas:
docs/ = all of the documentation for PostHog's platform
handbook/ = the PostHog company handbook
blog/ = our blog posts
Inside each of these are a series of markdown files for you to edit.
Posts and blog filtering
There are two ways to filter posts by tag:
Query param — Add a post_tags query param to the URL, e.g., /posts?post_tags=Comparisons. This works on the main posts listing and allows saving/sharing filtered URLs.
Static tag pages — For SEO purposes, we generate static pages at /{category}/{tag}, e.g., /blog/session-replay. These are generated at build time in gatsby/createPages.ts.
Hidden from index
Some categories and tags are intentionally hidden from the main posts index view. They still appear when you filter directly to that category or tag.
Categories hidden from index:customers, spotlight, changelog, comparisons, notes, repost
Tags hidden from index:Comparisons
Posts can also set hideFromIndex: true in their frontmatter to be excluded.
These exclusions are defined in src/components/Edition/Posts.tsx and src/templates/BlogPost.tsx.
Making edits
Creating a new Git branch
When editing locally, changes should be made on a new Git branch. Branches should be given an "at a glance" informative name. For example, posthog-website-contribution.
via the command line
You can create a new Git branch from the command line by running:
git checkout -b [new-branch-name]
For example:
git checkout -b posthog-website-contribution
via GitHub Desktop
You can also create a new branch in GitHub Desktop by selecting the dropdown next to the Current Branch name and clicking New Branch.
Image: GitHub Desktop - new branch dropdown
Then, in the dialog that follows, entering the new branch name.
Image: GitHub Desktop - new branch dialog
Once you have a new branch, you can make changes.
Markdown details
Frontmatter
Most PostHog pages utilize frontmatter as a way of providing additional data to the page. Available frontmatter varies based on the template the page uses. Templates are determined based on the folder the file resides in:
Blog
Markdown files located in /contents/blog`
---
date: 2021-11-16
title: The state of plugins on PostHog
rootPage: /blog
author: ["yakko-majuri"]
featuredVideo: https://www.youtube-nocookie.com/embed/TCyCryTiTbQ
featuredImage: https://res.cloudinary.com/dmukukwp6/image/upload/posthog.com/contents/images/blog/running-content.png
featuredImageType: full
category: Guides
tags: ["Using PostHog", "Privacy"]
seo: {
metaTitle: Overview of PostHog Plugins
metaDescription: Learn about the current state of plugins on PostHog and get valuable insights into their functionality and performance.
}
---
date: the date the blog was posted
title: the title that appears at the top of the blog post and on the blog listing page
rootPage: necessary for listing all blog posts on /blog. should always be set to /blog
author: the author(s) of the post. correlates to your handle located in /src/data/authors.json
featuredVideo: the iframe src of the video that appears at the top of the post. replaces the featured image on post pages.
featuredImage: the Cloudinary URL of the image that appears at the top of the post and on the blog listing page
featuredImageType: standard | full - determines the width of the featured image on the blog post
category: the broader category the post belongs to. one of the following:
-
tags: the more specific tag(s) the post belongs to. an array containing any number of the following:
-
seo: object containing SEO metadata:
metaTitle: String
metaDescription: String
Tutorials
Markdown files located in /contents/tutorials
---
date: 2022-02-14
title: How to filter out internal users
author: ['joe-martin']
featuredTutorial: false
featuredVideo: https://www.youtube-nocookie.com/embed/2bptTniYPGc
tags: ['filters', 'settings']
---
date: the date the tutorial was posted
title: the title that appears at the top of the tutorial and on the tutorial listing page
author: the author(s) of the tutorial. Correlates to your handle located in /src/data/authors.json
featuredTutorial: determines if tutorial should be featured on the homepage
featuredVideo: the iframe src of the video that appears at the top of the tutorial
featuredImage: the Cloudinary URL of the image that appears at the top of the tutorial and on the tutorial listing page
tags: the tag(s) the tutorial belongs to. an array containing any number of the following:
-
seo: object containing SEO metadata:
metaTitle: String
metaDescription: String
Docs & Handbook
Markdown files located in /contents/docs and /contents/handbook
---
title: Contribute to the website: documentation, handbook, and blog
---
title: the title that appears at the top of the handbook / doc page
seo: object containing SEO metadata:
metaTitle: String
metaDescription: String
Comparison pages
Create a table on a "PostHog vs..." page with the following components. (You can see examples of how this is used in this pull request.)
Import the components at the top of the post content (after frontmatter):
Create a table like:
In ComparisonRow:
Values for column1 and column2 can be: {true} | {false} | "Text string"
feature is required but description can be omitted (only if not using that column for the entire table)
It's best to create commits that are focused on one specific area. For example, create one commit for textual changes and another for functional ones. Another example is creating a commit for changes to a section of the handbook and a different commit for updates to the documentation. This helps the pull request review process and also means specific commits can be cherry picked.
Once all the files that have been changed are staged, you can perform the commit:
git commit -m '[short commit message]'
For example:
git commit -m 'Adding details on how to commit'
via GitHub Desktop
Files that have been changed can be viewed within GitHub Desktop along with a diff of the specific change.
Image: Viewing changes in GitHub Desktop
Select the files that you want to be part of the commit by ensuring the checkbox to the left of the file is checked within GitHub Desktop. Then, write a short descriptive commit message and click the Commit to... button.
Image: Making a commit in GitHub Desktop
Push changes to GitHub
In order to request that the changes you have made are merged into the main website branch you must first push them to GitHub.
via the command line
git push origin [branch-name]
For example:
git push origin posthog-website-contribution
When this is done, the command line will show output similar to the following:
posthog-website-contribution $ git push origin posthog-website-contribution
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'posthog-website-contribution' on GitHub by visiting:
remote: https://github.com/PostHog/posthog.com/pull/new/posthog-website-contribution
remote:
To github.com:PostHog/posthog.com.git
* [new branch] posthog-website-contribution -> posthog-website-contribution
This output tells you that you can create a pull request by visiting a link. In the case above, the link is https://github.com/PostHog/posthog.com/pull/new/posthog-website-contribution. Follow the link to complete your pull request.
via GitHub Desktop
Once you have committed the changes you want to push to GitHub, click the Push origin button.
Image: Push to origin from GitHub Desktop
Create a pull request
Create a pull request to request that your changes be merged into the main branch of the repository.
via the command line
Navigate to the link shown when you push your branch to GitHub. For example, https://github.com/PostHog/posthog.com/pull/new/posthog-website-contribution shown below:
posthog-website-contribution $ git push origin posthog-website-contribution
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'posthog-website-contribution' on GitHub by visiting:
remote: https://github.com/PostHog/posthog.com/pull/new/posthog-website-contribution
remote:
To github.com:PostHog/posthog.com.git
* [new branch] posthog-website-contribution -> posthog-website-contribution
via GitHub Desktop
With the branch published, click the Create pull request button.
Image: pull request from GitHub Desktop
This will open up a page on github.com in your default web browser.
If you are pushing to an existing branch, navigate to the posthog.com repo and switch to the new branch using the dropdown:
Image: GitHub branch switcher
Then, open the Contribute dropdown and click the Open pull request button.
Make the pull request title a descriptive name and complete the detail requested in the body.
If you know who you would like to review the pull request, select them in the Reviewers dropdown.
Preview branch
After a series of checks are run (to ensure nothing in your pull request breaks the website), Vercel will generate a preview link available in the Vercel bot comment. This includes all of your changes, so you can preview before your pull request is merged.
An initial build can take up to 50 minutes to run. After the initial build, subsequent builds should complete in under ~15 minutes. We're limited to two concurrent builds, so if there's a backlog, this process can take longer.
Because Vercel charges per seat, we don't automatically invite all team members to our Vercel account. If your build fails, you can run pnpm build locally to see what's erroring out. If nothing is erroring locally, it's likely the build timed out in Vercel. The Website & Docs team monitors for failed builds, so they'll re-run it for you. If the build is urgent, give a shout in #team-website-and-docs and someone with Vercel access can trigger a rebuild for you.
Image: Preview branch
Note: Checks are run automatically for PostHog org members and previous contributors. First time contributors will require authorization for checks to be run by a PostHog org member.
Deployment
To get changes into production, the website deploys automatically from master. The build takes up to an hour, but can be delayed if other preview builds are in the queue.
Product interest tracking for onboarding
We track which products users have shown interest in by visiting product landing pages or docs. This data is stored using PostHog's cookie_persisted_properties feature, making it available across all posthog.com subdomains (including app.posthog.com) for onboarding personalization.
How it works
When a user visits a product-specific page (like /product-analytics or /docs/session-replay), we record that product's slug using posthog.register() with the property prod_interest. This property is configured in cookie_persisted_properties in gatsby/onPreBoostrap.ts, which means it gets stored in a cross-subdomain cookie automatically.
To read the interests, we use posthog.get_property('prod_interest') which returns an array of product slugs like ["product-analytics", "session-replay"].
We always store the most recent interests last in the array.
Code structure
The tracking is implemented in:
src/lib/productInterest.ts - Core utilities using posthog.get_property() and posthog.register()
src/hooks/useProductInterest.ts - React hooks for tracking
src/components/Products/Slides/SlidesTemplate.tsx - Integration for product landing pages
src/templates/Handbook.tsx - Integration for docs pages
Reading interests on app.posthog.com
Since this uses PostHog's built-in cookie persistence, you can read the interests on any subdomain where PostHog is initialized:
Everything is usually automatically handled because our website is well-structured but if you want to start tracking interest for new products you'll need to add a new entry to PRODUCT_SLUGS in src/lib/productInterest.ts
Acknowledgements
This website is based on Gatsby and is hosted with Vercel.
PostHog.com is built and maintained in-house by the . You've probably never seen a Gatsby.js site like this before. Eli Kinsey is the mastermind behind how the site is structured.
`` – the chrome for each app and where the content renders
``
` loads and `.
This contains the window's top bar with the minimize, maximize, and close buttons. It also supports window resizing.
Inside here is where the contents of each app renders
The apps
Each "app" is simply a page like a normal Gatsby site. There are a handful of apps:
`` – used for all long-form content like the docs, handbook, blog
`` – a WYSIWYG page editor
`` – an OS-style file explorer
`` – an email-like app
`` – a slide deck
Each app can reference shared components like `` which contains the necessary navigational elements (like the back button, search, and filters).
Let's look at a product page to see how it uses the `` template.
Example: posthog.com/session-replay
This page (/src/pages/session-replay/index.tsx) includes two critical pieces:
`` – the views where the content will display
Defines the PRODUCT_HANDLE
Specifies which slides should appear in this presentation using createSlideConfig
` loads up all the various templates needed (like , , ) and sources the content using the useProduct` hook.
useProduct hook
Each product's data is defined in a JSON file like:
/src/hooks/productData/session_replay.tsx
When the session_replay handle is passed into useProduct, it looks up the product's data like:
icon
color
category
SEO data
screenshots array
feature customers
features array
feature comparison chart
etcc
Note: The maintains a billing API that contains pricing tiers and entitlements. This is how pricing data and usage tiers stay in sync between the website and product. The plan is to eventually move the product data into the billing API so there's a single source of truth for every product.
---
Services we use
| Service | Purpose | | ------------- | ------------------------------------------------------ | | Vercel | Hosting | | Gatsby | Static site framework | | GitHub | Source code repository | | Ashby (API) | Applicant tracking system | | Algolia (API) | Site search | | Strapi | Headless CMS for community profiles and changelog data | | PostHog | Analytics, feature flags | | Inkeep | AI-powered community answers |
Image: Diagram of PostHog.com
Website content is stored in two places:
Markdown/MDX files (in the GitHub repo) - _most website content_
The website team is unusual in that ~60% of the PRs we merge are authored by people outside the team - and that's excluding Docs, Blog, and the Handbook. We try hard to balance shipping our own stuff with not blocking others who also rely on the website to do their job. We have set up some light guardrails because we tend to see AI-generated PRs that are either 'wrong' (not enough context to prompt correctly; LLMs just not great yet at the frontend design-y stuff), or fine but very low impact yet take time to review.
There are three ways to get a change into the website, depending on what you're changing.
Adding or changing content? Default to PR
Adding or changing something that's fairly isolated? Use your judgement
Anything else, including bugs? Open an issue
Specific examples below. These are not exhaustive, so don't get hung up on exact wording - ask us if you're not sure!
Content changes: open a PR
Writing or editing a blog post, doc, handbook page, tutorial, customer story, or newsletter.
Rewriting the copy on an existing page, including product and marketing pages.
Page details like the title, tags, featured image, or SEO description.
Adding the page you just wrote to the sidebar.
Adding a redirect when you move a page you own.
Adding a customer story, a customer quote, or a row to a comparison table.
A new page that is for a specific marketing campaign, i.e. doesn't live in the main nav anywhere.
A new Product page where you are following the existing template.
Small changes where you have properly reviewed the output, checked preview, and understand the change.
If you are on a team that regularly works on the website and understand the context of how it works (typically folks on marketing and growth teams), it's usually fine to start with a PR in these cases.
If you aren't and/or your PR is a noscope one line prompt from PostHog Slack without any followup, you're probably in issue territory!
Everything else: open an issue
Any size change that affects the Home or Pricing pages - these are our two most important pages by a long, long way and we very carefully watch metrics there.
Creating or restructuring an existing page that is linked to from the main nav.
Anything visual that affects multiple pages. Layout, spacing, sizes, colors, where things sit on the page.
Anything about how the site behaves. Buttons, menus, dropdowns, windows, forms, search, navigation.
Bugs. Tell us and then let us pick the fix, as it's often not the obvious one LLMs go for (and sometimes there isn't a problem to fix).
Removing or hiding a feature that's already live on the site.
We'll close it and open an issue in its place so the idea doesn't get lost. That's not a comment on the work, nor a lack of gratitude for your effort! The volume of website PRs is well past what the team can provide feedback on, most of them are AI-generated, and when one gets merged that isn't quite right, it comes back to us later as something to fix.
If you think your change is an exception, ask in #team-website before you build it and we'll figure it out with you.
If something's broken
Post in #team-website. A broken pricing page shouldn't wait for triage.
Contributing from outside PostHog
Same split, and thanks for the help! Content PRs are welcome and we'll review them. For anything else, open an issue with the bug report template. We'd much rather talk it through with you than close work you've already done.
You will now be on the settings page for the newly created job.
Custom fields
We use custom fields to connect various data to each job posting. Below is the description and purpose of each.
Teams
Teams is the only required custom field. The value(s) selected determines pineapple preference, objectives, mission, team lead, and which team members appear in the sidebar. If multiple teams are selected, all selected teams will appear as accordions in the sidebar, and the mission and objectives will be hidden.
Timezone(s)
Determines the preferred timezone for the position. If a value exists, it appears under the title.
Repo
Determines which repo to pull GitHub issues from if using the Issues custom field.
Issues
A comma-separated list of GitHub issue numbers relevant to the position. Queried at build-time and shown in the automatically created Typical tasks section.
Salary
Determines which role to use in the salary calculator. If no value is present, the job title is used. The calculator is not rendered if there is no matching role in the compensation calculator. If the role has been newly added to the compensation calculator, you'll need to add the role as an option to the custom field in Ashby global admin settings.
Mission & objectives
Determines whether the Mission & objectives section is shown on job listings
Creating a new job posting
Pages are only created for listed job postings. While viewing a job in Ashby:
Click Job Postings in the sidebar
Click New Draft
From here, you can create a job description and add automations.
Job descriptions
Each job posting can have a different description. When creating a new description, separate sections by H2 if you would like them to be collapsible. When the site is built, sections that start with an H2 are transformed into collapsible elements and added to the table of contents.
Below is a list of the automatically created sections and how they work.
Salary
This section appears if the job title or Salary custom field matches a job in the SF benchmark file.
Benefits
This section appears on all job postings. The data in this section can be updated in the Careers benefits component.
Typical tasks
This section appears if any GitHub issues are added to the Issues custom field in Ashby. The custom field accepts a comma-separated list of GitHub issue numbers.
Objectives
This section appears if the team has a mission.mdx file in their team folder. Example
Interview process
This section appears on all job postings. The data in this section can be updated in the Job interview process component. To add a custom interview process for a specific job, add a new key to the roleInterviewProcess variable and assign an array of IInterviewProcess objects.
Example:
const roleInterviewProcess: Record<string, IInterviewProcess[]> = {
'Site Reliability Engineer - Kubernetes': [
defaultInterviewProcess[0],
defaultInterviewProcess[1],
{
title: 'Technical interview',
description: `You'll meet with an Engineer who will evaluate skills needed to be successful in your role.`,
badge: '1 hour',
},
defaultInterviewProcess[3],
defaultInterviewProcess[4],
],
}
Custom description for the /careers page
By default, we look for section headers (<h2>) in the job description to show in the summary that appears at the top of the careers page. We're sniffing for these subheaders (in this order):
"Who we're looking for"
"What you'll be doing"
"Requirements"
If none of these are found, the job description will be blank.
If your job description has more creative titles, you can add a short custom description that _only_ appears on this section of the website. (This will take priority over the subheaders listed above.) Add this in the role's settings in Ashby under the _Website description_ field. It requires html, but here's a template you can use:
<p><strong>Things you definitely won't be doing:</strong></p>
<ul class="list-none p-0">
<li>❌ backlog grooming (it always sounded gross anyway)</li>
<li>❌ deciding what we build</li>
<li>❌ shielding developers from users</li>
<li>❌ project management/writing gazillions of tickets, RFCs, or PRDs</li>
</ul>
<p><strong>From you:</strong></p>
<ul class="list-none p-0">
<li>✅ SQL (any technical experience beyond this is a plus) - you must be able to be a self-serve PM, not relying on engineers to do analysis</li>
<li>✅ very proactive/organized</li>
<li>✅ collaborative</li>
<li>✅ several years of experience as a PM talking to users/interviewing</li>
</ul>
Apply
This section appears on all job postings. The input fields here directly reflect the Application Form assigned to the job. The Application Form can be found on the job's settings page.
Getting the job to appear on the site
If the job posting is published, the job will appear automatically the next time the site is rebuilt.
There are some nifty MDX components available for use in Markdown content. These components are included globally, so you don't need to do anything special to use them (like renaming .md to .mdx or manually importing them at the top of the file).
Images
Product screenshots
The `` component encapsulates an image with a border and background. It's useful since the app's background matches the website background, and without using this component, it can be hard to differentiate between the screenshot and normal page content. It also optionally supports dark mode screenshots.
You use it by passing image URLs to the imageLight and imageDark props like this:
<ProductScreenshot
imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/posthog.com/contents/handbook/images/tutorials/limit-session-recordings/sampling-config-light.png"
imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/posthog.com/contents/handbook/images/tutorials/limit-session-recordings/sampling-config-dark.png"
alt="Sampling config shown set to 100% i.e. no sampling"
classes="rounded"
/>
Optionally pass zoom={false} if you don't want the image to be zoomable, otherwise it will be zoomable by default.
_Note: If you don't have a dark image, just leave out the imageDark prop and the light screenshot will be used for both color modes._
Annotated product screenshots
The `` component overlays interactive callouts on top of an image. Instead of baking dots or numbers into the image file, the markers are live DOM positioned with percentage coordinates, so they stay anchored and scale when the image resizes (and they theme correctly in light/dark mode).
There are two styles:
numbered — numbered badges paired with a "key" legend. Hovering a key row grows the matching marker, and vice versa.
dots — pulsing, clickable dots that open a popover with the callout's title and description.
The builder
Don't hand-write coordinates. Moderators can open the visual builder at /image-annotator (also under the account menu → Moderator tools → Image annotation). Pick a product screenshot (or paste a Cloudinary URL), click to drop markers, label them, then copy paste-ready code. It outputs code for both destinations below.
`` (recommended)
The simplest entry point. It resolves the image (light + dark) and an optional named annotation set straight from a product hook, so the image stays in sync if it's ever updated. Because the API is namespaced (ImageAnnotations.FromProduct), import it once at the top of your .mdx file — same as Tab:
<!-- prettier-ignore -->
<!-- prettier-ignore -->
| Prop | Type | Description | | --- | --- | --- | | product | string | Product handle, e.g. "session_replay". | | screenshot | string | Key in that product's screenshots object, e.g. "overview". | | title | ReactNode | Section heading. In split it sits in the left column next to the image. | | set | string | Name of an annotation set stored on the screenshot (screenshots[screenshot].annotations[set]). | | annotations | Annotation[] | Inline annotations — overrides set. | | type | 'dots' \| 'numbered' | Overrides the set's type (defaults to the set's type, then numbered). | | showKey | boolean | Force the key on/off (defaults to on for numbered). | | layout | 'stacked' \| 'split' | stacked (default) puts the image above the key. split is a responsive two-column layout. | | children | ReactNode | Left-column content (your prose) when layout="split". | | alt, imgClassName, className, keyTitle | string | Presentation overrides. |
Split layout: pass layout="split" and put your description as children to get a responsive two-column section (uses @container/reader-content queries). It stacks as description → image → key on mobile, and becomes description top-left / key bottom-left / image right on wider screens.
<!-- prettier-ignore -->
Every session replay comes with a browser-like DevTools suite synced to the timeline.
Watch session replays
Storing annotation sets in a hook: add an annotations map to a screenshot in src/hooks/productData/<product>.tsx. Multiple named sets are supported, since the same image may be annotated differently in different places. Coordinates are percentages (0–100) — copy them from the builder.
If the image isn't in a hook (or you want a one-off), define the annotations inline. MDX only allows ESM, so use export const — a bare const won't work. For the image, you can still reference a hook via product + screenshot (keeps it in sync), or pass a literal src/srcDark.
Splitting the image and key: because ` and read from the wrapping <ImageAnnotations>` provider, you can render them in different spots with other content in between.
<!-- prettier-ignore -->
Any markdown or other components can go in between…
_Note: srcDark is optional everywhere — if a dark variant isn't provided, the regular src is shown in both color modes._
Image slider
You can create a slider or carousel of images by wrapping them in the <ImageSlider> component like this:
Codeblocks in PostHog are created by enclosing your snippet using three backticks (\\\`) or three tildes (\~\~\~), as shown below:
{ "name": "Max, Hedgehog in Residence", "age": 2 }
This will produce the following codeblock:
{
"name": "Max, Hedgehog in Residence",
"age": 2
}
Adding syntax highlighting
Syntax highlighting can be added by specifying a language for the codeblock, which is done by appending the name of the language directly after the opening backticks or tildes as shown below.
{ "name": "Max, Hedgehog in Residence", "age": 2 }
This will produce the following output:
{
"name": "Max, Hedgehog in Residence",
"age": 2
}
Using tabs
You can use the `` component to create tabs in your code blocks. This is useful for showing multiple code snippets or examples in a single code block.
Especially in long tutorials, you can highlight the important differences between steps using highlighting comments. It's much easier to read visual diffs than reading through the code block line by line.
| Comment | Effect | Usage | | -------------- | ---------------- | ---------------------------------------- | | // + | Green highlight | Represents additions in diffs | | // - | Red highlight | Represents removals in diffs | | // HIGHLIGHT | Yellow highlight | General emphasis without special meaning |
const a = 1
const b = 2
const c = a + b // +
console.log(a + b) // -
console.log(c) // +
console.log('end') // HIGHLIGHT
const a = 1 const b = 2 const c = a + b // +
console.log(a + b) // - console.log(c) // +
console.log('end') // HIGHLIGHT
Collapsed code blocks
In some cases, such as large nested config files, you need readers to focus on a specific part of the code block while maintaining the context. You can do this by adding focusOnLines= to the code block. This collapses the code block and only shows the lines of code you specify.
Code blocks can also be used to show mermaid UML diagrams. When using these diagrams, make sure to include a text description of the diagram afterwards for accessibility and LLMs.
sequenceDiagram
Alice->John: Hello John, how are you?
John-->Alice: Great!
Alice->John: See you later!
sequenceDiagram Alice->John: Hello John, how are you? John-->Alice: Great! Alice->John: See you later!
Product list
Use ` to render a list of products sourced from useProduct hooks. It links each product to /{slug}` by default using the product's icon, color, and name.
Auto-source from a product data field (e.g. every product where wizardSupport is set):
Products are grouped in sourceValues order. Plain values (true, "some string") filter without an indicator. Object values ({ value, color }) also render a colored dot with tooltip text.
Only the products whose wizardSupport value matches a sourceValues entry will render. Other props: urlPrefix (default /), className, itemClassName, iconSize.
Wizard command
Use `` to render a copyable install button for the PostHog wizard CLI. Clicking the button copies the command to the clipboard and shows a toast notification.
The displayed command is always the clean npx @posthog/wizard …; the copied command always pins -y and @latest. The wizard reads the user's region off their auth token, so no --region flag is added. ` is a thin alias for `.
Props:
| Prop | Type | Default | Description | | --- | --- | --- | --- | | command | string | '' | Subcommand appended after @posthog/wizard (e.g. mcp add) | | selfDriving | boolean | false | Shorthand for command="self-driving" | | slim | boolean | false | Hides the "Learn more" link below the button | | variant | 'default' \| 'bordered' | 'default' | Bordered button style | | className | string | '' | Additional classes for the button element |
Slim mode (button only, no "Learn more" link):
<!-- prettier-ignore -->
Call to action
Adding `` to any article will add this simple CTA:
Don't overuse it, but it's useful for high intent pages, like comparisons.
Feature comparison tables
When comparing features between two or more products, use the ` component which sources data from the src/hooks/competitorData/` directory and lets you compare specific features across multiple competitors.
We mainly use them in customer stories and some product pages.
Quotes are sourced from the useCustomers hook and can reference product-specific quotes or general quotes by someone at a company. Be sure to add the customer's information to the useCustomers hook in src/hooks/useCustomers.tsx.
Example
<!-- prettier-ignore -->
quotes: {
viktor_eriksson: {
name: 'Viktor Eriksson',
role: 'Software Engineer',
image: {
thumb: 'https://res.cloudinary.com/dmukukwp6/image/upload/q_auto,f_auto/viktor_00c779a706.jpg',
},
quotes: [
"PostHog is super cool because it is such a broad platform. If you're building a new product or at a startup, it's a no-brainer to use PostHog. It's the only all-in -one platform like it for developers.",
],
},
},
Collapsible sections
The combination of <details> and <summary> components enables you to add a collapsible section to your page. Useful for FAQs or details not relevant to the main content.
<details>
<summary>Can I specify some events to be identified and others to be anonymous for the same users?</summary>
Not if you already identified them. Once a user is identified, all _future_ events for that user are associated with
their person profile and are captured as identified events.
</details>
Tabs
Tabs enable you to display different content in a single section. We often use them to show different code examples for different languages, like in installation pages.
To use them:
Import the Tab component.
Set up Tab.Group, Tab.List, and Tab.Panel for each tab you want to display. The tabs prop in Tab.Group should be an array of strings, one for each tab. This enables you to link to each tab by its name.
Add the content for each tab in the Tab.Panel components. You should use snippets for readability, maintainability, and to avoid duplication, but you can use multiple snippets in a single tab.
For example, here's how we can set up tabs using error tracking snippets:
Error tracking gives you multiple ways to control which exceptions are captured:
<!-- prettier-ignore -->
Before send
Suppression rules
Burst protection
You can default to a specific tab by passing the tab name in the query string like:
/docs/product-analytics/installation?tab=web
Links
Linking internally
Use Markdown's standard syntax for linking internally.
[Link text](/absolute-path/to/url)
Be sure to use _relative links_ (exclude https://posthog.com) with _absolute paths_ (reference the root of the domain with a preceding /).
To open a link in a new window within the PostHog.com OS interface, use state={{ newWindow: true }} like:
<!-- prettier-ignore -->
Link text
Linking externally
The ` component is used throughout the site, and is accessible within Markdown. (When used _internally_, it takes advantage of <Link to="https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-link/" external>Gatsby's ` features like prefetching and client-side navigation between routes).
While that doesn't apply here, using it comes with some handy parameters that you can see in action via the link above:
Add external to a) open the link in a new tab, and b) add the _external link_ icon (for UX best practices if forcing a link to open in a new window)
If, for some reason, you need to hide the icon, use externalNoIcon instead
Example:
click here
Private links
Sometimes we link to confidential information in our handbook. Since the handbook is public, it's useful to indicate when a link is private so visitors aren't confused as to why they can't access a URL (like a Slack link or private GitHub repo). Use the `` component for this. See an example (on our share options page.)
click here
Private links will always open in a new browser tab.
Mention a team member
Use this component to mention a team member in a post. It will link to their community profile and appears like this: Eli Kinsey
There's also a photo parameter which will inline their photo next to their name like this: Eli Kinsey
Mention a small team
Use this component to mention a small team in a post. It will link to their team page and appears like this:
The default version shows the team's mini crest and name in a bordered "chip" style. There's also a noMiniCrest parameter to omit the mini crest and border for inline usage like this:
Both versions will show the full team crest on hover. Clicking the tooltip will open the team page in a new window.
Embedded posts
You can embed what looks like ~~a Tweet~~ an X post using the <Tweet> component. It's used on the terms and privacy policy pages, but was componentized for use in blog posts to break up bullet points at the top of the post.
_Note: This does not actually embed an X post ; it's just styled to look like one._
Here's what a post looks like. It's designed to have a familiar look that makes it easy to scan.
If you show multiple posts in a row, they'll be connected by a vertical line to make it look like a thread.
Usage
Be sure to change the alert message which appears if you click one of the action buttons (reply, repost, like).
<!-- prettier-ignore -->
<Tweet
className="mx-auto"
alertMessage="Gen Z? Don't get distracted. You're here to read our exciting embedded post component."
>
If you show multiple posts in a row, they'll be connected by a vertical line to make it look like a thread.
You can optionally center the post with the mx-auto class (shown in the example code, but _not_ used in the preview above).
There were a few moving parts involved with setting up MDX so it might make sense to have them written down.
What's MDX?
Not in scope here - but it's essentially React in Markdown.
How do we make it work?
Page creation
Website pages are automatically created for all MD and MDX files using Gatsby's createPages API. Slugs are automatically generated based on the file title, and the design template for each page is determined based on the folder the file resides in.
Design templates
There are currently 5 templates:
Handbook / Docs - Files located in contents/handbook and contents/docs
Blog post - Files located in contents/blog
Blog category - Automatically created based on categories used in blog posts
Customer - Files located in contents/customers
Plain - All other files located in contents
Each template is passed a unique automatically generated ID that is used to query the data contained inside of the post.
The GraphQL query inside of each template will return everything we need, from content to frontmatter, and we use the component MDXRenderer to render the body, and MDXProvider to pass some context that is available to all MDX pages.
In this case, we pass references to components that can then be used without imports directly on MDX pages, like this hedgehog:
Because of the components passed to MDXProvider, I can include this hedgehog by just adding `` in my MDX file - no import needed.
However, if I want to include something from a module, I can also do so. Here's how one would insert a Transition component from Headless UI:
## Some Markdown
{/* ... */}
Currently, almost every component on the site is available automatically. This will eventually change because it causes some performance issues. For now, if you need a reference for which components you should be using in your MDX, check out our MDX components handbook page.
mdxImportGen
The mdxImportGen.js script handles global MDX imports automatically. This is currently a quick implementation that can improve and be made more robust in the pre-commit process. Essentially, it prepares a file based on all the components in our src/components directory which is then used to pass the components to MDXProvider, making them available everywhere.
Doing globally available imports this way was important for 3 main reasons:
Relative imports in MDX can be annoying
Keeping MDX files clean
Making MDX a nice experience even for less technical people that update our website
We don't include these by default as sourcing the products from Shopify takes an absurd amount of time. Ask the if you need these values.
Product Fulfillment
We used to rely on Brilliant for fulfillment, that has been deprecated, we now use Micromerch. You should notify Micromerch of any new products that you want to add to the store as they handle distribution and storage for most things and are connected to Shopify.
Here's a general structure for a presentation using the various templates. You can add multiple product slides by adding additional entries. See a full example on GitHub in product-engineers.json.
{
"name": "Product Engineers",
"config": {
"thumbnails": false,
"notes": false,
"form": true,
"teamSlug": "sales-cs"
},
"slides": {
"overview": {
"template": "stacked",
"name": "Overview",
"title": "Title goes here",
"description": "<p>You can add the {companyName} and it will get inserted when enriched with Clearbit.</p>",
"descriptionWidth": "@2xl:w-3/5"
},
"error_tracking": {
"template": "product",
"name": "Error Tracking",
"handle": "error_tracking",
"screenshot": "home",
"title": "Title goes here",
"description": "<p>Description</p>"
},
"all_in_one": {
"template": "columns",
"name": "All-in-one",
"title": "Multiple products on one slide",
"description": "Supports multiple columns of content",
"content": [
{
"handle": "product_analytics",
"title": "Product Analytics",
"description": "<p>Description goes here.</p>",
"screenshot": "funnelVertical"
},
{
"handle": "session_replay",
"title": "Session Replay",
"description": "<p>Description goes here.</p>",
"screenshot": "home"
},
{
"handle": "error_tracking",
"title": "Error Tracking",
"description": "<p>Description goes here.</p>",
"screenshot": "errorsCropped"
}
]
},
"pricing": {
"template": "pricing",
"name": "Pricing",
"title": "Pricing",
"description": "PostHog offers usage-based pricing. This means you only pay for what you use, and you can set billing limits so you never get an unexpected bill.",
"image": "/images/products/product-analytics/screenshot-billing.png"
},
"cta": {
"template": "booking",
"name": "Get a demo",
"title": "Get a demo",
"description": "<p><strong>No demos required</strong> – you can try PostHog without ever talking to us. But if you'd like personalized demo, book a time.</p>"
}
}
}
Templates
Different templates support different features.
stacked
Content is stacked top to bottom and optionally supports an image which replaces the default Hogzilla background image.
Image: Stacked slide template
The above example does not use the image prop, thus Hogzilla is included.
"overview": {
"template": "stacked",
"name": "Overview",
"title": "Title goes here",
"description": "<p>You can add the {companyName} and it will get inserted when enriched with Clearbit.</p>",
"descriptionWidth": "@2xl:w-3/5"
},
product
This imports the useProduct.ts hook to fetch product data based on the handle passed in. It allows it to access things like the product name, icon, color, and array of screenshots.
Image: Product template screenshot
In the above example, it uses the "home" screenshot from the ai_observability product:
"ai_observability": {
"template": "product",
"name": "AI Observability",
"handle": "ai_observability",
"screenshot": "home",
"title": "AI Observability",
"description": "Understand how your users consume AI in your product, and monitor performance and cost when using different models."
},
columns
This is a multi-column layout that supports multiple products or features side-by-side.
There is currently no logic to wrap items, so it works best for 2-4 columns for now.
Image: Columns template example
"all_in_one": {
"template": "columns",
"name": "All-in-one",
"title": "PostHog apps have great synergy",
"description": "Identify a trend, see what happened, assign issues – all in one place.",
"content": [
{
"handle": "product_analytics",
"title": "Product Analytics",
"description": "<p>Easily uncover user friction by following the drop-offs in a funnel.</p>",
"screenshot": "funnelVertical"
},
{
"handle": "session_replay",
"title": "Session Replay",
"description": "<p>Watch session recordings to understand friction in the user experience.</p>",
"screenshot": "home"
},
{
"handle": "error_tracking",
"title": "Error Tracking",
"description": "<p>Assign issues to engineers to get user problems solved quickly.</p>",
"screenshot": "errorsCropped"
}
]
},
"cta": {
"template": "booking",
"name": "Get a demo",
"title": "Get a demo",
"description": "<p><strong>No demos required</strong> – you can try PostHog without ever talking to us. But if you'd like personalized demo, book a time.</p>"
}
Customization
Overriding default content
You can create an entirely personalized presentation, use the dream-customers folder. Set the json filename to the company's domain name and inside the file, set an arbitrary ID that will be used in the URL, like:
/for/hasura.io/123456
Reference content from any persona file with inherit, or override the content by adding your own.
"overview": {
"template": "stacked",
"title": "Hey John!",
"description": "We've prepared this custom presentation specifically for the Hasura team to show how PostHog can accelerate your product development."
},
"error_tracking": {
"inherit": "product-engineers",
"slideKey": "error_tracking"
},
"feature_management": {
"inherit": "engineering-managers",
"slideKey": "feature_flags"
},
Display options
Use the config object in the JSON file that supplies the content for the presentation to customize how the presentation renders. This can be done for a persona, a specific company, or an individual.
All properties
"config": {
"thumbnails": false, // hides slide thumbnails column
"notes": false, // hides presenter notes drawer
"form": true, // shows the lead form
"teamSlug": "sales-cs" // specifies which Small Team appears in the form
}
The thumbnails, notes, and form values can be overridden in the query string (independently), like:
These configuration options are remembered when using the _Share your windows_ link generator in the _Active windows_ pane. This is useful for sending a link to someone that will open multiple windows _and also_ remember the display options of a presentation.
Product presentations
The above properties also work for product presentations, like:
/traces?thumbnails=false¬es=false&form=true
Lead form
The lead form is hidden by default but can be enabled in a persona's JSON file, or displayed manually using the query param &form=true.
"config": {
"form": true,
}
Non-personalized (industry-specific) landing pages show avatars of the .
Image: Default small team
Company-specific landing pages show the by default.
Image: No assignment in Salesforce
This is because different URL patterns are intended for different purposes.
| Path | Purpose | Team | | -------------------------- | -------- | ----------------------- | | /for/{company}/{persona} | Outbound | New Business Sales Team | | /for/{persona} | Inbound | Product-Led Sales Team |
Small team
The small team in the config object can be overridden for any persona, company, persona within a specific company, or completely custom landing page.
This can also be overridden to show a specific small team using &t={id} using mappings in the TEAM_QUERY_MAP in src/components/Presentation/index.tsx and works for product presentations, use case landing pages, personalized landing pages, and custom presentations.
| ID | Small Team | | --- | ------------------- | | 1 | sales-cs | | 2 | sales-product-led |
On landing pages personalized to a specific company, we check if the account is assigned in Salesforce. This takes priority over any small team assignment in JSON and the t query param.
Keeping product comparison charts up-to-date across a large website with multiple products is tricky, so we've built a way to source data from a single place. That way, if a competitor adds a new feature (or updates an existing one), we can update the data in one place and have it automatically reflected across the entire website in existing product comparison tables, blog posts, and other documentation.
To do this, we need a source of record for:
feature definitions (each PostHog product and its feature set)
competitor data (each competitor and their product and feature offerings)
By standardizing all features across all products and competitors, we can generate a comparison table without any hard-coded data.
Example
This is not an ordinary Markdown table. (In fact, it's not Markdown at all!)
Feature-level data for competitors is stored in the same format, with the exception being that products are namespaced under the products node in a single file instead of being spread across multiple files for each product.
There's also a platform node below the product array.
<code className="language-mdx">{<ProductComparisonTable competitors={['posthog', 'amplitude']} rows={[ 'product_analytics.features', // includes "Features" section header { label: 'Optional custom section header' }, 'dashboards' // only renders true/false for 'available' and sources text from dashboards.tsx using the 'summary' node ]} />}</code>
), }, ]} />
Compare specific features between competitors
If you want to cherry-pick specific features, just reference the key directly. (This is useful for blog posts that compare specific features between competitors in a manually set order.)
Headers automatically span across all columns and are styled with a border to visually separate sections.
Product page overrides
Excluding sections
Product pages list out all sections within a product's feature set by default, but in some cases it doesn't make sense to do so.
For example, showing the platform.integrations section might make sense for the Product Analytics comparison, but not for AI Observability comparison where that product doesn't really integrate with the tools that are otherwise integrated across the PostHog platform.
If you want to exclude a section from rendering, you can use the excludedSections property.
By default, the component will show rows where a competitor's cell doesn't have a value. This can be overridden on a per-product basis by setting require_complete_data: true in the product's feature definition file.
A brief description of what the roadmap item intends to accomplish.
Projected completion date / Date completed
The projected completion/completion date of the roadmap item. If the “Complete” checkbox is checked, this field label will change from “Projected completion date” to “Date completed”.
This field also controls where the roadmap item appears on the roadmap page.
If no date is present, it will appear under “Under consideration”.
If a projected completion date exists, it will appear under “In progress”.
If a completed date is added, it will appear under “Recently shipped”
Category
Used to group roadmap items together. We only use this field to categorize the milestones on the homepage.
Add GitHub URL
If a GitHub issue is relevant to the roadmap item, you can paste the entire URL here. There is no limit on how many issues you can attach.
This field is used to display GitHub issue titles and links on roadmap items under the “Under consideration” section. It also determines the progress of the roadmap items under the “In progress” section.
Image
Used to show album art for roadmap items under the “In progress” section. Images should be square, at least 200 x 200 pixels, and not contain any borders or shadows. Images are optional. If you need a new image, request it through the normal process.
Complete
Used to determine if the roadmap item is complete. If checked, the date field will change from “Projected completion date” to “Date completed”.
Milestone
If checked, the roadmap item will appear on the roadmap section of the homepage.
Beta available
If checked, buttons under the “In progress” section change from “Subscribe for updates” to “Get early access”.
The body of the notification email. Supports Markdown.
This field will auto-populate with any changes you’ve made to the roadmap item. For instance, if you check the “Beta available” field before clicking “Next”, the content will be auto-populated with “Beta is now available”.
View subscribers
Click this button to see all subscribers who will receive the email.
Once your email body and subject are ready, click “Update & notify subscribers” to add the emails to the Customer.io email queue. Any emails sent from Squeak are automatically placed in “Draft”.
To send the emails, you must log in to Customer.io > Click “Broadcasts” > Click “API Triggered Broadcasts” > Click “Squeak! Roadmap item” > Click “Drafts”. From here, you can select and manually send all roadmap notification emails.
Note: This will change in the future. Once we determine this works as intended, we can automatically send emails directly from Squeak and cut out the Customer.io steps.
MDX files in the repo under /contents/teams/{team-name}
_Quarterly goals, team-specific handbook content_
Team records in our CMS, with all fields editable directly on the small team page
_Team photo, mission, crest_
Small team FAQs
_Aggregated from team member profiles, and from our CMS_
Team page content
Any MDX files in the repo will display below the team members and _recently shipped_ sections.
Quarterly goals
We're moving toward having quarterly goals in their own MDX files, like 2024-Q1.mdx. This will allow us to show the current team goals, while displaying previous goals in an accordion.
Until then, when adding quarterly goals for a new quarter, add them to the index.mdx file and move the previous goals into a section below them (rather than deleting):
Request a custom team crest from Lottie. Describe your team with a few adjectives, maybe physical tools that can be used in an illustration, and a sentence or two about what you do. She'll create two versions: a large one (for your small team's page) and a mini crest used in other places (like the careers page).
Create a new team on GitHub and remove the new members from their previous team. If moving a previous team lead, remove their team lead status from the previous team first.
Give that newly-created team Direct Access with Write permission to the posthog and posthog.com repositories, as well as any other repos they will be contributing to frequently. This allows team members request review from their team instead of having to tag members individually.
Create the new feature/team-{team-name} labels on GitHub.
Add the team's feature ownership to the feature list.
owner: Use the team's slug (seen in the URL when visiting a small team's page). Supports an array for shared ownership.
notes: (Optional) Displays below owners. (Wrap string in < ;em>brackets</em>)
label: Defaults to the feature name, but slugified. Override with a custom tag if necessary. Supports false to hide the label if one doesn't exist.
On Slack, create a new channel called #team-{team-name}. Add a new People > User group with the handle @team-{team-name}-folks. Add / Remove people from other groups as necessary.
If there are existing forum topics or roadmap items, re-assign them to the new team.
This requires coordination with the team, as updating team names involves changing slugs which will break builds if not done in the correct order. Ask in #posthogdotcom team for help.
PostHog.com doesn’t behave like a normal website. Instead, it runs inside a desktop-style environment where every page is a draggable window. This guide explains how that system works under the hood.
Core architecture
PostHog.com runs on Gatsby with a custom windowing system built using React context providers. The entire site operates inside a desktop-like environment where traditional page navigation is replaced by window management.
At a high level, every page is wrapped in the App Provider, which manages global state and window logic. The Wrapper renders the desktop interface, and each page is displayed inside an AppWindow component on the Desktop.
Key components
App Provider (src/context/App.tsx) – Core state management and window system
Wrapper (src/components/Wrapper/index.tsx) – Desktop layout and window rendering
AppWindow (src/components/AppWindow/index.tsx) – Individual window state management
Desktop (src/components/Desktop/index.tsx) – Desktop environment with wallpapers and icons
How pages become windows
Every page in the site is wrapped using Gatsby's wrapPageElement API in gatsby-browser.tsx:
It also provides drag constraints for window movement via constraintsRef.
Window implementation
Individual windows are implemented in src/components/AppWindow/index.tsx using Framer Motion for animations and drag interactions. Each window is wrapped in a Window Provider so that child components can access the current window object via the useWindow hook.
Key features
Dragging – Windows can be dragged around the desktop
Resizing – Resize handles on window borders
Snapping – Windows snap to screen edges
Minimizing – Windows minimize to taskbar
Focus management – Click to bring windows to front
Animation problems – Check Framer Motion configurations in AppWindow
State sync issues – Use React DevTools to inspect App Provider state
This architecture allows PostHog.com to feel like a desktop operating system while maintaining the benefits of a static website for performance and SEO.
We encourage engineers to act like feature owners, carrying a project from ideation to completion. We maintain a design system in Storybook, so engineers can build high-quality features independently, as much as possible.
Because engineers choose their sprint tasks near the beginning of a sprint (and product doesn't plan tasks _for_ engineers in advance), our process doesn't allow for us to have a product manager and a designer to work closely together before a task gets selected by an engineer.
In our process of short, 2-week sprints with no pre-planning, design would become a blocker to an engineer quickly iterating on a feature. Thus, engineers don't get support from product designers. Product designers should deliver high quality components. The product teams should have people in them that can ship good-enough quality interfaces using those components. If that's not true, we should hire or move people around.
We believe that everyone is a designer. Because we hire generalists, there is no expectation that every project should start by running through design _first_. It is up to you when to involve our product designers in your work.
You should start by identifying the stage and goals of your project.
v0.1 or v2?
As the feature owner, you should make a choice if you're building a very basic first iteration of something, or if you're improving the experience.
There are two paths for creating the first version of a product: v0.1 or MVP (even earlier).
v0.1
If we're attempting to reach parity on a product or feature with other competitors in the space – and there's a clear path toward how a product should work or look – there's no need to loop in a designer. You should make your best judgement, while leveraging our design system to build your feature.
MVP
If you're shipping an entirely new feature (i.e. SQL for PostHog), then you should figure out if any users even care (!), which usually means creating an MVP and releasing it behind a feature flag to some friendly users. (Pro tip: make friends by being support hero.)
During both of the above approaches, designers are happy to provide light recommendations that will improve the user experience without becoming a blocker to shipping.
v2
If you're improving an _existing_ feature that is popular, you are probably creating v2. Typically when we decide to ["Nail [a specific feature]"](/blog/product-360#4-we-created-two-very-basic-frameworks), it's worth working closely with design to figure out how we can _10x_ our product vs. competitors.
However you're building, please _communicate_ to product design what your expectations are!
Feature Complexity
The more complex a feature is to implement, the more likely it is that involving product design will make you faster.
Your design skill
We generally hire full stack engineers, but some people think more like designers than others. This is fine - you should play to your strengths.
The less strong you are at design, the more we'd encourage you to involve a product designer.
If you're unsure about your skill level, ask a product designer for direct feedback. This is a book we'd recommend if you want to learn the mindset.
Scenarios for looping in product design
If you built something and just need some polish...
Feel free to share a link (or screenshot) of what you've built. We can provide UX or design feedback for your consideration.
If you built something and realize it needs some UX love...
Share a link (or screenshot) of what you've built. Depending on the state of the project, we can either go back to the wireframe stage to rethink some things, or figure out a phased approach to incremental improvement.
If you designed your own wireframes or mocks...
Sometimes if you have domain knowledge or have been thinking about a project for a while, it might make more sense for you to start the design process. Feel free to share with us for a second opinion, or if you think certain UIs or flows are suboptimal.
Need help brainstorming a flow? Pair with a product designer
If you'd like the help of a product designer on an MVP/v0.1-type project, a 30-60 min Zoom working session is a great way to brainstorm and sketch out ideas. Since our design team is small, we try to avoid too much "homework".
Usually during quick syncs like this, it's enough to help an engineer work through complex UX issues. Reach out to the platform-ux team if you're interested in a synchronous session like this.
---
In any case, prefer copying existing UI patterns instead of creating new ones. This means users' muscle memory will work for your scene when they first come to it.
Don't create a new version of something just because it's more convenient for your product. Take a few moments to look around how other products handle using the same component and copy the existing paradigm. This includes things like placement, sizing, and colors.
Avoid cramming in custom elements into common existing patterns just because there's space for something else. Creating one-offs leads to an inconsistent experience and confusion for end users. There are rare cases where you should deviate from this pattern. Before you do, always check in with the platform-ux team to see if there's a better pattern to follow.
Product design capacity
Sometimes product design may push back if they simply don't have capacity. It's subjective when this may happen, and it'll usually be in cases where they feel they won't be as helpful based on the above.
Understand the company strategy, and prioritize based on this _and_ what they believe users want
Can easily propose ideas for what to build
Make sure the things they've built are being used
Follow up after they've built something to improve it if needed
Are good at descoping things and getting products or features into people's hands quickly
Have users that they're friendly with
Manage to build things without lots of internal meetings
Dive _deep_ when they need to, because shipping D might also require solving A, B, and C
Bad product engineers
Consider research something that takes two weeks rather than two hours
Can't explain our company strategy
Can't explain who their product is built for
Don't know their product's competitors
Only work on things they've been told to work on
Don't know the names of any of their users
Never challenge why they're being told to work on something
Don't talk to users about what they're going to build, or what they've built
Don't track if the things they've built are being used
Spend 6 months on a huge feature before a user can try it
Never remove features or complexity, often by shipping features that aren't used and leaving them
Focus on internal alignment over company strategy and what users need
Wait for someone else to fix an adjacent problem
How to
Validate ideas
Despite what the industry tells you, it's debatable how well you can validate ideas up front (see: the number of startups that think they'll succeed based on user interviews then find they can't get any users). Just shipping is often the best way to validate an idea. When we built PostHog, Tim and James had to pivot 5 times – despite getting positive feedback on new ideas almost _every time_. Talking to users upfront can probably help remove totally stupid ideas fast, but for the majority of ideas "this could work", it only has a limited amount of benefit in our experience.
This gives you the best evidence (do people _actually_ use it, and what do they think), but _potentially_ at the highest cost as you have to build it! The challenge with this approach is making sure you de-scope the first version of the product or feature enough that users will at least try to use it, so you get enough signal that they care, without damaging our brand because the experience is so poor.
So, when you ship something:
Consider what you are trying to learn (if anything, importantly – many things are so obvious like fixing a well-defined bug, you aren't trying to learn anything) product-wise.
Descope it as much as possible to reduce the cost _you_ incur upfront of building it.
Judge for yourself if and how to limit brand damage (your options are one or more things like - internal use first, a feature flag rollout, messaging a couple of friendly users, not marketing it or limiting the marketing, or shooting for Minimum Lovable Product instead of Minimum Viable Product).
Follow up... figure out if / why it is or is not being used, and iterate. If you've shipped early, it'll be crappy so _will need more work_ as you figure out what users want.
Just shipping makes sense when it's very obviously in line with our company strategy (which is generally proven), and you can descope it successfully. This is almost _everything_ that you may ever build here. The key is to manage the rollout carefully.
Products at PostHog generically go through three phases, and considering your phase is important when you ship new features:
1. Pre PMF at PostHog
We only build things that _already_ have successful competitors with real revenue. The implication is that "just build it" works disproportionately well because other people have already figured out that new product X has product market fit.
The challenge is therefore figuring out if _PostHog's_ users base will want the new product, as we already know the product is useful.
2. Figuring out PMF at PostHog
This is where we are getting our very first paying customers.
The product focus is making sure people are _delighted_ with the above features. Maybe there are bugs or maybe there are too many gaps with competitors still for people to pay. Focus on how happy users are and why / why not. Keep an eye on early revenue data too - are people willing to pay, or are they churning?
3. Post PMF at PostHog
This is where we're scaling the number of free and paid users.
Features at this stage either fall into:
(i) gaps with competitive products that we've not prioritized so far, probably based on feature requests from users, in which case the risk of them not being useful for users is pretty low or...
(ii) totally innovative things like new UX driven by our take on AI, or a new way to access data (like Hog or SQL), or an integrated experience that no one else can offer because they don't have all the tools in one. In these cases, it is _more important_ to consider how your products are being used as you are more likely to build something that isn't useful (but at this stage, it's fine and encouraged to innovate)
There are plenty of other techniques, that you can do in parallel to get a signal on a new idea:
Use the public roadmap. If you have a rough idea, create a GitHub issue and create an item on posthog.com/roadmap. This will gauge demand.
Ask internally for help. There are lots of people that can help you. The CS team talk to users all the time, the support team have a strong sense of pain points, other product engineers have all talked to users, James and Tim have a broader view of how PostHog is doing, the Developer Marketing team can help you get usage or validate demand.
Interviews. Our Product Managers regularly run interviews, ask to be included and give a heads up what you're trying to learn about, or just message users directly! You can even embed your calendar in our surveys app to book your own user interviews. You will need lots of existing potentially relevant customers for this to make sense, since response rates are typically low.
Listen to the internet. We have a #brand-mentions channel in Slack that monitors for social mentions by customers, or get us to post a question here if you need.
Seek internal feedback. We dogfood all our own products to grow our company, so ask for _internal_ relevant users.
Ship things iteratively and follow up
Use staggered rollouts: we have a product _designed_ to help you do this. Depending on how risky a new feature is, start with internal users, or
Data: check if the thing you just built is being used. Remember to add some events.
Session replay: watch users using your thing. This can often highlight confusing UX.
Interviews
Support
Listen to the internet
Iterate with users
A note on attitude first - any kind of feedback, bug report, complaint or usage is a gift from users. It's easy to get dismissive or frustrated when people don't "do what we want"! Worst case scenario is that we get ignored.
Handling users well is really important. If we do a good job responding to feedback:
The product improves because we do a better job at building what users want.
We get marketing benefits because the user will be impressed and will tell their friends.
We get more feedback because it teaches people that we listen and that we care.
Tone matters a lot. Whenever you are messaging a user, please consider:
They're on the internet, so you are competing with cat videos. It better be compelling.
They receive loads of outreach from people. If you send something generic, it will get auto filtered out by their brain.
So, how do you make yourself compelling to engage with?
The tone is your starting point. Send something informal and human. You are explicitly trying to avoid sounding like a mega corporation that treats users like numbers. You are a human, your users are human. Be friendly, light hearted and fun. Make it clear the message isn't automated if you can.
If you _must_ automate messages for whatever reason, make them quirky and informal and human. "Yo I'm Manoel, my job at PostHog is making sure mobile users are happy. It looks like this includes you! I build X, Y, Z here – is there any chance we could talk about X new thing? Here's my calendar or respond and we'll find time!" sort of vibe. Don't make messages long if you want people to do something – one or two sentences.
The medium matters. The easier something is to spam, the harder it is to get hold of people. For example, email gets ignored far more than Slack or X.
Response times are very important. If you can catch someone _whilst_ you're top of mind, you are likely to get 20x the response rate. That means within a minute or two of receiving a message. There is a huge drop off if you don't respond for 30+ minutes. Obviously this isn't always possible, but take opportunities if you happen to be online at the same time as someone you need feedback from. I once ran a call center – if we phoned someone who made an enquiry within 5 minutes, it was 9x more likely we'd get hold of them.
Closing the loop is the final point. If a user gives feedback or asks for something, you should ultimately respond with:
A PR (which will likely delight them)
A roadmap item / issue they can follow (hey this is awesome, I want to do it, this is so you can follow progress)
A reason why we can't do their thing
Closing the loop with the above shows people we've listened and considered their points carefully, and that we respect their opinion. This means they will continue to give us feedback.
Talk to users
If you're talking to a user, there are some basic principles if you want to be a good product engineer.
Use a lot of open ended questions. Ask things like:
Do you understand your user behavior? Why / why not?
What do you want to know about how a feature is used?
If I could build one thing for you right now, what would it be?
Look for evidence that users have _actually done anything_ about the problems they say they have.
People want to be likable, so they'll often say they want what you're working on, even if they don't. Lots of features or products are nice-to-have versus must have. When something is a nice-to-have, people will act interested but won't get around to actually using it.
Ask things like:
Have you tried to solve this problem before? What did you do?
How important is this issue compared to other things you have to work on?
Has your company spent money trying to solve this before?
Write down every interview. This helps us come back as the rest of the team, or you, consider other products or features in future.
The maintains the revenue dashboards and queries that are used to understand:
What our historical revenue record looks like
What our revenue is expected to be this month
What our churn, growth, expansion, and contraction look like
Which customers have done the above activities
etc
Currently, all revenue dashboards can be found in Metabase (though we hope to have them all in PostHog's own data warehouse soon 👀).
Important dashboards
(these require internal access)
General overview: Useful to see our ARR graph and get quick links to dig into revenue for certain months.
Revenue lifecycle: Useful to see trends over time for churn, expansion, new revenue, etc.
Product-specific analysis (pick your product and date [month] at the top!): Kind of a combination of the above two, but for a specific product
Revenue by customer bucket: Useful for understanding trends in contract size for financial modeling, support, etc
FAQ
How is revenue attributed to a certain month?
Revenue is attributed to a given month based on the end-date of the invoice period. For example, an invoice that has a period of 2023-01-12 to 2023-02-12 will be counted in the revenue for 2023-02.
Some invoices cover multiple months. In this case, in the invoice_with_annual table (which is what all our dashboards use) we take the total amount of the invoice and divide it by the number of months the invoice covers, which gives us the MRR. We then generate a row for each month with that MRR so we can count that revenue into our monthly ARR/churn/expansion/etc calculations.
When is it a "forecast" vs a real, complete number?
As soon as any given month starts, we start closing invoices. As the month goes on and customers' invoice periods end, we close more invoices. This means that as the month goes on, we get more and more confident about what our revenue will be for that month. The month's revenue can still change after the month is over, however, due to delayed payments. This is generally not a hugely significant number, but it is something to be aware of.
How do we forecast a customer's revenue?
Our revenue is based on usage, so we do some basic math to make an educated guess about how much usage a customer will have in the current period.
For new customers, their usage can be very spiky as they tune their implementation. We don't currently forecast their usage if it's less than 31 days since their subscription started. Instead, we just report their current usage as their forecast.
If there are fewer than 7 days elapsed in the customer's current billing period, get the last 7 days usage (even if it's from the last period) and calculate the usage per hour. The calculate the remaining hours in the billing period, and do math to make an estimate.
If there are more than 7 days elapsed in the customer's current billing period, do the math based on all the days in the billing period.
If the customer has billing limits set, respect those billing limits.
How are cancelled bills handled? Are those forecasted?
As soon as someone cancels their account, their invoice is immediately closed. The revenue from that invoice immediately goes into the "completed" pile.
When are invoices updated?
A task is run nightly to sync the last 2 months of completed invoices, as well as all upcoming invoices for all customers. After the task is complete, the invoice_with_annual view is updated with the fresh data.
These are living guidelines, and they're meant to help us make better tradeoffs, not to be a gatekeeper. If a guideline doesn't fit your SDK, don't treat it as a blocker. Talk about it, write down the decision, and move on with context for the next person.
The big idea: PostHog SDKs run inside customer applications. That means customers lend us trust every time they install one. Our job is to be useful, boring in production, and safe to run in places we don't control.
Make the default experience excellent
Most users never read every option. They install the package, copy the quickstart, and hope it works.
Good defaults matter more than lots of configuration. Capture the right context by default, batch sensibly, retry carefully, and avoid making users learn PostHog internals before they see value. Configuration is still important, but it should feel like customization rather than a requirement to get a safe baseline.
A clean install should get developers to first value quickly: install the package, initialize PostHog, and capture a test event or evaluate a feature flag in a few minutes. Quickstarts should work from a new project without hidden setup.
In general, features should be enabled by default unless there's a good reason not to, such as privacy risk, compatibility risk, performance risk, or platform limitations. Users should be able to opt in and out of features, and ideally high-level feature controls should also exist in PostHog project settings through remote config. When the reason is privacy-sensitive data, see Treat privacy as a product feature.
Don't break the host application
The SDK should never be the reason a customer's app crashes, slows down dramatically, fails to build, or starts behaving strangely.
Prefer graceful degradation over cleverness. If feature flag polling, replay capture, networking, storage, or background work fails, the app should keep running. In most cases, failing silently with useful debug logging is better than surprising the customer at runtime. The logger is our friend here: use it to explain what happened without making the host app pay for it.
Silent failure is not always the right default. Initialization errors, invalid configuration, unsupported hosts, project token problems, and explicit customer-called APIs should surface clear, idiomatic errors when the customer can act on them.
Retries and timeouts should be bounded, predictable, and documented. Avoid retry behavior that surprises customers, creates duplicate work, or hides persistent failures.
If an SDK can't support a platform, framework version, or runtime, make that clear at install time or startup. Don't make customers discover it through confusing production errors.
Keep dependencies boring
Every dependency adds size, security surface area, licensing questions, maintenance work, and compatibility risk. It can also introduce malware or compromised packages, naming clashes, dependency resolution surprises, runtime breakage from a transitive version change, and noticeably larger binaries or bundles. Use dependencies when they clearly improve the SDK, but be skeptical of adding them to the core path.
A good rule of thumb: basic event capture should work with as little extra machinery as the platform reasonably enables. Optional integrations can have optional dependencies, but the base SDK should stay lean.
If a specific feature needs a specific dependency, consider making that feature a separate module or package. For example, Session Replay may need image or video encoding dependencies, and iOS Error Tracking may need crash reporting dependencies. Users should have a clear way to opt out of that feature and dependency when they don't need it, can't ship it, or need a smaller binary.
That said, dependencies are sometimes the right choice. Some platforms don't provide safe basic primitives, such as an HTTP layer, storage, or concurrency tools. In those cases, use a boring, well-maintained dependency. If dependency risk is high but the code is small and stable, vendoring can also be a reasonable option. Document the tradeoff either way.
Respect the platform
Each SDK should feel natural in its language and ecosystem. Follow platform naming conventions, package manager expectations, async patterns, error handling style, logging conventions, and test tooling.
Consistency across PostHog SDKs is useful, but not at the cost of making a Ruby SDK feel like JavaScript, or a Swift SDK feel like Python. Prefer a small shared vocabulary – capture, identify, alias, flush, shutdown – and let the platform shape the details.
At the same time, don't make SDKs different for the sake of it. Users move between SDKs, and LLMs often help port examples from one language to another. Keep names, concepts, method behavior, and configuration shapes as close as the platform reasonably enables.
Be careful with resources
SDKs often run in hot paths, mobile apps, serverless functions, CLIs, browsers, background workers, and long-lived servers. Resource usage needs to be boring too.
Watch for memory growth, unbounded queues, aggressive timers, excessive network calls, large payloads, lock contention, startup cost, and battery usage. Add backpressure where possible. If the SDK holds data in memory, try to provide a clear maximum size for that data or queue, and make it configurable when customers may need to tune it.
If a customer reports one of these problems, consider adding a stress test or regression test with a safe threshold. The goal isn't to make performance tests flaky. It's to catch future PRs that clearly bring back the same class of problem.
Keep identity and state boring
Identity is one of the easiest places to confuse customers and corrupt data. distinct_id, anonymous IDs, identify, alias, reset/logout, group state, feature flag state, and persisted properties should behave predictably and, where possible, consistently across SDKs.
Be explicit about whether an SDK is stateful or stateless. Browser and mobile SDKs usually own local state because they persist anonymous IDs, queued data, flags, and replay/session context. Many server-side SDKs should be more stateless by default because one process can handle many users, tenants, requests, or jobs at the same time.
Don't accidentally make a stateless SDK stateful by storing per-user data globally. If state is needed, make the boundary obvious: request-scoped client, explicit context object, local storage, cookie, in-memory queue, or whatever is idiomatic for the platform.
Make SDKs thread-safe
Assume public SDK methods can be called from multiple threads, async tasks, workers, callbacks, request handlers, or lifecycle hooks. Queues, identity state, remote config, feature flag caches, loggers, and shutdown paths should be safe under concurrent access.
If a platform has a single-threaded runtime, still think about re-entrancy and async ordering. If something is not thread-safe, document it loudly and provide a safe path for normal usage.
Treat privacy as a product feature
PostHog helps customers understand users, but our SDKs should not collect sensitive data casually.
Be explicit about anything that can include personal data, request/response bodies, headers, screen contents, console logs, or exception context. Prefer opt-in for high-risk data, make masking and redaction easy, and document what leaves the device or server.
Think about security beyond privacy
Privacy is not the whole security story. SDKs should avoid exposing secrets, storing sensitive data unnecessarily, weakening TLS defaults, trusting unvalidated remote input, or making supply-chain risk worse.
Use platform-sandboxed storage where possible, such as app-scoped storage, Keychain/Keystore-style APIs for sensitive values, browser storage with the right assumptions, or restricted file permissions on servers. If data is only needed temporarily, prefer memory over durable storage.
Releases are part of the security model too. SDK publishing should be automated through CI and protected by an approval process, as described in the SDK release process. Avoid local machine publishing for official releases when CI can do it, because CI gives us clearer provenance, fewer long-lived credentials, and a better audit trail.
Design APIs for forward compatibility
SDK APIs live for a long time. Once a pattern is copied into thousands of apps, changing it gets expensive.
Keep the public API small, boring, and hard to misuse. Use options objects for things likely to grow. Avoid exposing internal concepts unless customers need them. Public APIs and configuration options should be unique: don't offer two or more ways to do the same thing unless there's a strong compatibility reason. Duplicate paths confuse humans, documentation, support, and LLMs.
Agents can help spec and drive SDK changes, especially repetitive cross-SDK work. Public APIs, configuration, defaults, and behavior that affects customers still need human review for ergonomics, platform fit, and long-term support cost.
Be careful not to expand the public API by accident. Exported helpers, leaked internal types, undocumented options, and test-only hooks can become APIs customers depend on. Keep internals private where the platform enables it. If something is experimental, say so clearly and consider keeping it behind an internal API until we're confident it should be public.
Prefer additive API changes over breaking ones. It's much easier to add a new method, option, or type than to remove one later. When you need a breaking change, respect the SDK's versioning scheme, make the migration obvious, document it clearly, and release it intentionally.
For larger migrations, write a migration doc and, where useful, an agent skill that can help apply the change across customer codebases. Try to batch breaking changes into a single major version instead of shipping a new breaking change every week.
Deprecate before removing
Use semver, or the ecosystem's closest equivalent, for public API changes. Removing a public method, field, configuration option, package, or behavior should usually wait for the next major version.
Before removing something, deprecate it first. Keep the deprecated method or option working until the major release, route it to the new implementation where possible, and log a clear runtime warning when it is used. The warning should say what changed, what to use instead, and where to find the migration guide.
Deprecation warnings should be useful, not noisy. Avoid logging the same warning thousands of times in a hot path if you can log it once per process, session, or call site.
Write less SDK code when the server can do it better
SDKs should collect useful context and send high-quality data. They should avoid owning complex business logic that can live safely on the server.
Server-side logic is easier to change, observe, roll back, and fix globally. SDK-side logic ships into customer apps and can take weeks, months, or years to update. Put logic in the SDK only when it needs local state, local performance, platform APIs, or offline behavior.
Make debugging humane
When something goes wrong, customers and support engineers need a path to answers.
Provide debug logging that can be enabled without rebuilding the world. Include enough information to understand initialization, dropped events, retries, network failures, feature flag decisions, and queue state. Avoid logging secrets. Project tokens are public identifiers, but other credentials are not.
Remember that SDKs often run on customer devices or infrastructure where we don't have access to logs. When it helps support and debugging, include minimal, high-value SDK state in captured data, recordings, or diagnostics. Session Replay is a good example: a small amount of SDK health context can make production issues much easier to investigate. Keep this data minimal, documented, and privacy-aware.
Test the boring paths and the weird paths
The happy path matters, but SDK bugs often hide in shutdown, retries, offline mode, old runtimes, ad blockers, proxies, clock skew, app backgrounding, forked processes, serverless cold starts, and partial initialization.
Prefer tests that match how customers use the SDK. Add small example apps where they help. For mobile and browser SDKs, remember that customers can't always roll out fixes quickly, so a little extra caution before release is worth it.
Treat docs and examples as part of the SDK
An SDK without good docs is only half shipped. Keep the quickstart current, show idiomatic examples, and explain common production setup: flushing on shutdown, identifying users, using custom hosts, handling feature flags, and enabling debug logs.
Each SDK should have a troubleshooting page for common install, build, configuration, network, and runtime errors.
Examples should be boring, copy-pasteable, and close to how customers write real production code in that ecosystem.
Public methods, configuration options, and types should have documentation comments in the platform's standard style, such as JSDoc, docstrings, KDoc, or Swift documentation comments. Write them for humans, but remember that LLMs and IDEs parse them too. A good comment explains what the method or option does, when to use it, defaults, side effects, and any privacy or performance caveats.
The public API reference should be complete and current. It should cover public methods, types, configuration options, defaults, side effects, return values, errors, and examples where they help.
Release like people depend on it
Because they do. Use semver or the ecosystem's closest equivalent, keep changelogs readable, call out breaking changes loudly, and follow the SDK release process. Official releases should be automated through CI and sit behind an approval process to reduce supply-chain risk.
Release cadence is a balance. Giant releases are hard to review, hard to debug, and hard to roll back, but releasing every tiny change can also create noise and upgrade fatigue. Prefer coherent releases: small enough to understand, grouped enough to be useful, and clearly documented so customers know whether they should care.
The right cadence also depends on the platform and ecosystem. Web and server SDK users can often upgrade quickly through a package manager, but mobile, desktop, game engine, and enterprise customers may deal with app store review, slow adoption, long release trains, or internal approval processes.
Keep changelogs and version bumps accurate
A changelog is customer-facing release documentation, not just release metadata. For SDKs using changesets, the changelog entry is part of the code change. As the author of a change, you're responsible for writing a meaningful summary and choosing the correct semver bump before the PR lands. Take care to ensure that the entry accurately reflects what changed, who it may affect, and whether customers need to take action. If they do, describe that action clearly.
Use semver, or the ecosystem's closest equivalent:
Patch versions are for backward-compatible bug fixes, security fixes, documentation/package metadata corrections, and internal changes that don't add customer-facing API or behavior. A user should be able to upgrade a patch release without changing their code or expectations.
Minor versions are for backward-compatible additions or behavior improvements: new public methods, options, integrations, supported platforms, or feature support. Existing code should continue to compile, run, and behave as before.
Major versions are for breaking changes: removing or renaming public APIs, changing method signatures or return types, changing default behavior in a way customers may rely on, dropping supported platforms/runtime versions, changing persisted data formats without safe migration, or making previously valid configuration invalid. Major version bumps are ideally planned in advance, and should typically be avoided unless absolutely necessary.
If a release does include a breaking change, call it out clearly in the changelog and provide migration guidance. Before introducing a breaking change, consider alternative solutions by asking yourself:
Could this change have been written in a backward-compatible manner?
If this supersedes an existing public API or behavior, should the old one be deprecated first?
Can the new behavior be introduced as an opt-in option first, or can the old behavior remain available through a defaulted option or alias?
Do we understand who is affected and how hard migration will be?
Should this be batched with other breaking changes in the next major release?
Document decisions and sharp edges
If an SDK supports only certain platform versions, has unusual threading behavior, drops events under pressure, stores data locally, or handles privacy-sensitive data, write it down.
Most of the time, a code comment near the decision is enough. For bigger decisions, write an RFC or add the guidance here if it applies across SDKs. This isn't bureaucracy. It's how we avoid the next contributor rediscovering the same tradeoff six months later.
There is now a small, dedicated SDK team at PostHog (@PostHog/team-client-libraries) that helps drive direction and coordination. However, SDK development and maintenance remains a collaborative effort across the engineering organization. @PostHog/client-libraries-approvers exists in GitHub to coordinate the collaboration for those who are more interested than normal in the development of these SDKs.
How SDK work gets done
SDKs are maintained by engineers across different teams who either:
Contribute improvements when their team's product needs SDK changes (e.g., adding session replay support to a new SDK)
Pick up SDK work during hack days or when they have spare capacity
This distributed model means SDKs get attention from engineers with diverse expertise, and ownership is shared across the company.
Want to get more deeply involved?
If you're interested in contributing to our SDKs — whether that's fixing bugs, adding features, or improving documentation — drop a message in #team-client-libraries. We're always happy to have more people helping out, and it's a great way to learn about different parts of the PostHog ecosystem.
You can also sign up for the SDK support rotation to get hands-on experience with SDK issues.
Slack channels
#team-client-libraries – Main channel for SDK discussions and general questions
#support-client-libraries – Main channel for SDK support discussions, handovers between support rotation engineers
#approvals-client-libraries – Where release approval requests are posted (see Releases)
What are our SDKs?
There are too many to have a static list here. Check the libraries docs to learn more about them.
This guide documents our semi-automated release process for PostHog SDKs. Each SDK repository uses a GitHub App with restricted permissions to handle releases securely, requiring team approval before any release is published. Commits must be signed, as in every PostHog repository.
If you're creating a new SDK/repo that must be published you MUST implement this approach.
How it works
Our SDK release process uses a dedicated GitHub App per repository that can push directly to the main branch (bypassing branch protections) while still requiring human approval through GitHub Environments. This gives us:
Security: The app only has access to the specific repository it needs
Auditability: All releases require approval from the Client Libraries team
Automation: Changelog generation, version bumping, and publishing are handled automatically
Setting up releases for a new SDK
When creating a new SDK, or migrating an existing one to the new workflow, follow these steps to set up the release infrastructure.
Most of these steps require super administrator privileges on GitHub. Organization-level access is temporarily required to complete the setup — request it before you start, and it can be revoked once the release infrastructure is in place.
Description: Should be "Used to release new versions of posthog-<sdk_name> (e.g. "Used to release new versions of posthog-go.")
Homepage URL: Point to the SDK's docs page on posthog.com (e.g., https://posthog.com/docs/libraries/go)
Webhook: Disable (uncheck "Active")
Permissions: Under "Repository permissions", set only:
Contents: Read and write
Note: If your app needs to open PRs in other repositories and assign teams or members as reviewers (e.g., the posthog-js upgrader opens PRs from posthog-js to posthog and assigns the client-libraries and client-libraries-approvers teams), you also need to add under "Organization permissions":
- Members: Read-only
Where can this GitHub App be installed? Keep it restricted to "Only on this account"
Click the big "Generate a private key" button to generate a private key and save it locally — you'll need it later
Also save the "App ID" number - you'll need it later
Go to Install App in the sidebar
Install the app in the PostHog organization, restricting it to only the SDK repository
2. Expose proper access to client libraries teams
In your SDK repository settings:
Verify that both @PostHog/client-libraries-approvers and @PostHog/team-client-libraries teams have at least read access to the repository. This is required for them to be able to approve release workflows.
Access "Collaborators and teams"
Make sure both teams are added as collaborators with at least write access
For new repositories, make sure Enable release immutability is enabled in the repository settings — you'll find it under Settings → General
3. Create a release environment
In your SDK repository settings:
Go to Environments and create a new environment named Release
Configure protection rules:
Required reviewers: Add PostHog/client-libraries-approvers and PostHog/team-client-libraries as the only teams allowed to approve this release
Prevent self-review:Check this box
Allow administrators to bypass:Uncheck this box
Click Save protection rules to enforce them before configuring deployment branches — the deployment branches and tags settings below save on their own, and clicking "Save protection rules" afterwards resets them
Configure deployment branches and tags:
Deployment branches and tags: Select Selected branches and tags and add main as the only selected branch or tag
If the package manager requires publishing from tags, such as pub.dev, also add [0-9]*.[0-9]*.[0-9]* as an allowed deployment branch or tag pattern
Image: Protection rules)
Add environment secrets:
GH_APP_POSTHOG_<SDK_NAME>_RELEASER_APP_ID — Copy the App ID from your GitHub App settings
GH_APP_POSTHOG_<SDK_NAME>_RELEASER_PRIVATE_KEY — Paste the private key you downloaded, include the trailing newline
Easiest way to get the private key value with the correct formatting is via cat ~/Downloads/release-posthog-<sdk_name>-private-key.pem | pbcopy on Mac or type release-posthog-<sdk_name>-private-key.pem | pbcopy
Replace <SDK_NAME> with your SDK name in uppercase with underscores (e.g., GH_APP_POSTHOG_GO_RELEASER_APP_ID, GH_APP_POSTHOG_GO_RELEASER_PRIVATE_KEY)
Image: Environment secrets
4. Add app to bypass lists
The GitHub App needs to bypass certain protections to push release commits directly.
Select your newly created GitHub App (Releaser (<sdk_name>))
Click the three-dot menu and choose Exempt
Save the ruleset
Image: CodeQL bypass exemption
Repository PR bypass
Go back to your SDK repository settings
Navigate to Rules → Rulesets
Open the ruleset that requires PRs (may have various names)
If this ruleset doesn't exist, create one requiring PRs and reviews from codeowners which should be @PostHog/client-libraries-approvers for all files
Under Bypass list, click Add bypass
Select your GitHub App (Releaser (<sdk_name>))
Click the three-dot menu and choose Exempt
Save the ruleset
Image: Repository PR bypass
Don't add a Require signed commits rule at the repo level. The org-wide ruleset already requires signed commits in every repo, and a duplicate repo rule only adds another bypass list to maintain. Note that this bypass exempts the app from the pull request requirement, not from signing: the org signing ruleset has no bypass actors, and the release workflows create their commits through the GitHub API, so they are signed like any other.
Check for classic branch protection too. The steps above exempt the app in a ruleset, but a repository can also have classic branch protection under Settings → Branches → Branch protection rules, which GitHub enforces alongside rulesets and which has its own separate bypass list. If a classic rule requires pull requests, the release still fails with protected branch 'main' check failed: Changes must be made through a pull request even after the ruleset exemption. Remove the classic rule, since the ruleset already covers it, or add the app to its bypass settings as well. Older repos are most likely to have this; newer ones tend to be rulesets-only.
5. Grant access to organization secrets
The release workflow needs access to shared organization secrets. Grant your SDK repository access to the below organization secrets in the organization settings:
Secrets:
SLACK_CLIENT_LIBRARIES_BOT_TOKEN
POSTHOG_PROJECT_API_KEY
Variables:
GROUP_CLIENT_LIBRARIES_SLACK_GROUP_ID
SLACK_APPROVALS_CLIENT_LIBRARIES_CHANNEL_ID
6. Add the release workflow
Important: Our release workflows use GitHub Actions OIDC tokens for secure authentication with package registries. Make sure your workflow uses a version that supports OIDC for your registry:
- npm: Node.js v22+
Copy the release workflow from posthog-php — it's the reference implementation for new SDKs and includes security hardening the older workflows lack:
The release candidate is prepared once, uploaded as a patch artifact, and verified by sha256 before publishing — the approved diff is exactly what ships
persist-credentials: false on every checkout
The version bump script is pinned by sha256, so it can't be swapped out between approval and publish
Checks that the tag and GitHub release don't already exist, and that main hasn't moved since the release candidate was prepared
Minimal permissions on every job
Adapt it to your SDK:
Update the environment variable prefix to match your SDK name
Modify the changelog generation logic if needed for your language's conventions
Update the version bumping logic for your package manager (npm, pip, etc.)
Update the publishing steps for your package registry
Don't re-run build/test in the release workflow. PR CI and the CI run on push to main already gate what lands on main, so the release workflow should only version, verify, and publish — re-running the build and test suite there just slows down releases without adding safety.
npm packages: set up trusted publishing before enabling the workflow
This applies only to npm publishing (not other package registries).
If your SDK publishes to npm using OIDC trusted publishing, set it up before allowing your GitHub Actions workflow to publish.
New package (never published before)
OIDC trusted publishing can only be _configured_ for a package that already exists on npm. For a brand-new package there's nothing to attach the trusted publisher to yet, so the workflow's very first publish can't use OIDC and will fail with a 404.
To avoid this, bootstrap the package and configure its trusted publisher before enabling the workflow:
Log in to npm (npm login) as a member of the npm org.
Run setup-npm-trusted-publish to publish a placeholder so the package exists on the registry. This is a manual, authenticated publish (not OIDC). The command is self-contained and publishes from its own temp directory using your global npm auth, so the working directory doesn't matter.
Follow the CLI prompts to configure the Trusted Publisher for the placeholder:
Choose GitHub Actions as the publisher.
Fill in the repo details (PostHog/<repo>) and the release workflow filename (e.g. release.yml).
Only set the environment name (e.g. NPM Release) if the publish job itself runs inside that GitHub environment (see the callout below).
Under Allowed actions, check Allow npm publish.
This bootstraps npm trusted publishing for the package so future automated releases can publish successfully.
Existing package
If the package has already been published, you can configure trusted publishing directly in npm package settings instead.
Casing matters when configuring the trusted publisher. npm validates the GitHub organization, repository, and workflow filename against the values GitHub puts in the OIDC token, and those values are case-sensitive. The PostHog GitHub organization is PostHog (capital P and H) — entering posthog causes the publish to fail with a misleading 404 Not Found from npm, even though the package and the workflow exist. Use PostHog exactly when setting up or editing the trusted publisher, both via setup-npm-trusted-publish and in the npm package settings UI.
Only set an environment if the publish job runs in it. npm also validates the environment claim in the OIDC token against the trusted publisher settings. Fill in an environment name only if the job that runs npm publish has environment: <name> set in the workflow. If a GitHub environment is only used to gate approval in an earlier job, leave the environment field blank, otherwise the publish fails with a misleading 404 Not Found error.
7. Update the README
Add a section to your SDK's README explaining that releases are semi-automatic and link to the #approvals-client-libraries Slack channel where approval requests are posted.
8. Create required labels
Make sure the repository includes the release label, it's used to trigger new releases.
If you're not using something like changesets or sampo that automatically generates version bump labels, create the following labels as well to indicate the type of release:
bump-patch
bump-minor
bump-major
9. Open a PR
Create a PR with the new release.yml workflow and request a review from @PostHog/client-libraries-approvers. There is now a small, dedicated SDK team at PostHog (@PostHog/team-client-libraries) that helps drive direction and coordination. However, SDK development and maintenance remains a collaborative effort across the engineering organization.
Triggering a release
Once set up, releases are triggered by having a release label added to the PR alongside a changesets(or matching bump-* tag). Once a PR is merged, the environment workflow will kick up and someone from the @PostHog/client-libraries-approvers team will have to approve it on #approvals-client-libraries.
For changelog and version management, prefer JS changesets (@changesets/cli) even for non-JS SDKs — it only needs Node in CI, which the release tooling already uses. This is what posthog-php does. Some SDKs use sampo, a language-agnostic take on changesets, but it pulls in a Rust toolchain and is slower in CI, so we don't recommend it for new SDKs.
Troubleshooting
Access token expired or revoked when running npm publish
If you see the error "Access token expired or revoked. Please try logging in again" when publishing with npm publish — even though your credentials and tokens are correctly configured — the issue may be with npm's token handling itself.
Solution: Migrate your project to use a pnpm workspace and publish with pnpm publish instead. pnpm handles authentication differently and isn't affected by this issue.
The SDK Support Hero rotation is managed by the . Each week, one member of the team is designated the SDK Support Hero. The schedule is managed in incident.io.
Your primary responsibility is to make sure SDK questions get some love — across all SDKs, including mobile. During the rotation, please keep an eye on:
Escalated SDK tickets in PostHog Support — your team's view is bookmarked in #support-client-libraries
Firstly, try to stay on top of new escalated tickets in PostHog Support and GitHub issues, and make sure that issues related to a specific team are routed to them. If there is a relevant team (e.g. the issue is related to session replay in posthog-js), you can assign the ticket to that team, and use the team's label in GitHub. If there is no relevant team for a GitHub issue, please label with SDK Support Hero. Feel free to try to fix things yourself before tagging the team.
Next, please work on SDK tickets in PostHog Support, and GitHub issues labeled SDK Support Hero (and unlabeled, but please label these!). You can use your own judgement to decide which issues to work on but please consider effort / reward / urgency / your skill set. For example, posthog-js usually has the most issues, but if you're a Python expert, you might want to focus on posthog-python.
For mobile SDK issues, prioritize accordingly — rolling out fixes on mobile apps may take weeks or even months, so faster turnaround on these is important. Make sure, however, to validate changes carefully, avoid breaking changes and think through edge cases before shipping, since our ability to correct mistakes after release is significantly constrained.
At the end of the week, please write a public handover message in #support-client-libraries, to let the next person know what work is in progress, let the team know how the support rotation is going in general, and to share any learnings or feedback.
Connecting to GitHub requires an SSH key (unless using HTTPS). Traditional SSH keys live as text files on your filesystem, making them vulnerable to theft or misuse by malware. We explicitly prohibit the use of SSH keys stored on your filesystem.
Use Secretive or 1Password to generate and store your SSH key. We have a slight preference for Secretive because it stores your key in the macOS Secure Enclave, ensuring the key can never be exported or extracted, even by malware. Always use ECDSA or Ed25519 — don't use RSA.
Note: The default shell on macOS is zsh, so the ~/.zshrc instructions below apply to you unless you've deliberately switched to a different shell. If you're not sure which shell you're using, run echo $SHELL in your terminal to check.
Setting up with Secretive
Open Secretive and click the + button to create a new key.
Name your key "GitHub SSH" and select Notify in the Protection Level dropdown.
For additional protection, select Require Authentication instead. This will require you to use Touch ID each time the key is accessed.
Go to Secretive > Integrations in the menu bar.
Select your shell on the left side set the SSH_AUTH_SOCK environment variable as instructed. For zsh, add the following to your ~/.zshrc:
A git commit's Author field is completely user controllable and can be forged. Signing your commits cryptographically proves you authored them, preventing impersonation and confusion. Signing is required, not optional: an org-wide GitHub ruleset rejects unsigned commits in every PostHog repository, on every branch. Set this up before your first push, rather than when a push fails. This applies to automation too, see signing commits from workflows.
You can sign commits with either Secretive or 1Password. We have a slight preference for Secretive because it stores your key in the macOS Secure Enclave, ensuring the key can never be exported or extracted, even by malware.
Setting up with Secretive
Open Secretive and click the + button to create a new key.
Name your key "Git signing key" and select Notify in the Protection Level dropdown.
Go to Secretive > Integrations in the menu bar.
Click Git Signing and select "Git signing key" from the Secret dropdown.
Copy and paste the ~/.gitconfig and ~/.gitallowedsigners snippets into their respective files.
If you already have content in ~/.gitconfig, merge the new sections into the existing file rather than replacing it.
If you've previously configured commit signing (with a different SSH key, a GPG key, or an older Secretive key), replace any existing signingkey, gpgsign, gpg.format, and allowedSignersFile entries — don't append duplicates. Git will silently use the last value, but a .gitconfig with multiple conflicting signingkey lines is hard to reason about. Confirm the active key afterwards with git config --get user.signingkey.
The ~/.gitallowedsigners file is used by git log --show-signature for local verification. Each line is <your-git-email> <key-type> <public-key>, e.g. you@posthog.com ecdsa-sha2-nistp256 AAAA... Git-Signing-Key@.... If you skip it, signing still works but local verification will report No principal matched.
Select your shell on the left side of Secretive and set the SSH_AUTH_SOCK environment variable as instructed. For zsh, add the following to your ~/.zshrc:
Your ~/.gitconfig now has a signingkey pointing to a file. Copy your public key to the clipboard:
cat <path-from-signingkey> | pbcopy
Go to your GitHub SSH keys settings and add a new SSH key. Paste your public key and set the key type to Signing Key.
GitHub treats Authentication Key and Signing Key as separate roles, even for the same key. If you get "Key is already in use", it most likely means you already added this key as an Authentication Key (from the SSH Keys setup above). The same key can serve both roles — but you have to add it once for each. Add it again with key type Signing Key.
Verify the signature locally before pushing. Create an empty commit on a new branch:
You should see a fingerprint followed by G (good signature). The fingerprint must match the Signing Key you just added on GitHub — find it at GitHub SSH keys settings under the Signing keys heading. If it matches an Authentication key entry instead, your user.signingkey in ~/.gitconfig is pointing at the wrong file — fix it before pushing.
Push the branch to GitHub — you should see a green Verified badge on the commit.
Once commit signing is configured, enable the option in your GitHub Profile to "Flag unsigned commits as unverified". The org ruleset already blocks unsigned commits in PostHog repos, but this marks any commit attributed to your email and not signed by you as Unverified everywhere else on GitHub, including your personal repos.
Troubleshooting
If using iTerm/Cursor/GitHub Desktop/Sourcetree/etc., you may be endlessly prompted to "access data from other apps". You can fix this by granting the app Full Disk Access in System Settings > Privacy & Security > Full Disk Access.
If you are prompted to complete Touch ID each time you commit, your signing key is using a Protection Level of Require Authentication. Re-follow the instructions above to generate a new signing key with a Protection Level of Notify.
GitHub rejects your push with GH013: Commits must have verified signatures even though the commits look signed locally. The commit was signed with a key GitHub doesn't recognize as a Signing Key — usually because (a) the key is only registered as an Authentication Key, or (b) your user.signingkey points at the wrong file. Confirm with git log -1 --format='%GK' and cross-check the fingerprint against your GitHub keys. Once the right key is registered as a Signing Key, re-sign the existing commit:
Use --force-with-lease rather than plain --force — it refuses the push if someone else has pushed to the branch since you last fetched.
GitHub Actions
Great care should be taken when writing or modifying a GitHub Actions workflow. Actions can access (and exfiltrate) secrets scoped to the repo. We scan workflows with Semgrep and CodeQL for common misconfigurations.
Authentication
Most Actions use the default GITHUB_TOKEN, whose permissions can be scoped via the permissions property. However, GITHUB_TOKEN cannot trigger other workflows, so commits or PRs created by an Action won't run CI, leaving PRs unmergeable without manual intervention. The workaround is a GitHub App.
Personal access tokens are not an option here. Classic PATs are blocked org-wide. Fine-grained PATs require approval and are generally not approved, because they are tied to an individual user and break when that user leaves PostHog.
Use a finely scoped, purpose-specific GitHub App instead. Scope each App to its use case and ideally a single repo. Prefer creating a new App over expanding an existing one's permissions, otherwise every Action using that App inherits permissions it doesn't need.
Send a message in #team-security if you need help setting up a new GitHub App.
Signing commits from workflows
The org ruleset applies to Actions too. A workflow that commits with git push is rejected, because there is no signing key on the runner. Create the commit through the GitHub API instead, which GitHub signs with its own key. In practice that means one of:
planetscale/ghcommit-action, a wrapper around the GraphQL createCommitOnBranch mutation. This is what most of our workflows use.
Signing only works with a bot-generated token, meaning GITHUB_TOKEN or a GitHub App installation token. With a PAT, sign-commits and its equivalents are a silent no-op: the action reports success, the commit is not signed, and the push is rejected.
Two limits of createCommitOnBranch to plan for. Its FileAddition input takes only path and contents, so it cannot set a file's executable bit. And it sends expectedHeadOid, so the commit is rejected if the branch moved since the run read the head. Re-read the head and retry rather than forcing.
External contributors
In public repos, Actions may run against PRs written by external contributors. These PRs should be reviewed thoroughly before approving workflows to run against them. Otherwise, a malicious PR could gain access to and steal all of the secrets available to the repo.
Managing secrets
AWS
Application secrets are stored in AWS Secrets Manager. To modify an app's secrets, use our secrets tool.
GitHub
Secrets used by GitHub Actions are stored in GitHub secrets. All secrets should be stored in our GitHub org rather than in an individual repo. This allows us to more easily reuse secrets across repos, and also provides a holistic view of all of our secrets. The org secret should be scoped to the specific repos that need it.
Reporting a security issue
If you believe we've been hit by a security issue, raise an incident. In the best case, it'll mean security folks look at it ASAP. In the worst case, it's a false positive and we can close the incident.
Batch events into $snapshot_items arrays with a $session_id (UUIDv7)
Send to /s/ (replay capture endpoint) via $snapshot events
Events include metadata: $window_id, $session_id, $snapshot_source (Web/Mobile), timestamps, distinct_id
2. Ingestion pipeline
Phase 1: Rust capture service (recordings mode)
rust/capture/src/router.rs:235 and rust/capture/src/v0_endpoint.rs:342
Separate capture service instance running with CAPTURE_MODE=recordings
Receives POST to /s/ endpoint (routed to recording handler)
Validates session_id (rejects IDs >70 chars or with non-alphanumeric characters except hyphens)
Calls process_replay_events to transform events into $snapshot_items format
Publishes to session_recording_snapshot_item_events Kafka topic
Or session_recording_snapshot_item_overflow if session is billing-limited (checked via Redis) OR if session id is present in Redis key @posthog/capture-overflow/replay (operational/load management)
Kafka sink (rust/capture/src/sinks/kafka.rs):
Produces to primary topic: KAFKA_SESSION_RECORDING_SNAPSHOT_ITEM_EVENTS
Auto-trigger on save → Background LTS copy task (via post_save signal)
Periodic sweep → Finds recordings 24hrs-90days old without LTS path, queues background tasks
Note: Regular session recordings (not pinned/persisted) do NOT write to PostgreSQL - they only exist in ClickHouse session_replay_events table until explicitly pinned or persisted as LTS.
Tracking and managing usage is one of the core responsibilities of the . If we do it wrong, we don't get paid.
Each organization's usage is calculated once per day and saved in a usage report. This usage report is sent to the billing service, which saves the report and sends the usage along to Stripe for the customer's subscription, if one exists.
Usage reports
Usage reports are largely generated within posthog/posthog - because that's where the usage happens. Every day at midnight BST a cron job runs in each instance (US and EU) to calculate usage for every single organization in the instance.
Occasionally the cron will get interrupted - when this happens the billing service won't receive or store any of the reports, and usage won't be sent to Stripe. You'll notice that usage reports have failed in two ways:
When looking at the Revenue dashboard in Metabase, you'll see that there are fewer reports than previous days, and one of the instance (generally US) will show 0 reports sent.
When looking at the Usage report insight on the Growth dashboard you'll see a big dip in an otherwise steady trend.
We don't currently have a way to automatically re-run failed usage reporting, so we have to do it manually. To do so, you'll need to follow the instructions to connect to PostHog Cloud infra. Once you do so you can run a management command to re-run the usage reports for a specific date:
where the date is the day that the usage report would have been run, so is one day past the date where usage reports are missing. For instance, if we had 0 usage reports on May 11, the date you'd use in the command is actually May 12 (because usage reports are reporting usage for the previous day).
It is recommended to run async using the --async 1 option so you don't need to wait for all the billing requests to be completed synchronously. If you use this option, it'll finish with Done!. When using this option, it's important to go back and ensure it is completed and there are no errors / Clickhouse timeouts.
If you run the command without the async option it can take a while to run, and if it gets interrupted (eg because pods were turned over with a deploy) it'll fail again with command terminated with exit code 137. Simply reconnect and try again. If it's successful, you'll get a log like 21262 Reports sent!.
As a product engineer, you’re encouraged to visit customers at their offices to gather feedback and ship features or improvements on the spot.
While PostHog is fully remote - we optimize for async work, write things down, and talk to users remotely – the reality is that occasional in-person time with customers is highly valuable. Some products are hard to dogfood properly, and it can be tricky to fully grasp specific workflows or see how high-scale users actually operate.
In-person visits let you notice things that don’t surface on calls: team dynamics, tools they rely on day to day and small but important friction points that get lost in remote conversations. People also tend to hold back or polish their feedback when writing it down – they might dismiss a detail as unimportant, or assume you already know something when you don’t. Seeing it all unfold in real life can surface insights you’d never get otherwise. All of this makes a customer visit time well spent.
Which customer should you visit? Sometimes, when interacting with a customer on Slack, you’ll notice an obvious click with someone. You’ll know when this happens – they’re friendly, proactive with feedback, and genuinely interested in making the product better. They might also be driving heavy usage, with multiple power users, or even adoption across different teams. If you come across a customer like this and feel curious to dig deeper into how they use PostHog, that’s a strong sign they’d be a good candidate for a visit. Of course, this makes the most sense for customers whose teams are at least partly in-office – otherwise you won’t get the real benefit of seeing how they work together day to day.
Here’s one way to organize a great customer visit. None of this is set in stone, so feel free to adapt, and pay attention to what the customer is comfortable with.
1. Identify the biggest areas for improvement
Review the customer's Slack channel and pull together a list of the most pressing issues from the past few months. For larger customers, there may also be lots of context in BuildBetter and past recorded calls, as well as information from their sales or CS person. Focus on understanding what they’re struggling with most and which upcoming features matter the most to them.
2. Lock in dates and the point of contact
Find a single point of contact to help organize the visit. Share with them the list of topics and pain points, and explain that you’d like to meet in person to get a deeper understanding. Don’t underestimate this step – even if the company is very engaged on Slack, people are busy and organizing something optional like this isn’t always their top priority. Having one person on their side makes it much easier to get dates confirmed, which is the main thing you need at this stage. You can sort out the details and a more precise agenda later.
As for the duration, two to three days is usually a sweet spot – enough time to spend quality time with the team without overstaying or being a distraction in their office. Use your best judgment here and agree on the timing with your point of contact. A nice option can be to tie the visit onto a small-team offsite – if the team is already traveling, extending for a couple of days can allow some extra time for this.
For large customers with an account manager assigned, it’s super valuable to bring them along. They often already have a strong relationship with the customer, can ask additional questions you might not think of, and can keep things like scheduling, follow-ups, and expectation-setting smoother.
3. Book the travel
Book flights and tickets as early as possible to avoid high prices. Reach out to the People & Ops team to get a budget approved.
4. Plan the agenda
Work with your point of contact to set the agenda. Aim to get dedicated time with several people who use the product. A one-hour session is usually enough to go deep and uncover useful insights. Also offer other formats, like a company-wide training or Q&A session, and let your POC guide you on what’s most valuable for their team.
5. Deep prep
A few days before traveling, take a deep dive into how their users are actually using the product. Watch session recordings, look at the kinds of records they create, and try to spot patterns. For example, in the case of experiments, check which types of metrics they use most often, how many they create per week, and whether there are obvious points of friction. Alongside this, prepare a list of questions that can help uncover deeper insights during the sessions.
At the onsite
Run the sessions! Let users show you how they use the product in real time and as naturally as possible. Give them space to talk, ask questions to dig deeper, and don’t be afraid to let the conversation go off on tangents, as those often reveal the most interesting insights.
In between the sessions you’ll have opportunities to code. It makes sense to prioritize small improvements you can ship and demo on the same day – this kind of quick turnaround leaves a strong impression. It’s also common for team members to approach you with questions, sometimes even unrelated to your product area. Be ready for this and go out of your way to help. Solving problems in real time is one of the best parts of being there in person.
After the onsite
Revisit the transcripts of all sessions – you should record everything in Buildbetter or a similar tool. Share what you’ve learned with your team and discuss if any quarterly goals need to be re-prioritized based on the learnings. Summarize the features or improvements you shipped during or right after the visit and send a thank-you message to the customer's Slack that lists them clearly.
It's important for visibility to notate on the account that a customer visit took place. We can do this in Vitally, by creating a new note on the account, with the "On-site" category and copying any known people on the account to be aware of the note content. This can be helpful in many ways even if no primary person at PostHog is managing their account today. BuildBetter calls should automatically attach to the account along with any existing email conversations.
Just as important is following up in the weeks after. Customers should feel the visit was worth their time, and a big part of that is quickly actioning the items they raised, even if it’s just small fixes or clear updates on progress. This builds excitement and goodwill, shows immediate impact, and shows them it was worth investing their time with you. Most importantly, you’ll walk away with a much deeper understanding of how your product is really used.
PostHog AI lets users interact with PostHog's products through a chat interface and other shortcuts throughout the platform. The is responsible for building and maintaining the AI platform.
What is PostHog AI?
PostHog AI enables users to:
Ask questions about their data in natural language
Generate insights and reports through conversation
Navigate PostHog's products using AI assistance
Automate common analytics tasks
We want Max to work with _every_ PostHog product, so that we can at some stage make a chat (or even complete automation with approval steps as necessary) the default experience for people using PostHog, then resorting to clicking the UX as the backup option for _most_ tasks.
How to work with the PostHog AI team
Products already integrated with Max always have a supporting engineer assigned on the Max team.
This naturally distributes AI knowledge throughout the organization, while ensuring high-quality AI features that integrate properly with the platform. Implementing something new, missing features in the Max API, or seeing failures? Your supporting engineer is your go-to! Tag them directly on your PRs and questions.
If your team is integrating AI features for the first time – the PostHog AI team will do their best to assign a supporting engineer.
Just message about your plans in the #team-max-ai channel in Slack.
| Product | Supporting engineer on the PostHog AI team | | ------------------- | ------------------------------------------------------------------------------------------------------------- | | Product analytics | Emanuele Capparelli | | Data warehouse | Michael Matloka | | Session replay | Alex Lebedev | | CDP | Georgiy Tarasov | | \[Insert your team] | Shoot #team-max-ai a message! |
Getting started
If you need AI capabilities for your product area:
Reach out early: Contact the PostHog AI team lead at #team-max-ai in Slack to discuss your requirements
Define the use case: Be specific about what AI functionality you need, or consult with us if you're trying to flesh out ideas
Plan the collaboration: Work with the PostHog AI team to determine the best approach (e.g., sending an engineer to your team for a sprint or a few sprints vs. building the feature in PostHog AI directly without your involvement, or you just being able to do it solo)
Coordinate sprints: Align on timing and resource allocation if needed. This shouldn't feel like a heavyweight process, if it is - we should change it
Best practices
Start small: Begin with simple AI features and iterate based on user feedback. A lot of automation can be broken down into smaller, automatable steps!
Avoid death by random AI widgets - maintain consistency: Ensure AI features follow PostHog's design patterns and user experience standards. PostHog AI team can help if you are missing a UX pattern.
We write and publish a lot of content at PostHog. focuses on this, but we also publish writing on our blog from anyone, including engineers. These usually look like:
It helps us attract users, customers, and talented teammates.
It's a reference point you can point at for future engineers, customers, and teammates.
What to write about
PostHog's audience (ICP) is the same as you: the people building products at high-growth startups. This means the posts you're interested in are likely the same as what they're interested in.
There's a couple of frames that can help you decide if something is interesting enough to write about:
Is it interesting enough to write up and sending to an engineering friend?
Would it be useful for you two years ago?
If yes, then it's probably interesting enough to blog about. There's a huge amount that is obvious to you but not obvious to others. You're more of an expert than you think you are, especially when it comes to your personal experiences.
How to write
Start by thinking about a reader's perspective: What will be interesting or useful to them? What do you want readers to come away remembering?
Don't worry about some "PostHog designated style," there is no such thing. Write like you would in an email, Slack message, or RFC. Read through our style guide though, especially the first General principles section, but don't obsess over perfectly following it. The can help you and there's always exceptions.
AI is helpful for research, outlining, line-editing, and finding weak spots, but please don't get it to write the entire piece for you. Readers can tell when something is written by AI and discount it.
If you need a skeleton of post, many technical blogs look like this:
Hook: The surprising result or pain you experience.
Context: What the state of things were. Enough so readers can follow.
Journey: The investigation of what you tried, what failed, and what succeeded. Include the "takeaways" as part of the journey.
Resolution: What actually changed? Give specifics, numbers, and/or visuals if you can.
Use descriptive titles along the way rather generic ones like "Background" or "What we learned." If someone was skimming the piece, would the title give them the details they were looking for?
The details about publishing
The general workflow for a post looks like this:
Have an idea.
Share in the #content-and-video-ideas Slack channel. This is optional, but useful if you want feedback on the idea first. You can also just write up an outline or draft right away.
Open pull request of your draft in posthog.com. Blogs go in the /contents/blog folder (you can see the format from other blogs there).
Get review from someone from the and (optionally) a relevant teammate. If you're not sure who to ask, message the #team-editorial Slack channel with a link to your PR.
Iterate on feedback (usual 1-2 rounds).
Fix formatting and styling details ( can help with this). Check the deployment preview to see how it looks.
Merge and it's automatically published on posthog.com.
Once published, you can share it on social (LinkedIn, X, Bluesky, etc.), with relevant coworkers, and in relevant communities (like HackerNews, but be careful not to spam or ask for upvotes). This might feel a little cringe, but it's critical for actually getting people to read your writing.
Remember, you're the driver on all of this. You don't need someone's approval to write a blog.
Product engineers are responsible for writing and maintaining documentation for their products. This page is a guide to help you do this.
Ownership
High-quality docs require the expertise and context of the engineers building them, which is why you own your product's documentation.
Docs are extra important in the age of AI. All of our docs eventually make their way into the training data of newer foundation models. The quality and accuracy of your docs directly affect how people discover your product through LLMs.
AI search is our fastest-growing channel for user signups by far. So remember to update your docs and keep them up to date.
What about the so-called Wizard & Docs team?
The can help you, but they can't write docs for everyone. They are responsible for improving the docs as a knowledge base. This means:
Reviewing and improving docs PRs created by product teams
Shipping docs content based on prioritized feedback and emerging use cases
Building tools and systems to improve baseline quality and structure
Creating context services that power agents like the AI wizard
Working on large scale docs projects
If you want their input, hit them up in #team-wizard-and-docs or tag @team-wizard-and-docs in GitHub.
When you ship a new user-facing product or feature. Write docs for big product launches before they release (during early access or beta). Smaller features and updates can wait until after they are shipped.
When you recognize a confusion or gap in users' understanding of your product. This could be based on support tickets, sales requests, or just user feedback.
When you update product behavior or interfaces. Check if the docs need to be updated with new information or instructions.
Basically, if users could self-serve and use your product, but aren't, you should write docs to help them do so. Write the obvious docs before users start asking you obvious questions.
What about features behind a feature flag? If you are releasing a product to users, even a small number of them, you should write docs for it. Include what stage the feature is at (private alpha, beta, etc. is fine). This helps ensure users can successfully use it and provides the added benefit of drumming up demand from those who discover it.
What should I write docs about?
Docs should help people:
Get started with your product or feature. Installing it, setting it up, and finding it in PostHog.
Understand what your product does, including an as complete as possible list of features and their details.
Make the most of your product by detailing common use cases, concepts related to your product, answering common questions, and more.
Write the docs you would want to read if you were a user.
The has created a guide on how to write product docs for you to follow. It walks through how to structure and write your product docs in detail. Start there.
Where do docs live?
Nearly all our docs live on posthog.com/docs. You can find the repo to add and edit docs in the contents/docs directory of posthog.com. It uses file-based routing, so the folder and file structure is the same as the URL path. You can learn more about developing the website here.
Most docs should go somewhere in your product's section. Product docs usually have sections on installation, basic set up, key features, troubleshooting, common questions, and more. Docs for platform features like SDKs, data types, and PostHog AI live in the Platform section.
Don't know where a doc or feature should go? Ask in #team-wizard-and-docs.
What about internal docs?
If you can make something public, you should. Being open source is a core value of PostHog. We try to avoid "internal" docs as much as possible.
If it deals with private information, like security, customer data, or competitor analysis, use one of our internal repos like product-internal.
Code should be self-documenting. If it's complicated to figure out, you probably need to make it simpler. This is especially important for APIs and interfaces that other teams will interact with.
For cases where code isn't self-documenting or easy to understand, include a README.md file in the directory that is closest to the entry point of the code.
This README should:
Describe the general flow of interacting with the functions, but stop where the code starts to become self-documenting.
Be short. If it's long, then your interfaces should be made simpler.
Someone from presents a topic of the day each week in the company all hands - it isn't always the same person. The main objective of this is to repeat and reinforce key messages:
Make sure everyone knows what our mission is, and how their work contributes
Make sure everyone knows what our strategy is, and how their work contributes
This can be company strategy, but also product, GTM, pricing, hiring etc.
Reinforce good cultural behavior/our values
An element of repetition is important because a) we are regularly adding new people to the team, and b) just hearing a message once is not enough for it to stick. 'Repetition' does not mean literally saying the same words over and over again - it's more about finding examples of things people are doing or working on, and showing how those tie back to the bigger picture of what's important at PostHog.
We generally avoid using the topic of the day to announce new things, as these should be done async. Sometimes the topic goes deeper on a recent announcement, e.g. why we cut pricing for X.
The format varies week to week. Sometimes it's a talk, sometimes we invite demos - anyone can be asked or volunteer - and sometimes it's more curated around a particular theme. There is always time for anyone to ask any question.
If you did anything you want to share to everyone, you can volunteer and present it after the topic of the day (unless there is a specific set of demos that day). Demos are not limited to product work, and can be anything you did that's significant for PostHog and worth sharing. A customer story, customer win, changes in how a team works, event, handbook update... Code is not the only thing worth demoing.
If you have a topic or theme you'd like covered, ask in the #team-blitzscale channel in Slack.
Important topics to revisit regularly
PostHog’s mission - to help engineers build better products
How we’re building an enduring company
PostHog’s overall strategy
Every tool you need to evaluate feature success
Get in first
Be the source of truth for customer and product data
This is the schedule for how we run various planning processes at PostHog throughout the year, together with explanations for what each thing is and who takes part. We intentionally keep things as light as possible, but have started introducing some slightly more structured processes around longer lead things like hiring and deciding which products to build.
Besides _very_ high level financial forecasting, we don't plan out any further than 12 months, because things change and we don't want to feel locked into something that doesn't make sense. All 12 month plans are rolling, and we update them every three months at least.
Changes to the plan can happen outside of this schedule - this is a rough guide, not a strict timetable.
| Month | Week 1 | Week 2 | Week 3 | Week 4 | | ------------- | ------------------------ | --------------------- | -------------------- | ----------------------- | | January | Monthly accounts review | 12 month product plan | 12 month hiring plan | Monthly accounts review | | February | Board meeting | | | Monthly accounts review | | March | | Q2 goal setting | | Monthly accounts review | | April | | 12 month product plan | 12 month hiring plan | Monthly accounts review | | May | Board meeting | Whole company offsite | | Monthly accounts review | | June | H2 financial re-forecast | Q3 goal setting | | Monthly accounts review | | July | | 12 month product plan | 12 month hiring plan | Monthly accounts review | | August | Board meeting | | | Monthly accounts review | | September | | Q4 goal setting | | Monthly accounts review | | October | | 12 month product plan | 12 month hiring plan | Monthly accounts review | | November | Board meeting | | | Monthly accounts review | | December | Financial forecast | Q1 goal setting | | Holidays - keep empty |
What each meeting does
12 month product plan
What: We update our rolling 12 month plan, which tells us what products to build next. This then tells us who we need to hire to support the plan. The output of this plan feeds into quarterly goal setting (below).
Who:
12 month hiring plan
What: We update our rolling 12 month hiring plan, which tells us who we need to hire beyond the current quarter. The hiring plan lives in Pry.
Who:
Board meeting
What: Quarterly meeting to update the board on progress and talk through 1-2 strategic topics. Board packs are stored in Google Drive.
Who: , occasional guest presenter
Org tidy up
What: Go through all the small teams, make sure everyone is happy and in the right place, make any changes needed to support new products/general scaling.
Who:
Financial forecast
What: Review the 3 year financial forecast, add another year. Tweak based on past performance, then check it is realistic, and keeps us on track. The forecast lives in Pry.
Who: Fraser,
H2 financial reforecast
What: Midway through the year check that the 3 year forecast makes sense, tweak if necessary
Who: Fraser, Charles
Monthly accounts review
What: Review last month's management accounts against budget. November's accounts review happens in January, due to the holidays in December, as we typically get our monthly accounts around the 21st of the following month.
Who: Fraser, Charles
Pay reviews
What: We run these 3 times a year. Not in the calendar as the times shift year to year and we want flexibility as we grow.
Who:
Quarterly goal setting
What: Blitzscale pre-meeting, then individual teams meet to run their own processes.
This page is for customer success managers, technical account managers (TAM), and anyone sitting on a customer who needs hands-on help setting up PostHog. It covers how to pull in a forward deployed engineer (FDE), and, just as often, how to sort the problem out without us.
Most "we need help setting up PostHog" requests don't actually need an engagement. FDE work is often paid, so solving it yourself saves the customer both time and money.
Before anything else, point the customer at the PostHog wizard audit:
npx @posthog/wizard audit all
It runs the same checks our FDE team would do by hand. It's read-only, takes a few minutes, and produces a report (a markdown file plus a shareable PostHog notebook) that names exactly what's wrong and what to fix first. Plenty of teams find their own engineers can take it from there.
We also have a growing library of PostHog skills you can point an agent at to do a lot of this yourself. They cover far more than audits: migrations, config cleanup, spotting what's misconfigured, and plenty else. Most work directly against a customer's instance through the MCP tools, so you don't always need their codebase to dig in. To run them against the customer's own data, do it on their behalf by impersonating their account.
For the smaller questions that come up along the way, PostHog AI and the PostHog Slack app handle most of them without needing to pull in a person.
If they still need hands-on help
Before you route anything to us, gather the data we need to get started. It saves you a round-trip and saves us the context-switch:
Gather what we need to scope it. Two things make discovery quick: the wizard audit reports, so we start from real evidence instead of a blank page, and a read on what's actually blocking them: engineering bandwidth, trust in the implementation, internal coordination, or "we want someone to do it for us." That's the signal that decides what kind of engagement this becomes. Alongside those, name the customer, the product area, a one-sentence description of the problem, what would exist at the end that future customers could reuse, what codebase or data access is available, and a rough size (a week, a month, longer).
Set rough expectations on price. Use the shape, not an exact number; see what it costs. If the customer wants an exact figure, tell them you'll get a quote within a day and route it through the AE.
With that in hand, you can run intake yourself using the FDE vault skills (intake, scoping, and quoting). Anyone at PostHog can run them, and they'll produce a calibrated scope, an hour estimate, and a proposal without needing an FDE in the loop. See the skills README in the fde-vault repo.
Intake. A colleague or customer raises a need. Capture enough to classify and route it: the customer, the product area, and a one-line ask.
Scope. Classify the engagement type, estimate effort, and quote if the shape calls for it. The output is a short brief the customer can check before we commit. Details below.
Execute. Do the hands-on work: instrumentation, data modeling, migrations, integrations, dashboards, reference implementations. Capture the durable artifacts as you go.
Wrap-up. Confirm the deliverable shipped and was approved, hand the relationship back to sales and CS, and write down anything that came up so it can be preserved for the next customer.
Scoping and engagement types
Before delivery starts, every engagement needs a clear outcome, a rough timeline, and a shared definition of "done." We write this down as a short brief and send it to the customer to check before committing. Scope small: it's cheaper to expand a tight scope than to unwind a loose one.
Always ask yourself while scoping: would this output be useful to a different customer facing a similar problem? If yes, it's compounding FDE work, so make sure the artifact lands somewhere reusable. If no, it's a scoped deliverable or a support answer. Being honest about this keeps the team's capacity pointed at work that compounds.
Principles
These are the defaults we bring to every engagement. Each is a lever on the same goal: customer value that compounds.
Solve the customer's actual problem, not the one that's easiest to ticket. The strongest move is often to correct a customer's mental model rather than build exactly what they asked for. Before digging in, ask what decision actually depends on the answer, and what "good enough" looks like for it.
Start with the MVP. Say what the minimum answer is before you start. A short list today usually beats a long analysis next week. Building more than the question asked for isn't thoroughness, it's waste. Push back on every "should we also...".
Reach for PostHog's own primitives first. Prefer PostHog AI and the platform's built-in capabilities over bespoke engineering. The simplest path the product already supports is usually right, and it's the one the customer can maintain after we leave.
Solve it once. Anything you build for one customer should, where possible, become a reusable example, template, or product improvement.
Lead with substance. In customer communication, lead with what you found and what you'd do, never with the fact that an artifact exists. "The writeup is ready" reads as corporate filler. Say what's in it.
Stay close to product engineering. We're the fastest feedback loop between real customer usage and the roadmap, so use it.
Judgment over output
As AI handles more of the production, an FDE's value is less in how much they can produce and more in the judgment they bring to it. When generation is cheap, the scarce skills are the ones a model can't supply for you:
Prioritizing well. Knowing which of ten reasonable things to do first, and which not to do at all.
Deriving the true problem. Reading ambiguous or over-specified requirements and finding the real question underneath.
Choosing the simplest thing that works. The simple approach where it serves, the robust one only where it prevents real regressions.
Now vs defer vs delegate. Deciding what to fix now, what to consciously defer, and what to hand to the customer's team, the product, or an AI agent.
We hire and grow for this, and we give people room to exercise it rather than a script to follow.
What it costs
Pricing depends on shape, hours, and commercial context, so exact numbers live in the FDE calculator and the commercial reference, not here. The philosophy:
Discovery and scoping before an engagement is free and time-boxed. If a customer wants more before signing, that becomes a paid proof-of-concept.
FDE engagements have a minimum size (roughly a one-week sprint) because anything shorter can't produce something that compounds. A one-day "FDE engagement" is just support with a fancy name, so quote it as support instead.
ProServ is quoted per deliverable, not per hour. A deliverable that doubles in scope is a new quote, not a conversation about generosity.
Never invent an exact number on the spot. If a customer asks, say you'll get them a quote within a day and route it through the account exec.
Improvement loop
Doing the work and improving how we work are the same activity. Every engagement teaches us something: a recurring question, a pattern that held, a place the process drifted. We capture those, gate the ones that hold, and graduate them to the right level of generality: a customer question becomes a topical reference, a cross-customer pattern becomes a lesson or a playbook entry, a hard-won rule becomes a standard.
The result is a team knowledge base that gains weight over time, so the floor is higher on every new engagement.
Sprints
The FDE team works in fortnightly Sprints that run Monday to the Friday of the following week. Stand-ups are on Mondays and Wednesdays at 2.30pm UK / 9.30am ET.
On the closing Friday of a Sprint, a GitHub Action automatically closes the current Sprint's issue and creates a new issue for the next Sprint. FDE team members are expected to populate it before Sprint kick-off, which takes place at the Monday stand-up.
Working as a team
We're still new as a team and figuring out things as we go. To ensure everybody is pulling in the right direction and not duplicating work we:
Make work visible once it may affect the team, customers or shared systems. We follow overall PostHog convention of Pull Requests being preferable to issues and Slack discussions.
Build on existing work. Before starting a new solution, check for relevant work already in progress and either reuse, improve, or explicitly explain why a separate approach is needed.
Use peer feedback to shape the approach. Raise alternatives early so we can consider and agree on the best path forward.
Create maintainable team assets - avoid creating tools or workflows that only one person can operate.
Track customer outcomes, not just work outputs.
In general, at PostHog we bias for sharing imperfect work early, so that peers can help shape the direction of that work, rather than waiting for something to be perfectly ready before making it visible to the team.
Systems and automation
One of the goals for the FDE team is to accelerate and improve our delivery by focusing on building automation, over one-off work. This helps us capture deep customer knowledge and allows for faster iterations. To that end, we have built systems and workflows to help us better achieve that goal.
FDE Vault
The FDE Vault is the operational brain for the FDE team and is where we store internal context about how we work and track specific customer engagements. The goal for the FDE Vault is to compound organizational knowledge over time by encoding our standards, playbooks, pricing, decision history, mistakes, and hard-won patterns in a central repository.
FDE Vault Boy Bot
FDE Vault Boy is a triage bot for the #team-fde Slack channel, built as a Slack workflow. It runs automatically whenever a message containing pre-defined keywords is posted in #team-fde which requires FDE attention. The bot classifies the message to identify what's being asked, then provides a tailored response based on the original ask and its category.
Team Digest
Team Digest is a weekly GitHub Action which runs from the FDE Vault. It posts a Slack message to the #team-fde channel summarizing the past week for the team: Tasks, Meetings, Deliverables, and Pull Requests (opened and merged), with the full digest details stored as a linked GitHub issue.
FDE Signal Router
People love working in Slack, so most of how the team operates lives in threads that scroll off and never compound. The FDE Signal Router is built to catch these valuable conversations.
Reply to any Slack message with the :fde-is-on-da-job: emoji and the context is captured to a Slack canvas in the #team-fde channel, where it is routinely monitored and reviewed by the FDE team.
Use it to flag anything warranting action from the FDE team, whether that means routing it to a more permanent home or raising it for discussion at standup or sprint planning.
Welcome to the PostHog Forward Deployed Engineering team! We only hire about 1 in 400 applicants, so you've done well to make it here!
Onboarding here is mostly self-serve – we won't sit you in a room for training for two weeks, and unlike a lot of companies, we'd prefer you get up and running with quickly. If you're not sure who's supposed to make something below happen, the person responsible is almost certainly you.
Below is a rough plan for your first month – use it as a guide, not a contract. The handbook itself is a work in progress, so you'll find gaps as you ramp up, things you needed to know that weren't written down. That's normal, and when you find a gap your job is to fill it in so the next person has it easier.
Day 1
Meet with Simon who will run through this plan and answer any questions you may have. In addition, come equipped to talk about any nuances around how you prefer to work (e.g. schedules, family time etc.)
If you start on a Monday, join your first FDE standup.
We fill in a GitHub issue every week before this meeting so we are prepared for the discussion topics. Ask one of your fellow FDEs to add your GitHub handle to the automation which creates the sprint issue.
If you start on a Monday, join your first PostHog All Hands (at 4.30pm UK/11.30am ET).
Advice: You should keep a fun fact about yourself in your back pocket and be prepared to have a strong opinion on whether pineapple belongs on pizza.
General onboarding / tool set up
Complete your onboarding tasks in our ops platform to get yourself set up as a PostHog employee. It's okay if you don't manage to get this all completed on Day 1.
Install your favorite LLM of choice.
Set up tools like Zoom, Gong, Granola and Calendly so that you can talk with customers in our standard way. Our Sales and CSM colleagues have a guide on how to set up our canonical call stack. Ask Simon for access to these.
The rest of week 1 is about getting to grips with the PostHog concepts that you'll come across most frequently as an FDE.
Self-guided product learning:
For each of these steps after you are finished record a short video (we use Loom mainly) explaining what you've done and learned and share it into your onboarding channel. We have deliberately left links to the documentation out of this section so that you can learn to navigate our website and docs.
Build a demo app using your favorite JS framework and server-side language (assuming they are in our supported libraries of course).
Set up PostHog in the app. Avoid using the wizard/other helpers as most customers you encounter will have been through a manual integration process.
Set up identity resolution on both the client and server side. Make sure your users are stitched together properly between client and server.
Implement sensible session replay controls.
Implement client-side feature flags and a realistic experiment which uses those flags.
Switch your feature flags to use server-side local evaluation. What are the differences in process? How do we bill for these two approaches?
Integrate error tracking both on client and server.
Add in any other products as you see fit. We have a useful framework which can be used as a guide.
Rerun the integration above with the PostHog Wizard to see how much easier it is, then ask it to audit your app. This is how other teams self-serve discovery before they bring the scope conversation to the FDE team.
At the end of the week share a full retro of what you've done and learned with the team, and also submit a PR to this page to improve it for future new starters.
Week 2 – start working with customers
The FDE Vault is where we share what we're working on. Whenever you pick up a ticket, task, or intake, write it up in the vault using our shared format, so it's easy for the other FDEs to follow along and give feedback. Set it up from the README in the root of the repository, and learn the rest as you record your own work.
This is when you start working with your customers. Ask the vault for the current in-flight engagements we have, and then work with the FDE on that engagement to see which tasks you can pick up. Ask for their review once you're done. When you pick up a task, ask the vault how we solved similar problems for other customers.
Support tickets:
For weeks 2 and 3, also pick up support tickets, usually 1-2 per day, depending on your workload. A ticket is the quickest test of what you learned in week 1: a real customer problem, your answer, and their reply.
Before your first ticket, do the support hero training with a support engineer. It covers where tickets live, how to claim one, and how to reply.
Ask in #team-fde which ticket view to pick from. Choose tickets in the areas customers bring to FDE, like feature flags, migrations, and instrumentation.
Ask another FDE to review your answer before it goes out.
Note each ticket that looked like it needed an FDE engagement instead of an answer, and why. Bring those notes to the team at the end of week 3. They show the line between support and FDE from the support side.
Weeks 3 and 4 – take on more customer work
We will normally do in-person onboarding in week 3 – this will mainly be focused around a review of your first couple of weeks, how the wider GTM organization works as well as in-person work on the below.
Keep working on your engagement tasks, and take on more of the work yourself.
Simultaneously, for any new engagements that crop up after your second week, start to run intake for those engagements (the vault should help you out with what to do here)
What good looks like at the end of week 4
Things are going well if:
You have significantly leveled up your PostHog product knowledge from when you started
Your work is visible and reviewable: it's recorded in the FDE Vault and passes its checks
You've started to work on customer engagements
You've run your first intake
You've answered support tickets and can say which ones needed an FDE engagement
You've improved the way we as a team work
Month 2 and beyond
By the end of month 2:
You'll have completed your first end-to-end customer engagement
You'll have continued to improve the way we work
You'll have contributed something of value back to PostHog (the product)
New hire frequently asked questions
What are some useful Slack channels?
PostHog has a transparent culture when it comes to communication so here are some useful Slack channels. You can invite yourself to these channels without needing to ask for permission:
#team-fde: the Forward Deployed Engineering team. This is where we spend most of our time working with each other.
#group-cs-sales-support: cross-team discussion for everyone who owns customers.
#team-customer-success: the Customer Success team.
#team-product-led-sales: the Product-led sales team.
#team-new-business-sales: the New Business sales team.
#team-onboarding: the Onboarding team.
#team-people-and-ops: for any ops-related topics.
#customer-churn: discussion of potential and actual customer churn.
#changelog: product launches.
#incidents: for notifications of incidents which may impact customers. Make sure you set this to alert you for every message so that you know when something is up.
#ask-max: bot focused on internal processes and questions. This should be your first port of call if you need to self-serve an answer.
#ask-posthog-anything: when you can't self-serve an answer to a question from our handbook, docs, Slack, code repos or #ask-max.
#tell-posthog-anything: For company-wide announcements or notifications about PostHog people, products, policies, projects etc.
#team-fde-tests: Channel used to test out any automation / Slack workflows (without spamming the main #team-fde channel)
We aren't all about work 24/7 here at PostHog so here are some more fun channels:
#random: For non-PostHog stuff.
#whereintheworld: Posting cool things from around the world
#merch: Anything merch-related (because we love merch)
#no-context-posthog: If we told you what this is for, that would be providing context.
Here are also tips for Slack:
Ask one of your fellow to add you to the Team FDE Slack User Group. This will notify you anytime someone mentions @fde in any chat.
Set up "Channel keywords" so you can notified about topics you care about. We recommend starting with "fde" as the first keyword but feel free to add your own.
To help you focus on your most important notifications, you can set specific people as VIPs to make their messages stand out. Maybe your fellow FDEs can be VIPs?
Forward deployed engineering (FDE) is PostHog's team of engineers embedded with customers to get their implementation right. Depending on the engagement, that might mean hands-on work in their codebase (migration, instrumentation, dashboards, experiments) or it might mean getting their foundations right and enabling their team without ever touching code.
What makes this different from professional services is that every engagement compounds. The patterns we see across customers become reusable artifacts, skills, and product improvements that benefit the next customer and the broader PostHog user base.
FDE isn't just technical execution. AI made generating code easy, so the value we add is judgement: prioritizing for our team and the customer, helping them find the root of their problem, then planning and executing the best solution that fits their culture.
We don't maintain a fixed list of services. If solving a customer's problem produces something reusable, we're interested in seeing if we can help. In practice, that often looks like:
Help customers design and implement PostHog for their specific stack, scale, and use cases
Unblock technical adoption: instrumentation, data modeling, migrations, and integrations
Build reference implementations, examples, and internal tooling that make future engagements faster
Support. We have an amazing Support team who provide deep technical insight and fixes issues day-to-day, but they have to move fast from customer to customer. FDE work is higher-touch, tied to a specific customer outcome, and designed to leave something reusable behind.
Sales, success, or account management. Your TAM or CSM owns the commercial relationship, we're embedded on the technical side for scoped engagements.
Product engineering. Our focus is work that compounds across customers and engagements, not owning product direction, though the insights we surface help our team prioritize.
When FDE gets involved
The FDE team is small, so we're deliberate about where we spend time. Typical triggers:
A high-value prospect or customer has a technical blocker to adoption or expansion
A complex implementation, migration, or integration that benefits from hands-on engineering
A repeatable technical problem worth solving once and templating for everyone
Who to talk to
If you have a customer who might need FDE help, or you're trying to figure out whether something fits, the fastest path is to talk to the team directly. Bring the customer, the product area, and a one-line description of what they're trying to do. That's enough for us to tell you whether it's FDE-shaped and what happens next. If you're routing something formally from sales, CS, or engineering, the full intake path is in how to get an FDE involved.
We work with teams that have a PostHog problem other customers have too.
We want to fix a bad implementation before the customer stops trusting their own data.
| | Teams that have a PostHog problem other customers have too | | --- | --- | | Description | Accounts where something in the implementation holds the team back, self-serving hasn't fixed it, and the fix would help other customers too. That covers:<br />• A customer at churn risk from an implementation they no longer trust<br />• A team scaling into a product area where no best practice exists yet<br />• A new customer whose first implementation decides whether the account ever works | | Criteria | Ideally all of them. We take work outside the ICP on purpose, so not every one has to be met.<br />• The work compounds across customers, so what we leave behind transfers to the next one<br />• It serves revenue retention or growth<br />• $50k ARR or above. For a new customer we count predicted ARR. Smaller accounts qualify as a group when one piece of work serves all of them and their combined ARR clears the bar<br />• Any industry, any region<br />• At Proving or later in the customer journey. The coverage map leaves us blank at Exploring, Evaluating, and Buying<br />• The wizard audit and the PostHog skills haven't already closed the gap | | Why they matter? | • Retention and expansion both run through the implementation. An account that can't trust its own data doesn't renew, and doesn't expand<br />• Every engagement produces something reusable, so the next customer with the same problem costs us far less than the first<br />• We see the messy problems before anyone else, which tells us what the product should build next | | Examples | • A team whose three SDKs evaluated the same flags with no shared identity state<br />• A technically strong product team with no bandwidth to work on PostHog<br />• An account where one person held the whole data pipeline<br />• A net-new implementation that set the foundation for everything built after it |
Where we show up in the customer journey
The coverage map marks us conditional at every phase we appear in, and blank at Exploring, Evaluating, and Buying. Conditional means someone has to bring us in, nearly always a TAM, CSM, or TAE selling an engagement. There's always a CSM or TAM on the account before us.
| Phase | What brings us in | | --- | --- | | Proving | We help prove technical fit during a POC with a top prospect. | | Implementing | The implementation need is more than a TAM or CSM can deliver. | | Ramping | Friction in an implementation that's already live. This is where most of our engagements currently land. | | Expanding | A mature account moving into a product area with no playbook yet. | | Steady state | A churn prevention play, fixing an implementation the customer no longer trusts. |
An account can be at risk in any of these phases.
How we use this
The ICP decides who we approach, not whether we say yes when a customer or someone in sales comes to us. That account has already found us, so what's left is capacity and scoping.
Any PostHog customer is technically interesting, so without a shared definition every account looks like a candidate and we spread thin.
Going outside the ICP on purpose is how we find out it has gone stale. How we split FDE from professional services is our current reading, and it will move as we learn.
Capacity is a separate question. The ICP says which accounts qualify; how many we hold at once comes down to what the team can carry. Currently, one embedded engagement is roughly one engineer.
What this rules out
Accounts below the ARR bar, unless one piece of work serves a group of them. We serve those through the product, the PostHog skills, and the wizard audit.
Single-customer delivery. We still do it, as professional services. It comes to us through sales or bundled into an engagement we're already running, and we don't go out looking for it.
Exploring, Evaluating, and Buying. Sales owns those phases.
Two things we deliberately don't screen on:
Geography and time zone. They make no difference to us.
Whether the customer has engineering capacity. Every engagement we've converted so far involved a team without it, but that predicts a customer saying yes and says nothing about whether the work compounds.
Our current persona
Persona is the role of the person we work alongside in the account. Whoever asks for us is usually not that person.
Who asks for us. Someone accountable for what the data says, and unable to fix it themselves. Often a founder, a product lead, or a TAM carrying the account. They can be deeply technical and still have no PostHog depth, which is the common case and the one to plan for.
Who we work alongside. An engineer, or the one person who owns the data pipeline. They know the codebase, they don't know PostHog's failure modes, and they have other work. Our job is to leave them able to maintain it themselves.
The anti persona. A team that wants a pair of hands for a few weeks. That work still happens, and sales scopes and bills it as professional services. We look for what compounds inside it anyway, because that's the habit we bring to every engagement, but we don't proactively look for this type of work.
We'd be at a disadvantage if we didn't use AI, but using it badly could put us at even more of a disadvantage. LLMs are great for exploration, batch processing, transformation, search, and anywhere a fuzzy answer is useful. We use them to speed up better solutions, not to solve the same problem again from scratch.
You're responsible for what you ship, whether AI generated all, most, or none of it, no exceptions.
Customers place their trust in us when they delegate their work to us. So we should only delegate that work to systems that deserve our customers' trust. Using AI well means treating delegation itself as an engineering discipline.
Principles for working with AI
We wrote these principles from actually doing the work – if doing the work teaches you something better, go with that.
You're still the driver: Would I be happy to put my name on this if the customer read it today?
Would I be happy to put my name on this if the customer read it today?
If we can follow a standard exactly as written, we should automate it. You're here to evolve our standards. When real work exposes a gap, use your judgment and improve the system.
Understand before you delegate
Could I solve this myself, or at least tell when the answer is wrong?
Delegate only problems you understand to systems you trust. For PostHog products, we should be able to solve the problem ourselves before using AI.
You don't need to know every implementation detail. You do need to know what cannot break, how the system can fail, and whether you're okay with those failures.
Use the right tool for the job
Am I using AI because it's better here, or because it's available?
Using your judgment also means choosing the right tool, and knowing when work stays human: when the answer is ambiguous, consequential, or depends on taste and direction.
If we keep solving the same problem, we should stop relying on a model to figure it out from scratch. Some questions should become hardcoded checks like queries or scripts.
Use skills for R&D
Do other FDEs face this problem, and what is the skill teaching us about the solution?
Skills allow us to combine and share our best experiences. Sometimes the skill becomes the solution, but often it uncovers what we should build.
If no one is using a skill, that's a signal. Maybe it isn't good, the problem isn't important enough, it creates more friction than it removes, or a skill simply isn't the right tool.
Automate repetitive work
What do we lose when this doesn't get done?
If something depends on memory, someone will forget. Logging tasks takes seconds, but skip it and the team loses visibility.
AI helps us automate work we always assumed had to be manual. You can use agents to infer tasks from your work, so that overhead disappears entirely. Automate work when the cost of skipping it is higher than the cost to maintain the automation.
Trust is the measure
Can someone check this claim quickly without redoing my work?
At FDE, our work compounds. That only works if we can trust past contributions, so we treat trust as a quality signal and measure it against our contracts.
Trusted records unlock new work. In a recent experiment, we used validated schemas and tagged blocks in our records to generate deterministic reports for stakeholders: no tokens, no hallucinations.
So make your work visible and cheap to check. Someone should be able to use, review, or challenge it without retracing your investigation. When you make a claim, link data to queries, code to exact lines, and behavior to tests. That's how AI-generated output becomes something we can trust and learn from.
Know your audience
What does this reader need from me, and is writing the right format for it?
Get to the point. Give people what they need first. Adapt to how they prefer to communicate and work. When people are already overloaded, less is more.
Agents need a different kind of writing: provenance, evals, invariants, structured context, and enough detail to keep working when requirements change and nobody is around to decide.
The work moves
AI makes execution easier, but our work isn't done. The puzzle pieces have moved. Creating new paradigms, new infrastructure, and things that don't have a name yet is still the spark humans bring.
Forward deployed engineers (FDEs) own the technical outcome of an engagement; the commercial relationship stays with sales and CS. Once the work is scoped, delivering it well comes down to a handful of habits: a steady cadence, clear deliverables, and a clean handover. For the process behind an engagement (the lifecycle, scoping, engagement types, and pricing), see how we work.
Delivery
Hands-on implementation work: instrumentation, data modeling, migrations, integrations, and reference implementations.
A deliverable is finished when a stranger on the customer's team could pick it up cold, understand the scope, follow the recommendation, and not need to ping us. Every deliverable answers four questions, in order:
What is this? One paragraph, no jargon.
What did we find or build? The substance: lead with the conclusion, then the supporting analysis.
What does the customer do next? Specific, ordered, and assigned to named people.
What did we assume, and what's out of scope? Calibrates expectations and protects against scope creep on the next iteration.
Write in the customer's vocabulary, not ours; their team has to live with the deliverable. Be direct: "use X" beats "you may want to consider X."
Foundations before dashboards
Most analytics engagements have a hidden trap: dashboards are the visible deliverable, so there's pressure to build them first, but they're only as trustworthy as the data layer underneath. Built on a half-joined identity layer or a partially instrumented event stream, a dashboard won't throw an error. It'll show a number that looks right and isn't, which is worse than no dashboard at all, because the customer will make real decisions on it.
So we work in order:
Data layer. Get the product, billing, and CRM sources cleanly joinable, taxonomy clean, and identify/group calls firing on time.
Dashboards and automations. The stuff the customer opens every day: churn triage, renewals, product health, alerts.
Documentation and training. Hand off to the customer's team so they own it after we leave.
Rhythms
Reply within a business day to any direct customer mention or DM. If you can't answer in a day, acknowledge in a day and give a real ETA.
Weekly sync. 30 minutes at the same time each week for in-flight engagements. If there's nothing to talk about, cancel; don't pad.
Weekly async update. A one-paragraph status note in the customer channel that frames the next week, so nobody's surprised on Monday.
<!-- TODO: ONSITES document how FDEs run customer on-sites: when one is worth it, how to prepare, and what good looks like. Reference the sales team's customer on-sites guide (/handbook/growth/sales/customer-onsites) and engineering's visiting customers guide (/handbook/engineering/visiting-customers). -->
Handover
When the technical work is done, hand the relationship back to the account owner and write down what was built and why. A clean handover means:
The deliverable is shipped and approved by a named person on the customer side.
Any follow-on work is captured as explicit tasks, not left implicit in the prose.
Questions that came up during the engagement are answered in writing, so the next customer, or the CS owner, hits an answer instead of re-deriving it.
Anything that generalized has been graduated into shared fde-vault.
Boundaries with support
FDE engagements are scoped and higher-touch, and they leave a durable artifact. Ongoing, ticket-shaped issues belong with support. If a customer's questions are recurring and reactive rather than pointed at a specific outcome, that's a signal it's support (or a support retainer), not an FDE engagement, so reframe it rather than absorbing it silently.
Forward deployed engineers (FDEs) are one of the fastest feedback loops between real customer usage and the product roadmap.
Feeding customer problems back
FDEs hit PostHog's rough edges under real customer workloads before anyone else does. When you find a bug or a product gap, tell the owning small team and file an issue: what broke, who hit it, what it blocked, and how to reproduce it. Good context gets it fixed faster, so the next customer never hits it.
Escalations
When a customer engagement is blocked by something only a product team can fix, we hand off to the owning team. How that handoff works varies: some teams prefer async write-ups, others prefer you join their standup. Finding the best channel for each team is part of the job, the same way it is with customers. When something works well, share it with the team so others can use it.
Contributing changes
FDEs can often fix or extend things directly rather than waiting on a team. When we do, we follow the same development process and review standards as everyone else, and we work with the owning team rather than around them.
Respecting team ownership
Product teams own their areas, full stop. We find the owning small team, loop them in early, and respect their call on their surface. The whole point of feeding customer problems back is to make the roadmap better, and routing around the team that owns it defeats that.
Forward deployed engineering (FDE) works alongside the sales, customer success (CS), and onboarding teams. They own the commercial relationship and bring us in when they need scoped delivery of technical outcomes.
Who owns what
Sales owns the deal and the commercial relationship; see new business.
CS / TAMs own the ongoing customer relationship and health; see customer success.
FDE owns scoped technical engagements that unblock adoption or expansion.
We collaborate with these teams to provide focused, embedded technical work. The commercial relationship stays with the account owner throughout.
How FDE gets pulled in
Sales or CS flag a technical blocker or opportunity, and we scope it. Before you route something to us, run the quick self-check in how to get an FDE involved. That page also covers the cases where a customer can self-serve without an engagement at all, which is often.
One thing worth naming from the sales and CS side: an FDE ask usually surfaces mid-deal or mid-relationship, so the person routing it already holds the commercial context we don't. Bring that with you: where the account is in its lifecycle, what's actually at stake commercially, and how time-sensitive it is, so we scope against the real constraint rather than the technical problem in isolation. Then bring it to the team.
Pre-sale vs post-sale
FDE engagements begin where pre-sales ends. If a prospect needs deep, ongoing technical work to be convinced, that's a signal the engagement should be scoped.
Pre-sale: helping a prospect prove PostHog will work for them through advisory reviews, proofs-of-concept, and architecture assessments, often alongside trials. Currently FDEs don't do pre-sales work.
Post-sale: implementation, migration, and expansion work for existing customers. This is where the FDE engagements live, and where the work is most likely to compound.
Handoffs
Clean handoffs in both directions:
Into FDE: CS or sales gives us the customer context and the technical ask, and we scope it before committing.
Out of FDE: when the technical work is done, we hand the relationship back with a record of what was built, what the customer should do next, and any follow-on work captured explicitly. See handover for the checklist, and the sales team's sales handover for the adjacent process.
One rule of thumb: if the customer's team needs to act on something without us in the room, it belongs in a durable deliverable, not a Slack DM or a thread they'll never manage to find again.
However, while we default to written and asynchronous communication, we find that having a few regular touch points for the whole team to come together on a call useful for sharing certain types of information, strengthening our culture and discussing more dynamic issues in real time.
We keep these minimal in terms of time expectation - no more than 2hrs total per week. They are usually scheduled around 8.30am PDT/4.30pm GMT to allow people across multiple timezones to attend more easily. We default to cameras on, it’s nice to see real faces since we don’t get many in-person moments. If you need yours off, just give the team a quick heads-up why.
You should have been invited to any relevant meetings as part of your onboarding.
Weekly schedule
Monday - PostHog all-hands meeting. Members of the team share company-wide updates about things like recruitment, product metrics and commercial performance - the notes and recording are shared weekly in the #general Slack channel. We protect time for Q&As and demos at the end. _The content of these meetings is always confidential._
Tuesday - Meeting-free - no planned internal meetings allowed. Learn more.
There's a reserved slot for cross-team meetings every other week - avoid scheduling recurring meetings (standups, 1:1s, sprint planning) so you can use the slot when necessary
Thursday - Meeting-free - no planned internal meetings allowed. Learn more.
Friday - extracurricular type meetings like BookHog often end up here!
The all-hands
The Monday all-hands features a few regular sections and is recorded in this document.
Announcements: Revenue and churn updates, plus other major news
Hiring & anniversaries: Updates about headcount, who is starting soon, new hiring roles, and who is celebrating a PostHog anniversary
Acknowledgements: Opportunity to give kudos to your colleagues
Demos: Show us what you've worked on last week - anyone can demo, though we sometimes ask for a particular theme to tie in with the topic of the day
When public holidays overlap around the world and a lot of people are out, we'll move the all-hands to another day that week. Our rule of thumb is to reschedule when 35% or more of the team is away.
How to give a good demo
Demos are a great way to share what you've been working on and keep everyone in the loop. A little prep goes a long way toward making them useful and respectful of everyone's time. It also stops the meeting length getting out of hand!
Test your setup before you start. Make sure screen sharing and your microphone work so you can dive straight in. A quick check a few minutes before the meeting avoids awkward fumbling and keeps the energy up.
Keep it short and purposeful. Aim for quick, concise demos. It can help to write down some bullets to structure your demo ahead of time. Lead with why what you built is useful or interesting — that context helps people stay engaged and can be especially useful for less technical teams.
Don't rely on real-time. If your demo involves triggering other services (e.g. sending emails or calling APIs), cue them up in advance or use mocks. Live demos are fun when they work but can eat into everyone's time when we're waiting for something to load.
Arrive with energy. We don't expect polished sales pitches, but it's always more engaging to listen to someone who is excited to show what they've made.
It's okay to skip or shorten. If something isn't working or you run out of time, feel free to skip it and move on. You can always share a Loom in #tell-posthog-anything so people can watch when it suits them.
Be ready when it's your turn. Pay attention to the order of raised hands and be prepared to speak when you're up. It keeps the flow smooth and shows you're tuned in to the group.
When in doubt: a short, clear demo that explains the "so what?" beats a long one that leaves people wondering why it matters.
No meeting days (Tuesdays & Thursdays)
We try to keep these days focused on deep work. Therefore, we run no planned meetings on these days.
However, speaking ad-hoc to your teammates on this day is fine - especially:
new people shouldn't worry about following this rule for the first couple of weeks - it's more important you get up-to-speed quickly
if it's obvious you need a meeting
If ad-hoc meetings are regularly happening, consider improving the agenda of another regular meeting so there isn't as much context switching in people's days.
People in customer-facing roles where being on calls is a bigger part of your job don't need to stick to this as much, but please don't loop in engineers to customer calls on these days if you do by default.
Sprint planning
Each small team runs its own sprint planning meetings on whatever schedule you feel is most useful. Some teams do this on a Monday, others on a Wednesday, and sprints are usually 1-2 weeks long. We split into Small Teams for these. If a product team, your team's exec will also attend.
All sprint planning meetings are open to anyone to attend - if you are not a member of that small team, then we ask that you sit in as a non-speaking observer only.
This document outlines all possible billing configurations for customers at PostHog. The goal is to ensure the team is on the same page with the different configurations we support to ensure things move smoothly as we scale. We want to ensure they support the billing repo, dashboard, usage reports, revenue reporting, etc.
Below are the main configurations. Each one outlines how the Stripe customers are set up and billed, and how we account for revenue on them.
Free plan customers
We don't need to worry about these users because they aren't paying anything, even if they have a Stripe customer.
Paid plan customers
Regular user on a paid plan with no credits.
Pay the invoice directly with no funny business
Can be with or without tax.
Every line item on the invoice is a product with a product key
Should be using default products/prices
Should only have 1 Stripe customer and 1 subscription. Configuration 5 below is the exception.
Details
mrr = sum(mrr products) + tax
Start-up plan customers
Startup plan where users receive credits (e.g., $50,000).
Credits apply to all charges until the credits run out.
Credit usage needs to be tracked.
Metadata added to the Stripe customer (is_startup_plan_customer, credit_expires_at, etc.), as agreed in this RFC. The Vitally and Zapier automations read the same metadata.
Revenue is not earned until credits are depleted or expired.
Can be with or without tax.
Should be using default products/prices.
Should only have 1 Stripe customer and 1 subscription. Configuration 5 below is the exception.
Details
mrr = 0 while on credits
mrr per product = 0 while on credits
Annual plan customers (prepaid credits)
The customer pays an invoice for credits before the subscription is created.
Once the invoice is paid, the subscription is created by revops.
Metadata added to the Stripe customer (annual_plan_starts_at, annual_plan_ends_at) sets the contract term. The billing service reads these dates to decide if the customer is on an annual plan today.
Much of this is done via Zapier. See the billing docs for more info.
Credits apply to their usage.
Credits reduce product charges on invoices.
Should be using default products/prices.
The Enterprise platform and support package is not related to this configuration. It is an add-on that a customer can buy on any configuration. See contract rules.
Details:
mrr comes from the actual usage in that month (minus the credit-discount-percent on the customer)
Customers with organizations in more than one region
A customer can have one organization in the US cloud and one in the EU cloud, usually because their own customers need EU data residency. Data does not move between the regions, and the customer cannot query across them.
Before you choose a configuration, confirm three things with the customer: why they need the second region, the usage split they expect, and if their finance team needs the spend for each organization. Some customers ask for a second region and then use only one organization.
Get the organization ID for each region before contract setup. It is much easier to set the configuration up at the start than to change it later.
There are two configurations. Agree on one with the customer before the order form goes out.
Option A: one Stripe customer for each organization
Each organization gets its own Stripe customer, subscription, invoices, and credit pool.
Write the credit split for each organization on the order form.
Each organization operates as usual: separate spend visibility, MRR, forecasts, and billing limits.
The customer pays for each add-on one time for each organization. We can comp the add-ons on the second organization, so the customer pays one time.
Credits are not shared. If the split is incorrect, revops must move credits between the organizations manually.
Use this option when the customer knows the split, or when their finance team needs the spend for each organization.
Option B: one Stripe customer for all the organizations
The organizations share one Stripe customer, one subscription, one invoice, and one credit pool.
Usage from all the organizations is added together and reported against the shared subscription.
The customer pays for each add-on one time. No override is necessary.
The customer cannot see a spend breakdown for each organization.
All the organizations show the same combined usage and forecast numbers in the billing UI.
Billing limits for each organization are not reliable. A limit applies to the combined pool, and the organization that reported last wins.
Internally, MRR and invoices attach to the canonical organization, which is the organization with the lowest customer ID. The other organizations show no MRR in our own tools, which include flags, campaigns, and Vitally.
Use this option when the customer does not know the split, and their finance team does not need the spend for each organization.
Legacy configuration
Note: this above list is focused about the creation of new customers going forward – there are many existing configurations not covered directly in this document.
We haven't had a specific playbook/motion/plan on how to do cross sell, until now!
CS & TAM managed accounts historically have only been slightly better than average when it comes to product adoption. We can change this. We have the technology. We have the power.
Described here are some of the current goals and tactics to improve effective cross-selling measures when working with customers accompanied with specific how-to guidance.
Goals
The main objective is to get existing PostHog customers to adopt more of the platform. We firmly believe that adopting more products leads to a better experience and higher satisfaction with PostHog.
For a TAM today, a quantitative goal is to move from an average 4.8 products adopted currently to 6 products adopted for AM managed accounts over the next two quarters. Accounts may be promoted to CSM coverage and continue with the adoption plan.
AEs and CSMs goals might be polar opposites. Where AEs may want wide exposure, it's also important to establish the right time for product adoption, rather than overselling something that may not apply to the initial implementation.
CSMs are not here to push new products and features; CSMs are here to ensure customers successfully use PostHog and get the most value for their business. Remember, we want to help our champions look like heroes at their companies!
Results
Cross-selling has clear expected outcomes:
Increase Revenue / product usage
Increase stickiness
Offer real value of the "platform" to users
Measuring success
Successful expansion strengthens customer relationships and increases account stickiness. Each additional product that delivers value makes PostHog more integral to the customer's operations. There are a number of things we can look at that deliver these results.
Number of business value conversations
These could be QBRs or other one off calls. We want to increase the number of calls that are primarily discussing business value
Number of product trials started and completed and the time it takes to adopt
Number of in-person visits
Product adoption quarter over quarter
Churn rate by total number of products
Churn rate by specific products i.e. are there products that once adopted lead to a noticeably lower (or higher) churn rate.
Customer feedback on expanded products
Percentage of revenue from a customer spread across products
Is all the revenue for a customer coming from person profiles or is spread between recordings, events, feature flags, and exceptions
Since we have different folks at different stages of ramp and onboarding, instead of making these metrics flat or percentage based, we are looking for an increase quarter over quarter.
Accounts that are a good fit
As a part of this process you are determining whether they are a good opportunity for cross-sell motions and if they are representative of an ideal candidate for growth. Here are some key qualities we've found to date:
Smaller / startup size accounts that don't have existing tooling and can grow with PostHog - it is much easier to grow into using multiple products than it is to try to supplant an existing product.
Engineer heavy - direct technical contacts that have influence in adoption
Product engineers
Technically minded leadership like CTO
Technically adept product manager
Pushing the limits of PostHog - support engagement isn't "how do I do this simple thing" but "how do I tackle this complex concept"
When customers mention relevant challenges organically
Following positive business announcements (follow your accounts company pages on Linkedin, set Google alerts, etc)
Times to avoid or pause cross-selling:
During active support issues or incident
When current implementation needs attention
Within first 30 days (unless customer-initiated)
Following budget constraints announcements
Complaining about price, actively seeking reduction
Usage declining for 4+ weeks
Key champion leaves company
Data Engineer takes over ownership of PostHog
Hypothetical approach
One way of approaching this that we have seen work is a research -> QBR -> recommended cross-sell
Account research and understanding the business
Some sort of engagement (QBRs?) to understand business priorities and tie them to PostHog
Make specific recommendations around what to adopt and how it will help with business priorities
For example, customer B2C SaaS has a business model selling subscription plans. Digging in to understand the differentiators of the plans and reviewing their custom events to ensure they are collecting the appropriate data. Come to the QBR ready to discuss the particulars of their situation. You may or may not have the info you need to make a recommendation on the call, but at the very least, you should have a direction to suggest. You could recommend customer analytics, experiments for plan adoption, and surveys for user feedback given what you know about their business model.
This doesn't always need to be a formal QBR process. Some form of research -> discovery/interaction/recommendation is the basic flow here.
The why evolve framework for cross-selling
Document Results
Start every cross-sell conversation by quantifying their wins with current PostHog products
Example: "Your team has tracked 50M events, identified 3 major UX issues that were costing 12% conversion"
Highlight Evolving Pressures
Frame new needs as natural progression, not disruption
"As your user base grows internationally, you're facing new questions about region-specific behavior patterns"
Share Hard Truths
Be transparent about gaps without undermining current success
"Your analytics show what's happening, but your team still spends hours in user interviews trying to understand why"
Emphasize Risk of No Change
Show what they miss without additional products
"Without session replay, you're making UX decisions based on incomplete data"
Describe Upside Opportunity
Paint vision of complete analytics stack
"You'll move from guessing why users drop off to seeing exactly what frustrated them"
The new cross-sell motions playbook
You've been here awhile and just want the script. Wet get it. The following sections describe the actual approaches that fit well within PostHog for a cross-sell motion, and can be pitched in grouping by feature or by user needs.
Remember that where possible, we're providing solutions and outcomes rather than features. Today we have clear examples with the Error tracking product where customers have found success, with more direct playbooks in the works.
Common cross-sell and expansion paths: Adoption paths are good to frame products as point in time or natural progression to their implementation. For example:
Product analytics → Session replay: When customers struggle to understand user behavior from metrics alone
"You mentioned spending hours debugging that checkout issue last week. Session replay would show you exactly what users experienced."
Customer facing teams → Session Replay: When organizations need better user troubleshooting and support, not just user research into behavior.
Any product → Feature flags: When teams need safer deployment strategies
"That rollback you had to do last month affected all users. Feature flags would have limited the impact to just 5% of traffic."
Feature flags → Experiments: When customers want to test and evaluate results from feature flags; a very natural synergy here, of course
Experiments → surveys: run A/B/n tests and offer surveys to back up / validate insights
B2B companies → Group analytics: When tracking company-level metrics becomes critical
"You're currently exporting data to spreadsheets to analyze customer behavior. Group analytics provides those insights natively."
High event volume → Identified events: When anonymous events limit user journey analysis
Growing teams → Boost or Scale package: When organizations need advanced permissions and SSO
Here are some other known examples that aren't necessarily 0 to 1 linear adoption, or working backwards from what a customer is using outside of PostHog:
Data warehouse has continued to receive special attention since the launch of PostHog's related products.
AI Observability + data warehouse - enrich AI Observability with data from other sources like Stripe or Supabase
Customer analytics + data warehouse - natural fit between connecting up stripe and enriching data further
Feature flag + mobile replay - use for sampling/roll out that is not natively supported by mobile replay
Experiments / feature flags + error tracking - insight into errors for new/beta features, and seeing the impact of those errors on conversion rates is valuable
Feature flags + AI Observability - ability to granularly segment features based on cost/engagement of users. i.e. you can release higher cost models to users who have already shown a willingness to spend
Bundle "Features"
Bundling is another good way to position products by customer type and stage. The following product stacks match certain types of user needs with value.
The "early stage growth" stack
Products: Analytics + Session Replay + Surveys Value story: "You know what users do, see how they struggle, and can ask them why" Ideal for: B2C companies with conversion optimization focus
The "ship fast without breaking" stack
Products: Feature Flags + Error Tracking + Experiments Value story: "Roll out safely, catch issues instantly, measure impact scientifically" Ideal for: High-velocity teams with continuous deployment
The "vibey AI startup" stack
Products: Analytics + Flags + AI Observability + Error tracking Value story: "Tie user behavior to run cost, launching features that are both user requested and revenue generating" Ideal for: AI-focused startups optimizing for cost efficiency and user engagement
What to look for when cross selling
We've already seen general indicators that are worth paying attention to when it comes to success cross-selling and here is an expanded list with what to do next.
New PostHog product launch - did we launch a product that is a good fit for their use case? Did we add a new data pipeline source or destination?
Reach with details on the new product
Offer to credit them back their first month of usage so they can try it out risk free
Raising funding - did the customer just raise money?
Congratulate the founder on the raise
Lead with product that can capitalize on their opportunity to bring in more revenue / usage
i.e. if they are B2C, pitching experiments to maximize conversion
PostHog price change - did we change pricing to make adoption more palatable?
Let your main point of contact know how much they will save with the new pricing if they currently use the product
If they don't suggest adoption based on the new rate and offer credits to offset learning curve
Revenue increase - is the customer seeing an increase in revenue?
Depending on how you know about it, either congratulate them (or don't)
Recommend a product that would capitalize on that revenue
Error tracking to clean up issues
Feature flags to launch new user features
New customer product launch - is the customer launching a new product that could benefit from additional PostHog goodness?
Check out the product yourself (if applicable)
Congratulate them on the new launch
Suggest products that would help with the success of the new launch
i.e. surveys for feedback, feature flags for new features
Competitor drops (or lacks) SDK support - does a competitor lack critical support or have they dropped support?
Reach out proactively to main technical contact if there is overlap
Mention our support (and lack of competitor support)
Send any pertinent docs
Follow up regularly with status updates and additional resources
Eng/marketing hiring - is the customer hiring more technical roles? Could we do this through LinkedIn?
Prep PostHog onboarding for new user
Offer call / support for getting them up to speed
Suggest products that make that new hire's life easier
i.e. error tracking to figure out where the gremlins are
New users from other business units - are we aware of / seeing people from other parts of the business asking about (or even using) PostHog?
Make note of who the new users / units are
Ask for a warm intro from current main point of contact
Reach out 1:1 to new users to get feedback / offer help
Customer expanding into new geography / territory - is the customer moving into a market they weren't previously in?
Ensure they are capturing the correct custom events / properties
Pitch products that help with differentiating location experience
i.e. feature flags for unique features based on GeoIP
When an owner leaves PostHog or a new owner is added - is the new owner open to other products that can help solve the problems they care about?
Reach out to new owner to understand their priorities
Hit any products that were previously suggested to the other owner
Offer credits for adoption of the new product
Shift in customer business model - is the customer introducing a new type of subscription, going from on-prem to cloud, changing their fundamental offering?
Dig in to understand the changes
Suggest flags / experiments as a good way to get feedback / modify the experience for the new model
Alerts
What alerts would be helpful to have that would indicate good cross sell opportunities. Continue to question what would be useful to follow in order to positively influence timing.
Could we use our PostHog to flag when an account's revenue is increasing on their end? (not spend with PostHog, but their actual revenue)
Could we use signals in Vitally / PostHog to notify about new power users?
Could we get an alert when an account tries a new product for the first time?
Discovery through conversation
Effective discovery focuses on understanding customer challenges rather than pushing products.
Example questions to ask
The questions below are designed to spark thoughtful conversations with customers. They help uncover how teams are currently solving problems and whether there might be simpler or more effective ways to do so using PostHog.
Use these questions in preparing for calls and use them as examples for developing your own questions. Each includes the question, the pain revealed, and the PostHog advantage.
High-value discovery questions for upsell/cross-sell:
"How does your team decide what to build next?"
"What's your process for investigating customer-reported issues?"
"How do you measure feature adoption across different customer segments?"
"What does your deployment process look like for major changes?"
"How do you validate that new features impact key metrics?"
“Are there other team members on different teams you could introduce me to or that you recommend I reach out to?” (Always, always, always be asking for “referrals” in this way!)
These questions will naturally surface use cases for session replay, feature flags, experiments, and other products. We should also identify opportunities programmatically through the other data sources we have to supplement the conversation approach. It's not a recommendation to ask each and every one of these questions on a call. These are simply a guide and an example of the types of questions that will help surface opportunities.
Error tracking
| Question | Pain Revealed | PostHog Advantage | | --- | --- | --- | | When an error occurs, how easy is it for you to see exactly which user actions led up to it and how it affected the experience? | Debugging relies often relies on reproducing error | Error Tracking tied directly to replays makes root cause and impact obvious. | | If you’ve built your own error tracking, how much effort goes into maintaining and correlating it with analytics? | Time wasted maintaining infra, blind spots in analysis. | Lightweight SDK that's tightly integrated with other products. | | How do you decide which errors to fix first? | Prioritizing by gut feeling or frequency, not business impact. | Error Tracking + Product Analytics can show which errors have the greatest impact. |
| Question | Pain Revealed | PostHog Advantage | | --- | --- | --- | | When debugging, how often do you rely on logs or secondhand reports to reconstruct what happened? | Time lost piecing together events. | Session Replay shows exact user journey, reducing guesswork. | | How do you confirm if a bug is isolated or widespread across users? | Hard to prioritize fixes without scope clarity. | Replays + analytics show impact | | How do you identify user friction today? | Lacks visibility into real interactions without PM background. | Session Replay gives direct user perspective for product calls. |
Feature flags
| Question | Pain Revealed | PostHog Advantage | | --- | --- | --- | | When launching a new feature, how do you manage risk of rollouts failing? | “Big bang” releases increase risk + stress. | Feature Flags enable safe, gradual rollouts & rollbacks. | | How do you measure whether users actually engage with a feature once it’s enabled? | No feedback loop between rollout and usage metrics. | PostHog connects flags directly to analytics & experiments. | | What’s your process for debugging an experiment if users drop off unexpectedly? | Experiments may fail without clarity on root cause. | Session Replay + Error Tracking pinpoint where the experience broke down. | | How do you currently measure the business impact (e.g., retention, conversion) of an experiment? | Results limited to engagement metrics, missing real business outcomes. | Product Analytics + Data Warehouse show both engagement and business impact. |
AI Observability
| Question | Pain Revealed | PostHog Advantage | | --- | --- | --- | | When your LLM-driven features underperform, how do you pinpoint why? | No clear visibility into model errors or user friction. | AI Observability shows usage, performance, and cost data together. | | How do you know which LLM features are helping vs hurting users? | No clear way to measure LLM impact on user behavior or business outcomes. | AI Observability + Session Replay shows which interactions drive value vs cause drop-offs. | | How do you evaluate your AI Observability in the context of broader product goals? | Standalone tools miss product context. | Integration ties LLM performance to actual product outcomes. |
Surveys
| Question | Pain Revealed | PostHog Advantage | | --- | --- | --- | | When analyzing survey responses, how easy is it to connect them to specific user behaviors or outcomes? | Responses are siloed, making it hard to correlate feedback with analytics or events. | Surveys integrate natively with Product Analytics and Session Replay, linking responses to user journeys and metrics. | | How do you target surveys to the right users without manual segmentation or guesswork? | Less targeted surveys lead to low relevance and response rates. Custom targeting requires dev time. | Display conditions use cohorts, feature flags, and events to show surveys only to specifics users, with built-in response limits. |
Expansion within existing product usage - and up-selling
It's worth calling out a question again: are we selling more of the thing, a more expensive thing, or a new thing? Cross-sell and expansion opportunities can have significant overlap in product plays.
If we're planning expansion, the best way to do this is to replicate usage of existing product with _new_ teams at the same company. This is a bit more straightforward conceptually, and may be harder to execute because you're likely to be starting with a new team from scratch.
You may want to consider expanding usage of the same product within the same team if there is obvious scope to do so here. This can also be difficult as it depends on the individual success and growth of their product, which you can't control.
Trial/Evaluation incentives
If we want customers to use more products, we should incentivize new product adoption. This could be in the form of credits for a specific timeframe to cover adoption and usage of the specific product. For example, if a customer wants to try out data warehouse, we offer 2-3 months of credit for any data warehouse usage as they figure out how they would use it and where it provides additional insight.
We have opportunities to get creative with how we incentivize new product adoption with users. A few ideas are:
Bring them over at competitor pricing for X months
We could eat Launch Darkly's lunch
Free trial / $0 product usage for X months
Related to the above suggestion for credits, this would be a more "on rails" approach
Give them additional credits on top of their new product usage
If they adopt data warehouse, don't just cover their usage, give them an additional 5% for each new product adopted
Could we offer in app notifications about good combinations of products?
If a user is using feature flags heavily, we should suggest experiments
Easier migration for competitors products
Each additional paid product adopted above 3 adds 5% discount
Our first example here is for cross-selling Error tracking, which generally has the below requirements. Feel free to copy this as a format for other bundle motions where applicable.
Product specific pre-reqs
You understand their engineering processes and timelines (at least on a high level) and expect them to have resources available to look into Error Tracking.
They have implemented PostHog Analytics (and ideally Session Replay) into their application(s) and are actively using those features.
You know which teams to talk to regarding Error Tracking, you have identified the people best suited to successfully implement Error Tracking.
They have expressed pain points that Error Tracking can help resolve.
Motion
Qualify if an account is suitable for this motion by understanding how they detect, prioritise, and fix errors today. If your stakeholder can't answer or isn't interested, find another stakeholder. If the answer is that don't have a tool to do this, don't link their errors to impact on key user actions within their app or that they prioritise based on error volume or another metric that is equally uncorrelated with impact on UX, this is a good opportunity for this motion.
Suggest that they turn on exception capture for the relevant environment, with a billing limit or free trial set so there is no cost. In exchange offer to find the impactful errors they are missing and help them move towards a UX based methodology for error prioritisation by combining errors with PostHog product analytics data.
Create dashboards of the new error data that correlates errors with drop-offs in conversion events (signups, checkouts, whatever is relevant here)
Share your analysis as a Loom or other low time commitment format for review, emphasising the uplift in conversion events if these errors were prioritised. If required present these findings back to the stakeholders.
If required help your stakeholder build a business case for the additional spend by linking the missed conversion events to value. For example, if the average LTV of a signed up user is 50$, multiply the dropoff in sign up events by 50 to get a rough ROI of finding and fixing these errors.
Pitch this value as a reason to remove the billing limit and expand usage of error tracking.
Product usage signals
Customers don't always ask for Error Tracking directly, but their usage patterns can indicate a potential need. When you review customer accounts and chat with users, look for these signals:
Using session replay to investigate user issues, suggesting they don't have a way to detect errors automatically.
Frequently searching through event logs or funnel drop-offs to find technical issues or user drop points.
Setting up alerts primarily on custom events (rather than exceptions), which could indicate they lack out-of-the-box error visibility.
Creating dashboards or insights that combine product usage with support data, showing a need to correlate bugs with user experience.
Tagging engineering or support teams in insights to ask them to "investigate".
Using manual workarounds to monitor application health, such as exporting incidents from PostHog to spreadsheets or other tools.
Asking how to attribute support tickets or complaints to specific user sessions, which could be easier with automated error tracking.
Chat with users
Engage with users. Look for cues that signal gaps that Error Tracking can fill:
"We keep seeing bugs in production but it's hard to know where they're coming from"
"I'm not sure if we're catching all the errors our users encounter"
"We use logs to try and track down issues, but it's pretty manual"
"We get complaints from users, but it's hard to reproduce what happened"
"We only find out about errors when customers report bugs"
"Is there a way to get notified when critical errors happen in real time?"
"We need to understand how errors are affecting our revenue or user growth"
"It's difficult to connect the dots between bugs and their actual impact on users"
Visiting the error tracking product page (https://posthog.com/error-tracking) and clicking "Get started - free"
Reading blog posts about error tracking:
https://posthog.com/blog/posthog-vs-sentry
https://posthog.com/blog/best-sentry-alternatives
Asking PostHog AI about error tracking
Asking MCP about error tracking
Discovery questions
When reviewing accounts, ask:
Product feedback: "How have you been using session replays and is there anything you would like this product to do differently?" This can reveal gaps that Error Tracking might fill.
Incomplete implementations: Are there any products a customer started to configure but didn't finish? Understanding why can highlight pain points Error Tracking could address.
Product churn: Are there any products a customer used and then stopped? Understanding why can help identify if Error Tracking could solve the underlying issues.
Decision-making timeline: Are they doing annual engineering roadmaps or quarterly goals? This helps you time cross-sell conversations appropriately.
Competitive landscape: Use the SDK scanner to check if they're using a competitor for error tracking, which can help you position PostHog's integrated approach.
Demonstrate the value
Once you've identified customers who'd benefit from Error Tracking, show them value in ways relevant to them.
Product Analytics
A few good starting points:
Track error trends over time: Create a trends insight for $exception events and create alerts when errors hit specific thresholds. You can get both historical trends and real-time notifications on high-impact exceptions to prioritize engineering work.
See if errors are affecting conversion: Combine errors with funnels to figure out if drop-off is happening because of errors – especially if errors are blocking users from getting through critical flows. You can tie this to customer lifetime value to show potential revenue loss. This is also useful for experiments - you want to make sure your variant didn't underperform because of a bug rather than the actual feature you're testing.
Measure retention impact: Track whether users who hit errors come back less frequently.
For all of these, you can layer on data like $exception_types, $exception_values, or $exception_sources to figure out which errors are most common and how they're impacting users.
Session Replay
Session Replay and Error Tracking work wonderfully together – probably the strongest integration we have. You can watch recordings of what users are doing in your app and get clear signals of errors they're hitting. You can search for specific events, jump straight to a given issue, and see what happened before and after – all of which provide valuable context for debugging.
When viewing a session, use the "Only show matching events" toggle to filter by exception-related events. You can use $rageclick to identify UI frustration that correlate with errors – this helps highlight silent frustrations users are experiencing that otherwise aren't communicated. You can also create dynamic cohorts of impacted users and take actions on them.
Other use cases
Feature Flags: Roll out or revert code updates based on users who've hit specific exceptions. This lets you quickly respond to errors by targeting affected user cohorts and minimize impact if users are having a bad experience. Feature flags can act as kill switches – quickly turn off problematic features without deploying changes.
Data Pipeline: Set up custom destinations to send your error tracking exceptions to other sources if the built-in alert function isn't enough.
AI: Leverage PostHog AI or Claude Code to help diagnose, summarize, and prioritize issues based on impact.
Surveys: Use the capture exception template to request feedback from the user when they encounter errors.
Error tracking integrations: strengthen adoption of PostHog's error tracking by integrating with external issue tracking the customer is already using.
PostHog vs other error tracking
Historically, error tracking is something only engineering teams use. With PostHog, there's deliberate value for other teams. For example, marketing can figure out why conversions dipped and look at Session Replays tied to errors. This is incredibly valuable to quickly identify blockers. Other error tracking tools might give you clarity on bugs and errors, but PostHog gives you the complete picture of the user journey.
Common blockers
“This increases costs that we didn’t budget for”
We should proactively give credits so customers can trial a new product. For example:
Free trial: give credits to cover usage of a new product for X weeks / months – make sure this is timeboxed!
Match competitor pricing: if a competitor is significantly cheaper than PostHog, verify this and offer to bring customer over at competitor pricing for X months
More credits: offer to give additional credits on top of new product usage
“My champion doesn’t make decisions on this product”
You should first try to build a relationship with the persona that will be users of the product. For error tracking, this will be engineers who work on areas where exceptions are critical (link to persona page).
Ask your champion how they are currently tackling the common use cases. Identify team members you want an introduction to and ask your champion for a warm connection. You can position it as a learning opportunity, asking for feedback, or a pitch (if you have a really strong understanding of the specific value-add). Help your champion with the internal pitch.
For error tracking, these questions are helpful to start the conversation:
When an error occurs, how easy is it for you to see exactly which user actions led up to it and how it affected the experience?
Debugging relies often relies on reproducing error
Error Tracking tied directly to replays makes root cause and impact obvious.
If you’ve built your own error tracking, how much effort goes into maintaining and correlating it with analytics?
Time wasted maintaining infra, blind spots in analysis.
Lightweight SDK that's tightly integrated with other products.
How do you decide which errors to fix first?
Prioritizing by gut feeling or frequency, not business impact.
Error Tracking + Product Analytics can show which errors have the greatest impact.
If you’re not sure who the persona should be, ask the product team!
“I don’t have the resource or time to implement error tracking”
Position implementation as simple, especially if you’re asking your customer to try out a product for the first time. This is where you shine as a technical success person. Help your customer cut through the cognitive load of figuring out implementation.
Error tracking can be implemented with one click, or two lines of code(depending on the SDK). Hyperlink to the project settings to enable exception autocapture or share the snippet addition for the SDK they’re using. Follow up with a rough plan that is tied with their needs, such as:
Enable exception autocapture – see events flow through
Assess the errors, issue groupings – decide if you want to customise default properties so you’re getting higher quality signals
Work with errors - update the status, view stacktraces, watch session replays and assign to teammates
Set up alerts
You can also help create dashboards to help your customer understand the value of the product.
Action items
What are common Error Tracking dashboards PostHog and current Error Tracking customers are using? How can we help users get started with similar dashboards as easily as possible?
A good starting point for Error Tracking are customers already using Analytics and Session Replay. What other combination of products does Error Tracking work well with?
What is a high level story that shows the value of using Error Tracking in PostHog compared to other solutions the customer is using already? How does it help them to be able to correlate data from Error Tracking with e.g. Analytics and Session Replay?
e.g. as an eCommerce customer, being able to correlate exceptions related to shopping carts with the Analytics data about the value of that shopping cart would allow customers to prioritize fixing bugs based on lost revenue.
e.g. as a b2c company, prioritize errors happening as part of the signup funnel
What metrics do we track to measure success of this initiative?
Percentage of CSM managed accounts using Error Tracking each quarter
New Error Tracking MRR for CSM managed accounts in X quarters
Technical recommendations
Error tracking for the web is significantly less useful without proper sourcemaps. You can see under "Symbol sets" in the configuration menu if the required files are being uploaded correctly.
Encourage customers to set up roles so that issues can be assigned internally to the right people.
Use the SDK health check to make sure they're on the latest SDK versions.
How to cross-sell and upsell additional PostHog products
Cross-selling is a primary focus across all growth oriented teams. In fact, "cross-sell" is mentioned here as many times as success... applying to customer-facing roles including AEs, CSMs, and TAMs.
Success at PostHog comes from identifying genuine customer needs and demonstrating how additional related products solve real problems. The never ending objective is helping customers extract more value from PostHog, which naturally leads to increased product adoption.
Equally important is cross-selling exposure inherent from teams such as product and marketing. If the product, brand, onboarding, and what we are telling customers day to day is inconsistent, we're going to have a bad time.
What does cross-selling mean?
These descriptions below will describe the overall who/what/why and we will evolve specific motions people have found useful to cover the how/when. For a baseline, we will use these general definitions with specific context following for PostHog:
Cross-sell: selling additional products that are useful and complementary to existing customer adoption
Expansion: customer is or will be needing more of already adopted products, in the form of more volume or different business groups and teams in a similar pattern
Upsell (upgrades): offering advanced functionality to an already adopted product, or they're a candidate for an add-on, both of which have higher costs
There are many ways a customer can signal or be primed for growth. All forms we will lay out here which may be in the form of usage, by voicing it directly, or you introducing the right products at the right time.
Wait! What should the relationship look like before you attempt cross-sell?
The relationship is first.
Leading with a cross sell motion is a bit like coming out the gate with offers related to contract billing terms and credits. While there are some limited circumstances where this makes sense, we should almost always start by focusing on the relationship.
The best way to build that relationship is to help the customer. That could be leaning in on a support ticket, offering recommendations around getting more our of PostHog, reducing spend, or even helping clarify docs.
Customers genuinely like PostHog, so engage them like a friendly acquaintance. Being hyper responsive to requests is a great way to build up good will. Another way is to own problems and follow them through to conclusion. Even if support is taking the lead, stay engaged and tie up any loose ends.
Here is a general checklist that should be met before putting a plan to cross-sell. Specific product motions may have additional pre-requsites.
You have an active relationship with the customer – there are regular touchpoints and they are responsive to your outreach.
You understand their product and PostHog implementation. You know which technologies they are using, and how PostHog fits into their setup.
There are no major open issues with their PostHog implementation. They are happy with their current setup and aren’t voicing major frustrations.
There is no active risk to their renewal, and you aren’t already negotiating that renewal.
Clear path to talk to the right people
Ask your current champion who the interesting likely people would be to talk to
Be prepared to identify the right ICPs within the customer team
Identify teams that are responsible for critical paths/functions within their codebase, some examples across products are
Billing teams
Authentication & authorization teams
Data API teams (e.g. REST or GraphQL teams, that see a high volume of queries)
Management API teams (who have to deal with orchestration failures across projects)
Support tooling teams
Job titles that would be interesting are e.g. Platform Engineers, Backend Engineers (especially if they are on one of the teams mentioned above), anybody owning reliability or infrastructure
Growth best practices
Do:
Focus on solving documented customer problems
Provide trial access for evaluation
Share relevant case studies and documentation
Set clear success criteria before expansion
Optimize their implementation before introducing new things
Follow up on product experiments, even small ones
Generally, this is all to provide them with a solution that will make their life better (and make them look better!). It’s a win-win.
Don't:
Recommend products without clear use cases (it’s okay to give awareness or suggest trying out something new)
Create urgency where none exists
Introduce expansion topics during crisis moments
Overwhelm customers with too many products at once
We are friends, now what?
As you build a relationship with the account, learning about who they are, how they make money, and what they care about should naturally happen. Even so, you may need to dig in further, especially if their business is complex. Doing everything you can on your end to understand their business before asking business questions is another way to establish your expertise and build that good will.
There's a balance as any time you put additional burden on your champion or a stakeholder, you are less likely to help them achieve a positive outcome for us or for them. This is common as additional products require additional work to implement.
Then, opportunities!
Identifying growth opportunities
We use a combination of proactive outreach, insights, and automated alerts in tools such as Vitally to identify cross-sell opportunities. Below are some examples and we will go in more detail on specific motions.
You can use these signals which are documented on health-tracking alongside regular customer interactions to prioritize outreach.
The best opportunities connect products to customer outcomes using their terminology and context.
Example signals of cross-sell opportunities
Web Analytics Opp (Marketing): Triggers when companies with marketing roles, >50 employees, and no visits to the web analytics page are identified
B2B Group Analytics Opp: Triggers when group count is 0, group analytics plan is null, and the company type is B2B
Replay Upsell Opp: Triggers for companies with customer success, sales, product, or customer service roles as PostHog users but no session replay usage
FF Opp (High Engineer %): Triggers when a company has a high % of engineers but isn't using feature flags
FF Opp (No Experiments): Triggers for companies who have users in product, marketing, leadership, or engineering roles haven't viewed any experiments
Strong expansion signals
Consistent usage approaching billing limits
Multiple departments accessing PostHog
Questions about problems that other PostHog products solve
20%+ month-over-month event volume growth
Custom implementations replicating native PostHog features
Actively using PostHog competitors identified by using BuiltWith, Wappalyzer, or internal SDK Scanner.
How to run a cross-sell process
You made it here! You have the relationship, and you have the hunch (clear signals) a customer is good for cross-sell. Let's put it in to standard practice by following and building upon cross-selling motions
Here's a taste of what follows:
First you need to find out who cares about the problem that our other products solve - is it the existing team or the new team?
Use a tool like The Org to help you identify new people.
Make sure you are asking for introductions to other teams during the regularly scheduled checkin calls - ‘who else would benefit from this?’, 'are there other teams with similar pain points?'. They will know better than any outside tool to gap organizational relationships.
In-person visits can help accelerate this
Then you need to find out what are they using now to solve the problem (if anything) - surface this during the check in calls that you already have scheduled as part of onboarding if it's the existing team. If you're talking a new team, you'll effectively run this as a new sales process.
Your approach will depend on the product that makes sense here:
If it's already a mature product we have shipped, you should aim to show how the product complements what they _already_ are using in PostHog - don't just arbitrarily sell in a product for the sake of it. For example, you can say ‘other customers that look like you are doing X, this is what we’re seeing’.
If it's something in beta or coming soon, you should start giving them sneak peeks of what's on our roadmap. You can also schedule a feedback session with the relevant product engineer if they’re a great fit - customers _love_ this. Again, consider playing the founder card for something _really_ new and big.
Understanding the blockers to using other products - these could be:
Privacy/compliance concerns (e.g. viewing session recordings) - we have a lot of documentation on this
Already doing it in house/with something else - demonstrated cool ways in which the products integrate and save their team time
May be too far down the line with their own data warehouse - it is hard to do a replacement at this stage, so instead talk about how you can enrich their data in PostHog with what's already in their data warehouse
Not ready to invest the time and resources to implement more tools - tie this to the pain of _not_ having an additional solution in place and emphasize time to value is extremely quick with PostHog e.g. with autocapture, session replay, and (soon) no-code experiments.
Pro tip - if a customer isn't using a PostHog product and there is no obvious reason why they shouldn't, ask them directly why they're not using it!
TAMs create Salesforce opportunities for cross-sell deals they're actively working. This is how we measure whether TAMs are driving multi-product adoption vs. benefiting from organic growth, and how we learn which motions actually work.
This is measurement only - it doesn't change how commission works.
What counts as a cross-sell opportunity?
All four must be true:
Customer is already paying for at least one PostHog product
TAM is targeting adoption of a different product
Expected MRR on the new product is ≥$100/month
TAM is running an actual sales motion (not just hoping they adopt it)
If a customer spontaneously starts using and paying for a product, you don't need to retroactively create an opp. This is for intentional motions only.
How to create a cross-sell opportunity
Use the existing Salesforce record type: New revenue - existing customer
Opportunity stages
| Stage | What it means | |-------|---------------| | Discovery | Identified use case, talking to stakeholders about the problem | | Demo | Showing them the product, connecting it to their specific needs | | Trial | Customer is actively testing the product (see trial guidelines below) | | Closed Won | Customer is paying ≥$100/month on the product | | Closed Lost | Didn't convert - document why |
Not every deal needs every stage. If a customer already knows the product and just needs help getting started, skip to Trial. The stages exist for tracking, not bureaucracy.
When closing an opp (won or lost), do it manually even though Vitally may auto-close goals when a revenue threshold is met. Consciously closing the opp shows you're on top of the account and creates a clean intent-to-outcome link in our data.
Trial guidelines
If you're giving a customer extended time or capacity to try a product before paying, use one of these approaches:
Option A: Billing limit
Set a billing limit on the product (e.g., $500/month cap)
Customer uses it, hits the limit, decides if they want to pay for more
Time-box it: 30 days is reasonable, 60 days max
Option B: Trial
Add credits to their account to cover the trial period
Document the amount and expiration
Clear expectation: "We're giving you X weeks to try this for free"
Either way
Set a clear end date
Schedule the follow-up conversation before the trial starts
Document success criteria: what does "this worked" look like?
What this is NOT
Not a quota change. Commission still works the same way.
Not required for organic adoption. Only for deals you're intentionally driving.
Not for tiny expansions. <$100/month expected MRR doesn't need an opp unless it's part of a trial/POC leading to real adoption.
What we're measuring
Cross-sell metrics are tracked in the sales growth review. After each quarter, we should be able to answer:
How many cross-sell oops did TAMs create?
What was the win rate?
Which products had the highest/lowest conversion?
What was the average deal size?
What was the average cycle time (discovery → closed)?
Now that PostHog has found product market fit, we hold regular growth reviews where we plan work to accelerate our growth and drive revenue. These sessions are only worth running _after_ you've found product market fit because until then you need to focus on building a solution users feel they really need. Once you've found product market fit, growth sessions can help you optimize.
We've established a successful pattern for running these meetings every four weeks and actions we've taken from them have led to some significant increases in monthly revenue growth.
Attendees
We find it's important to bring a mixture of technical people, and those with wide context of what the business is working on. Regular attendees include...
Raquel (Manages lots of engineering teams)
Tim (Co-CEO)
James (Co-CEO)
Charles (Marketing)
Running a growth review
Before the meeting
Before the meeting, everyone creates a list of hypotheses. These can be problems which limit growth, or opportunities to accelerate. They should all be related to growth engineering (e.g. not simple bug fixes), and they should be focused on improving our long term monthly growth rate.
Examples:
"New, more expensive pricing has hurt signups"
"We're not solving bugs quickly and this is hurting word of mouth growth"
"We are losing B2C customers to open source"
"We should charge for products separately so we can upsell on features rather than volume. This would let us charge sooner than our current 1m events/month limit, and would let us keep prices low for people that don't use the full breadth of the platform"
During the meeting
When the meeting starts, allocate 10 minutes for people to read through everything and to add any additional hypotheses.
After reading, watch session recordings of users going through key flows of the product. Allocate 20 minutes for this. This may generate some further hypotheses. For example, users converting to paying customers, users activating, users inviting their colleagues.
During the meeting, you should work through each hypothesis to determine if it is correct and decide how to respond. Answer each hypothesis using available data and write up any actions, such as experiments you want to run, with clearly allocated owners.
After the meeting
Four weeks later, re-run the entire meeting. You may end up carrying some hypotheses from session to session if they're blocked or lower priority.
Growth session template
## Agenda
* 10 mins to read through / add or edit hypotheses
* 20 mins to review session recordings
* 4 hours to work through hypotheses and to create actions
## Hypothesis
Why aren't we growing faster?
*
## Actions
*
Because PostHog offers so many products, and people sign up with all sorts of different needs, we track activation separately for each product.
Every product should have activation criteria - these are used to determine if a user has activated for a specific product yet. If they haven't, and they've showed intent for that product, we can nudge them in the right direction. These are also used to understand what retention looks like for the product, and to figure out what PostHog can do to offer a better experience!
How we track activation, and how to set up an activation query for a new product
This is the basic structure of our activation queries:
An organization triggered a 'product intent' -> This is the 'upfunnel' metric
An organization met the 'activation criteria', usually one, multiple, or a set of qualifying events in a given time period (e.g. 14 days) -> This is the 'downfunnel' metric
An organization triggered an event correlating with product usage 3 months after they showed product intent -> This is the retention / survived metric
Here is an example structure:
Image: image
You can find all per-product activation queries on <PrivateLink url="https://us.posthog.com/project/2/dashboard/130345"> this dashboard</PrivateLink>.
Picking the right activation criteria
The ideal activation metric strikes a balance: enough companies should reach activation (so it's not too restrictive), while those who activate should have high retention (so it's not too easy). To find a couple of potential definitions, you want to look at product usage and think about what behavior could correlate with successful activation (aka the "aha-moment"). This could be things such as
Has done a key event once (such as launched an experiment)
Has done a key event multiple times (such as analyzed 2 insights)
Has done a combination of key events (such as watched 5 recordings, and set a recording filter)
To pick the best activation definion, it's recommended to write the activation queries for multiple potential activation definitions (~5-10), and compare the activation and retention numbers. This leads to a much higher confidence in the activation metric than just picking your best guess.
Which definition is the best indicator for long term retention? You want to pick a definition that gets a sizable number of organizations to activate, but also to retain. But be careful: If you pick a activation definition where only 1% activate, and 100% of those 1% retain, your activation metric is too narrow!
Note on the retention / survived definition: For this, it's recommended you pick whatever tells you they are an active user. It can be the same as your activation definition, or something a bit simpler, as long as it is closely related to the user actually using the product (e.g. in replay, activation is currently defined as analysing 5 recordings AND setting a filter, usage is simply defined as having analysed one or more recordings).
If you haven't already, make sure you also track product intents for your product. It's worth noting that adding new product intents will impact your activation rates (e.g. an existing user intent might be stronger or weaker than an onboarding intent). If you are comparing activation rates historically, it might be worth filtering for intents that rarely change, such as "onboarding product selected".
Read this blog post for a deep dive into how we first came up with our activation definions.
Structure of the SQL query
Our activation SQL queries consist of two parts: A materialised view to count the eligible events, a SQL query on top of the materialised view to count the conversion percentages. We use materialised views to make these queries more performant.
We store the activation logic in SQL queries and not in code to make it easier to see our activation definitions, to experiment with new definitions, and to drill down to understand why a certain bucket might not perform so well.
The following activation logic is stored in the materialised views:
Count only the first product intent per organization (since product usage intents can be triggered multiple times by the same org), as well as filter out cross sell product intents
Check if an organization meets the activation definition within 30 days of showing product intent
Check if an organization meets the retetion / survived definition within 3 months of showing product intent
Here is an example <PrivateLink url="https://us.posthog.com/project/2/sql?open_view=01966c82-9958-0000-7959-1728ad7dd6d4"> materialised view query</PrivateLink>. To write your own, we recommend copying the query and change the product & event filtering criteria as needed.
The following logic is stored in the SQL query:
Check if a organization is both activated AND retained to be counted in retention / survived
Calculate the conversion percentages from product intent -> activation -> retention / survived
To write your own, we also recommend copying one of the existing queries. All our activation queries follow the same structure, which we should also follow for new products. Once you've found a good definion of activation for your product, please do add the final activation query to this dashboard.
Tracking activation in the code
We use SQL queries to analyze activation. In addition, we track product intents and activation in the code. We do this so that in the future we could act on this, e.g. someone showed intent, but they didn't activate? Show them in an-app banner or send them an email.
To add a new product to this, you can add the activation criteria in the product intent model.
This code is run every time an intent is updated. For example, if the activation criteria is "save 4 insights", and we send a product intent every time someone clicks "new insight", we'll also check at that time if they have 4 insights saved, and if so mark them as activated.
Why does this matter?
Tracking activation is important, because it tells us how many companies start using our products successfully each month, and how many retain. Measuring it month over month allows us to see trends, and whether improvements to the product actually made a difference.
If the activation metrics look good, it gives us the peace of mind to focus on new feature development. But if they trend downwards, it's probably a good time to look into our onboarding and "first time user" funnels to see in which areas our UX can be improved.
Because PostHog offers so many products, and people sign up with all sorts of different needs, we track activation separately for each product.
To learn more about what activation is and how we measure it, check out this blog post.
To make sure we're measuring activation properly, we need to know when someone is interested in using a product. If we put everyone who signs up into the activation funnel for each product - without even knowing if they are actually interested in it - then we'd end up with a super large top of funnel, murky metrics, and a dismal activation rate for all products.
So instead of just putting all people into each activation funnel, we try to identify people who are interested in using a product. In other words, we identify people who show _intent_ to use a product, and we record these people (and the moment the intent happened) as events. These types of events are called _product intents_. The product intents mark the top of the funnel for each product's activation funnel.
Product intents are:
Flexible, so they can happen anywhere and any time
Stored in the database, so we can use them in the product if we want
Convertible, so we know if someone who has shown intent for a product has successfully activated
When should I start capturing product intents?
As soon as your product is in any sort of public beta you should start tracking product intents. This is _not_ because you should be hyper focusing on your product's activation numbers at this stage - instead it is so that we can start collecting data for later on when we want to determine a good activation metric.
So, collecting product intents should be a precursor to any sort of public release.
What makes a good product intent?
People click around in the UI a fair amount, so generally you want to find something sufficiently deep, or something that happens multiple times, before saying someone has shown intent. Here are a few examples:
In onboarding, we ask people what products they are interested in. This is a very direct way of indicating intent! If your product has an onboarding flow, we automatically collect a product intent for it.
For data warehouse, when someone actually clicks to set up a source, we consider that an intent. It's a couple pages deep, so people who've gotten there are less likely to just be clicking around.
If someone views docs for your product multiple times (you could keep a counter in localstorage), that could be sent as a product intent.
Is the onboarding product intent good enough for my product?
Nope. Lots of people join PostHog with a single product in mind - and then later realize that we offer other products they also want to use. Each product should have product intents being recorded somewhere past onboarding, so they aren't missing out on data about these types of post-signup customers.
How do I use these product intent things?
Generally we've made the plumbing such that recording these product intents is quite easy.
Figure out where you think the product intent event should happen.
When someone clicks that button / views that page / does that thing, then simply call addProductIntent in the teamLogic. That fires off an API request that records the product intent in the database and sends the event for you. You don't need to send the event yourself - it's all handled.
You must include the _context_ of the intent with this API call, this is so that you can understand what is driving product intent in the analytics. You can store this in the intent_context — and you can find existing intent contexts in the product intents utility.
It's worth noting that adding new product intents will impact your activation rates (e.g. an existing user intent might be stronger or weaker than an onboarding intent). If you are comparing activation rates historically, it might be worth filtering for intents that rarely change, such as "onboarding product selected".
Cross Sells
As well as understanding what actions users take when trying out a product, it's also useful to encourage users to try out other products that would be helpful for them. If you are using product analytics for example, session replay is a really helpful way to understand why a metric is what it is. If you are creating an onboarding funnel to understand your conversion, running an experiment to improve that conversion would be helpful.
We track cross-sells within the product using the same product intent framework. There is a helper for this in the teamsLogic called addProductIntentForCrossSell, which you can use to track cross sells. You can find these in analytics using the usual event for product intent (user showed product intent) and filtering by type=cross_sell.
Why does this matter?
It's important that we understand if people who are trying to use our product are actually successful in doing so. This is a likely imperfect, but better-than-nothing, way to do that. If people aren't having the success we'd expect for a mature product (ie no large feature gaps with competitors), then we should probably look into why - and this gives us a cohort of people to examine, talk to, and track.
Sometimes we might want to offer a customer one time credits to cover an upcoming invoice, for example when accommodating a trial for a new product or offering compensation for a recent incident. Here’s how to do that.
Go to Billing Admin → Credits
Click Add Credit at the top right.
Click Add credit at the top right.
Select the customer from dropdown or search
Enter the total credit amount.
choose from the following options for reason:
First Big Bill
Unwanted Spike
Trial Accommodation
Promo Credit
Incident Credit
Bug Credit
Other
Add any internal notes for context in Notes section.
Include a link to a related Slack message, PostHog Support ticket, or internal discussion in reference link field
Click Save and the credit will automatically be added to the customer’s balance in Stripe and applied to their next invoice.
Things to keep in mind
Credits only apply to upcoming invoices.
If you’re trying to adjust a completed invoice, this should be handled as a refund instead. See refund or credit? for which one to use.
Always include enough context in your notes or reference link so others understand why the credit was given.
When someone signs up to PostHog, we enrich them (figure out the company, its size, the person's role, and so on), score them against our ICP, and push that data into our sales systems. This page explains how that pipeline works and, more importantly, what to do when it stops.
How it works
A PostHog destination fires on every signup and sends it to Clay.
Clay enriches the signup, running cheaper sources first for cost: Clearbit (better on larger companies), then Harmonic (better on startups, richer industry tags), then Clay-native fallbacks only when a field is still missing.
The result is mapped to a consistent set of ICP fields and an ICP score, which are written back onto the PostHog organization and person as properties.
The same signup also creates a contact and account in Salesforce, and a weekend job re-enriches Salesforce accounts. Everything syncs into Vitally, where playbooks turn it into sales tasks.
The single most common failure is Clay running out of credits or hitting its row limit, which silently leaves a window of signups un-enriched. This has happened multiple times, and historically nobody noticed until it surfaced downstream days later. The alert below exists to catch it.
Monitoring
There is a PostHog alert that watches the enrichment write rate:
Insight: Org enrichment write rate (Clay → icp_company_type) — the daily count of enrichment writes landing on organizations.
Healthy: roughly 460–1,500 writes per day, with mild weekend dips.
A gap: the rate collapses to near zero.
Alert: fires when the daily rate drops below 250, checked once a day.
What to do when the alert fires
Confirm it's real. Open the insight. Is the most recent complete day near zero, while signups are still coming in normally? If signups dropped too, it's a traffic issue, not an enrichment one.
Check whether enrichment was turned off on purpose. Sometimes the Clay enrichment is paused deliberately (for example, to conserve credits). If so, that is expected. Snooze the alert and move on.
Find the cause. In order of likelihood:
Clay is out of credits.
Clay hit its per-table row limit and needs a new table with the destination repointed.
The signup destination in PostHog stopped firing.
Fix it. Top up Clay credits, create and repoint a new table, or fix the destination. Clay credit top-ups are owned by RevOps.
Backfill the gap. The organizations created during the outage stay un-enriched unless they are re-run through Clay. Identify the organizations created between the first and last firing day that are missing ICP fields, and re-enqueue them. Without this step the gap is a permanent hole in our data, which is what happened in past incidents. Confirm the write rate climbs back above 250 the next day, and the alert resolves on its own.
Ownership
RevOps owns this pipeline end to end, including Clay credit top-ups and the enrichment configuration. Questions go to the RevOps team.
We score every work-email signup on how well it matches who we build for: AI-pilled software teams at any scale, backed by leading investors or real revenue. This is the ICP fit score. "Fit" because it answers exactly one question: does this company match our definition?
The fit score is definitional, not a revenue prediction. A four-person seed-stage AI startup paying us $50/month can score high, and a large non-software enterprise paying us a lot can score low. A separate expected-revenue score (planned) will answer "what is this signup likely to be worth?" The two are consumed together as a fit × revenue quadrant and will disagree on purpose for some accounts.
Where it lands
The score is stamped on the organization in our internal PostHog project as three properties, written at signup and refreshed whenever the org is re-enriched:
| Property | Values | |---|---| | icp_fit_status | scored / disqualified / insufficient_data / not_found. Check this first: a score is only current when the status is scored or disqualified | | icp_fit_score | 0–100. Never read a missing score as 0 | | icp_fit_version | The formula version the score was computed under (e.g. v0.5) |
An organization with no icp_fit_status at all was never evaluated. Personal-email signups are not enriched, so they never get one; that is different from not_found.
Not to be confused with the legacy icp_score property: that is the old Clay-era formula on a different scale, still written in parallel until its existing consumers (cohorts, flags, scanners) migrate to icp_fit_score. Thresholds do not translate between the two; roughly, legacy > 8 corresponds to fit > 40.
How it works
Each signup's company is looked up in Harmonic by the domain of the work email, and the profile is scored in three steps. This page describes the intent and shape of v0.5. The exact rules, thresholds, and Harmonic fields live in fit_score.py, and every score carries the version that produced it.
1. Hard disqualifiers: score 0, with a reason code
Actual schools and universities. This keys off Harmonic's company type, not its market tags, so an ed-tech startup selling to schools is not caught.
Signups who told us they are a student.
2. Insufficient data: no numeric score
A profile that matched but has no headcount, no funding, no tags, and no web traffic gets insufficient_data instead of a number. These are mostly brand-new companies. We retry them automatically over the following months rather than treating "no data yet" as "not ICP".
3. Weighted components, summing to 100
| Component | Points | What it reads | |---|---|---| | Traction | 35 | Monthly web traffic level (up to 15) plus 90-day traffic growth (up to 20). Growth only counts above a minimum traffic base, because small-base percentages are noise | | Capital | 30 | Total funding tier (up to 20; a raise Harmonic knows exists but not the amount gets the base tier), plus 10 for a quality investor: a fund on our curated list, any YC batch, or AI Grant. Capped at 30 | | AI-pilled | 15 | Any of: an AI tag, AI language in the company description, or a .ai signup domain | | Headcount growth | 10 | 180-day headcount change, by percentage or by net hires | | Software relevance | 10 | Engineering headcount present (10), else software-product tags or software language in the description (7) |
Metadata flags (don't affect the score)
| Flag | Meaning | |---|---| | low_confidence | Scored from at most one of the four core signals (headcount, traffic, funding, tags). Read this as "unknown", not "bad" | | agency_flag | Consultancy or agency. Qualifies on its merits, but downstream teams may route differently | | nonprofit_flag | Non-profit | | quality_investor | Backed by a fund on the curated list, YC, or AI Grant |
Deliberate design choices
Missing fields score 0 within a component, because no enrichment footprint correlates strongly with being outside the ICP. Fully empty profiles become insufficient_data instead, so "no data" is never silently confused with "evaluated and low".
The filters live in two curated lists: the tag lists (which Harmonic tags count as software-relevant, AI-pilled, or quality capital; internal) and the quality-investor list (internal). RevOps owns both and reviews them quarterly. A sheet edit reaches production only when it is synced into a new versioned list config, and each score records which list version it used. YC batches are matched by tag type, so future batches qualify automatically.
Growth windows are horizon-tested: 90 days for traffic (365 days discriminates no better than chance), 180 days for headcount (90 days is one-hire noise on small teams).
How we validated it
We validated the score as a definition, not a predictor: companies that are obviously who we build for should score high, and obvious non-fits should score low.
Customer sanity check: median scores rise monotonically with customer value tiers. This is expected directionally, though we deliberately didn't tune weights against revenue, since this isn't an MRR predictor.
Full-cohort run: across two weeks of work-email signups (about 9.7k), 69% received a score, 5% weren't found, and 1% were disqualified. In production, insufficient_data is about 35% (measured 2026-09-01, 18,396 evaluated orgs: scored 62%, insufficient_data 35%); a daily re-enrichment sweep (live since August 28, 500 US orgs/day) moves roughly a third of swept insufficient_data orgs to scored, so this share keeps falling. Mine's validation cohort — pulled 1–2 weeks after signup, once Harmonic profiles had filled in — measured about 25% insufficient_data. Threshold choice is therefore a downstream-capacity decision, not an accuracy one.
Known limitations
Enrichment coverage is weaker outside the US.
Generic company domains occasionally match the wrong company, so spot check before high-touch outreach.
New companies accrete enrichment data over time. Scores are a snapshot; insufficient_data and not_found signups are retried automatically over the following months.
The Lead Assignment Tracker in Salesforce is the source of truth for who's in the round robin, how leads are weighted, and how to manage assignments. This page explains how to use it self serve.
Understanding the tracker
Navigate to the Lead Assignment Tracker section in Salesforce. There you'll see every person who's part of the round robin, along with the following columns:
User, Role, Territory These identify who the person is, whether they're a TAE or TAM, and which region they cover.
Priority This column controls how many leads a person receives relative to others. The default value is 1. If you set someone's priority to 3, it means for every 3 leads the rest of the team receives, this person gets 1 — so a higher number means fewer leads. Use this if you want to throttle lead volume for a specific person (for example, if they're ramping or handling a reduced workload).
Manual Leads Adjustment This column lets you calibrate a person's total so the round robin stays fair. The most common use case is adding someone mid-month: by the time they join, others in the same region may already have leads assigned to them (lets say 50). Without an adjustment, the system would send that new person a flood of leads to "catch up" To prevent this, add 50 to their Manual Leads Adjustment column to bring their baseline in line with the rest of the team so the round robin distributes fairly going forward. This column is also used to rebalance after time off (see below).
Is Active This checkbox controls whether someone is included in the round robin. Uncheck it to temporarily exclude someone. For example, if they want to pause new lead intake outside of a scheduled vacation. Check it again when they're ready to receive leads.
Note: For planned time off, there's automation in place that handles toggling people on and off based on their calendar. Is Active column is mainly for cases outside of that — like when someone's OOO isn't on their calendar, or they want to pause for another reason.
Adding a new person
Click New in the Lead Assignment Tracker
Select the Salesforce user you want to add
Select their territory from the multi-picklist
Set their role (TAE or TAM)
Add a Manual Leads Adjustment if they're joining mid-month (see above)
Click Save
That's it, they're automatically added to the round robin.
Monthly reset
The Manual Leads Adjustment and total assignment counts reset at the start of each month so you don't need to redo these calibrations on an ongoing basis.
Lead assignments during time off
For scheduled time off, automation handles turning people off and back on based on their calendar — you don't need to do this manually. The steps below apply when someone's OOO isn't reflected in their calendar, or when you need to turn off lead assignments for a reason other than vacation.
In Salesforce → Lead Assignment Tracker
Uncheck the Is Active box to remove them from the round robin
When they return, recheck it and use the Manual Leads Adjustment column to rebalance their totals if needed
In Default app → Routing → Queues
Find the queues the person is part of (US East, US West, EMEA, or Asia based on location; All and Max Availability Queues for everyone)
Toggle their Status to Inactive to stop Default from routing leads to them
When they return, toggle them back to Active
Important: Even if someone marks themselves as "Out of Office" in their Default personal settings, that does not stop lead assignments. You still need to manually toggle them off in the queues.
When to take these actions
≤ 5 days off: Turn them off the day they leave, turn back on the day they return
\> 5 days off: Turn them off 2 days before their leave starts, turn back on the day they return
Calibration after time off
While someone is inactive, others in the queue continue receiving leads — so their totals rise. When the person returns, you'll need to rebalance so the round robin doesn't immediately dump a backlog of leads on them.
In Default Queues: Look at the Total Assignments and Calibration columns. Add the number of leads others received during the absence to the returning person's Calibration field before reactivating them.
In Salesforce: Do the same using the Manual Leads Adjustment column in the Lead Assignment Tracker. For example: if others received roughly 10 leads each while someone was out, add 10 to the returning person's calibration/adjustment field before turning them back on.
Understanding how our revenue moves through different lifecycle stages helps us identify the specific drivers behind our growth, not just the net change in revenue. We use lifecycle analysis to see how much growth comes from new customers, expansions, contractions, and churn. We analyze this at both total revenue and per product levels to understand each component of our business.
Customer lifecycle stages
new
Customers in their first month of paying us.
reactivated
Customers who previously churned but have returned with monthly spend > 0. This signals customers who may be using our services on and off.
flat
Existing customers whose monthly spend remained exactly the same as the previous month. This represents our stable, predictable revenue base.
growing
Existing customers whose spend increased compared to the previous month. This shows how successful we are with our upsell, cross sell, and product expansion efforts.
shrinking
Existing customers whose monthly spend decreased but didn't reach zero. This could be due to usage based fluctuations but also an early warning indicator of customer dissatisfaction or competitive pressure. We pay close attention to this amount and do deeper analysis to understand the reasons behind.
How we calculate lifecycle components
New revenue: total monthly revenue from customers in their first month
SUM(CASE WHEN growth_lifecycle_stage = 'NEW' THEN mrr ELSE 0 END)
Reactivated revenue: total monthly revenue from customers who returned after churning
SUM(CASE WHEN growth_lifecycle_stage = 'REACTIVATED' THEN mrr ELSE 0 END)
Retained revenue: baseline revenue that continuing customers maintained
SUM(CASE
WHEN growth_lifecycle_stage = 'FLAT' THEN mrr
WHEN growth_lifecycle_stage IN ('GROWING', 'SHRINKING') THEN prev_month_mrr
ELSE 0 END)
Expansion revenue: Additional revenue gained from existing customers through increased usage
SUM(CASE WHEN growth_lifecycle_stage = 'GROWING' THEN mrr - prev_month_mrr ELSE 0 END)
Contraction revenue: Revenue lost from existing customers due to reduced usage (negative value)
SUM(CASE WHEN growth_lifecycle_stage = 'SHRINKING' THEN mrr - prev_month_mrr ELSE 0 END)
Churned revenue: Revenue lost from customers who went to $0 (negative value)
-SUM(prev_mrr) WHERE prev_mrr > 0 AND curr_mrr = 0
Rate calculations
Baseline revenue
This the total monthly revenue at the end of previous month which is the denominator for our rate calculations:
Key rates
New rate: How much new revenue we acquired relative to our at baseline revenue
new_rate = (new_revenue / baseline_revenue) × 100
_Example_: 10% new rate means we acquired new revenue equal to 10% of our at baseline revenue
Expansion rate: Growth from existing customers as a percentage of base
We're moving our canonical numbers into PostHog's semantic layer so that any person or agent asking "what's our MRR?" gets the same answer without having to know how it's calculated.
That only works if metrics are named well enough to find and distinguish. These are the ground rules for creating one.
Names are reserved but not permanent. You can rename a metric, redefine one under the same name, and reuse a deleted name later with a new definition. Renaming frees the old name and breaks anything that stored it – saved SQL, run URLs, links – and sends an approved metric back to proposed for re-approval. So treat the name as a reference other things point at, and pick one worth keeping.
1. Name shape
<subject>[_<method>][_<segment>][_by_<dimension>]
Fixed order, so names sort and scan predictably. Only subject is required.
| Slot | What it says | Values in use | |---|---|---| | subject | What's measured, named as specifically as it needs to be | mrr, arr, nrr, gdr, logo_retention, paying_customers, usage | | method | How it's computed over time | current, monthly, quarterly, monthly_rolling, quarterly_annualized | | segment | Population filter | managed, ever_core | | by_<dimension> | Breakdown column the metric returns, one row per value | by_product |
The name says what the number is. Other info about the metric like who reads it, what it was built for etc may change while the number stays the same, so a name built on them may be inaccurate later on.
Don't name a metric after where it's published. If two similar metrics differ because of different windows or different customer segments, put that in the name instead:
Don't name a metric after the workflow that prompted it. A metric built for a growth review is still just MRR by product for the month, and the next person curious about that product wants the same number — they shouldn't need to know where it came from to find it.
The test: would this number exist if the workflow didn't? If yes, the workflow doesn't belong in the name. Something like a per-run cost for a specific internal system is different. There the system is the thing being measured, so it's part of the subject.
One metric with a dimension beats many near identical metrics. If the same number exists for every product, make one metric that returns product as a column and filter it, rather than one metric per product. Give the agent the path to the number and let it narrow down.
The dimension goes last in the name as by_<dimension>: mrr_monthly_by_product returns (month, product, mrr). A segment filters the population, a dimension is a column the metric returns, so nrr_quarterly_annualized_managed is one number per cohort while mrr_monthly_by_product is one row per product.
Adding a value that isn't in the table? Add it to the table.
No units in the name set the unit field instead (usd, percent).
2. What the SQL should return
There's no query engine on top of a metric. Whatever the definition returns is handed to the agent, which filters or aggregates it further to answer the question. Shape the result with that in mind.
Default to a series, not a single number. Return one row per period at the finest grain the number is useful at, usually monthly, plus one row per dimension value if the name has a by_ slot. One series answers "what is it now", "last quarter" and "how's it trending" from a single definition. Make a standalone scalar metric only when a headline number must be exact and the agent shouldn't do arithmetic to get there: arr exists as its own metric for this reason.
One subject per metric. A count of insights created and the number of unique users creating insights are different subjects, so they're different metrics (insights_created_monthly, insight_creators_monthly), not two columns in one. Multiple columns in one metric are ok only when they're windows or components of one calculation that must agree with each other: gdr_monthly_rolling returns 3, 6 and 12 month windows of the same measure, mrr_bridge_monthly returns lifecycle stages that reconcile to a total.
3. Make the difference from siblings visible
The name doesn't need to explain what NDR is, that's what the description is for, and our retention metrics and revenue adjustments pages cover some of the underlying methodology. The name needs to make clear how yours differs from the other similar metrics. If you can't tell two siblings apart without opening both, the qualifier needs work, or it needs a row in the table above.
4. Shared logic goes in a view, not a second copy
There's no way to define a metric in terms of another metric today. So if you're about to paste the same expression into a second metric, create a view instead and have both read from it.
This matters a lot, we already have copies have drifted apart from each other!
One thing to know: editing a metric sends it back to proposed for re-approval, but editing a view doesn't. A view carrying shared business logic moves every metric downstream of it silently, so it needs an owner.
Intent, setup, and engagement are customer level concepts that Sales, Marketing & Website, Customer Success, and Growth all rely on. If you think a definition should change (which events qualify, which table is the source of truth, etc.), see "Adding an event to these definitions" section below and suggest here before you edit a dashboard tile so we can all work off of same source of truth.
Growth's self-serve dashboard tracks these definitions against specific time windows and cohorts (e.g. "% of intent orgs that completed setup within 14 days of signup").
Level of aggregation
Every definition below is at the organization level (PostHog's organization group). An org qualifies once any of its users has triggered a qualifying action.
Standard exclusions:
PostHog's own organization because our own usage is not customer behavior.
PostHog staff inside customer orgs: exclude events where the person's email contains @posthog.com.
Impersonated sessions: exclude events with was_impersonated = true. Impersonation carries the customer's identity, so the email filter doesn't catch it.
Ready-made actions: the event-based definitions (Intent, Engaged, Teammate invited, Teammate joined) exist as actions in project 2, named [RevOps def] … and tagged revops-def. Each action carries the same events and property filters as its table below, so use it in insights and funnels with "unique organizations" math, or in SQL with matchesAction('[RevOps def] Org engaged'). The actions do not apply the standard exclusions – add those in the insight. Setup and Paying have no action because they read billing tables, not events.
Organization vs. customer/billing account: the billing tables (prod_postgres_billing_usagereport, prod_postgres_billing_customer) also have a customer_id a billing system identifier separate from organization_id. Today these are the same level: organization_id and billing customer_id are 1:1 and prod_postgres_billing_customer has a single organization_id per customer row so there's no way to attach multiple orgs to one billing customer in the current schema.
Intent
An org has shown intent once any of its users triggers at least one of the events below. Because orgs take different paths, each event counts on its own. An event qualifies by what it means – did someone deliberately do something with PostHog before getting value from it? – not by current volume – so we can keep this accurate as new products launch and usage shifts between surfaces.
Both the start and the finish of the same flow qualify (onboarding started and onboarding completed; wizard: agent started and wizard: agent completed).
| Event | What fires it | Captured from | |---|---|---| | user showed product intent | When a user performs one of the registered intent actions for a product (choosing a product in onboarding, setting replay filters, opening a product's setup page, …). The specific action is in intent_context. | Server – fired by app actions | | onboarding started | Opening a product's onboarding flow in the app | Browser | | onboarding step completed | Completing a step of an onboarding flow | Browser | | onboarding completed | Finishing an onboarding flow | Browser | | sdk selected | Picking an SDK on the install step | Browser | | onboarding_products_confirmed | Confirming product selection (legacy onboarding screen) | Browser | | product setup task completed | A task in the in-app setup checklist being completed | Browser | | wizard: agent started | The wizard's agent phase starting – in the user's terminal, or as a hosted (cloud) run kicked off from onboarding | Wizard (CLI or hosted) | | wizard: auth complete | Completing authentication in the setup wizard | Wizard (CLI or hosted) | | wizard: agent completed | The wizard's agent finishing its setup run | Wizard (CLI or hosted) | | setup wizard finished where status = 'success' | The wizard finishing its run successfully – the definitive "wizard done" event | Wizard (CLI or hosted) | | quickstart product enabled | Enabling a product from the quick-start panel | Browser | | heatmaps toggled where heatmaps_opt_in = true | Turning on heatmap capture in team settings | Browser | | autocapture exceptions toggled where autocapture_opt_in = true | Turning on exception autocapture in team settings | Browser |
Some events that look similar but do not qualify: the <field> team setting updated events (e.g. heatmaps_opt_in team setting updated). Onboarding saves default settings in bulk, so these fire for nearly every new org – they look like deliberate toggles but usually aren't. Use the toggle events above instead.
An org has completed setup if it has at least one day of non-zero product usage: any counter in org_usage_summary greater than 0 on its billing usage report (prod_postgres_billing_usagereport, one row per org per day, keyed by organization_id). The summary holds per-product counters: events, recordings, exceptions, llm_events, rows_synced, feature_flag_requests, survey_responses, logs_mb_ingested and so on. This is a billing system usage signal. Note a non-empty summary is not enough: a row can exist with every counter at 0, so check for a value above zero.
This is a different concept from per-product activation (see Per-product activation), which is a specific, retention-validated behavioral milestone chosen separately for each product. Setup is simpler: it just means billable data started flowing for the org at all. Use "setup" for this org-level signal and reserve "activation"/"activated" for the per-product, retention-validated definitions.
Signals that look similar but aren't this definition: the single event signal first team event ingested is sometimes used elsewhere as a setup proxy. This doesn't match the canonical definition.
Engaged (customer initiated product or tool usage)
An org is engaged once any of its users triggers at least one qualifying event below. An event qualifies when the action behind it shows a customer getting value: a person deliberately using the product, or automation the customer built themselves. Anything PostHog's own systems fire on a schedule with no human involved doesn't qualify.
One known blind spot: customer automation can outlive its usefulness. A forgotten script keeps its org "engaged" until someone turns it off, and events can't tell us whether anyone still reads its output. We accept that, because the alternative – not counting api – would wrongly mark every API-only customer as unengaged.
The threshold is deliberately a single event. The quality bar lives in which events qualify, not how many times they fire – a count threshold would also quietly set a lower bar for chatty surfaces (one dashboard session emits dozens of events; one Slack question emits two). For health questions, add a window and a tier on top instead: recurring engagement = qualifying events on 2+ distinct days in the window, and team engagement = 2+ distinct engaged users.
Related: one action often produces several qualifying events. An agent creating a dashboard over MCP fires both $mcp_tool_call and dashboard created (with source = 'mcp'); opening a dashboard in the app fires viewed dashboard plus a query executed per tile. Harmless for the definition but another reason never to read summed event counts as "number of actions".
Action: [RevOps def] Org engaged – consuming and creating events together, with the source allowlist and the two historical source IS NULL windows below built in.
The source allowlist
Events captured on the server carry properties.source, which says which surface made the request. Events marked "allowlist" in the tables below only count when source is one of: web, desktop, slack, mobile, posthog_ai, mcp, api, cli, terraform (creation events only – Terraform re-reads every object on each terraform plan, so its consumption events are CI noise)
Machine values never count: cache_warming, alert, export, subscription, self_driving (Signals scouts), posthog_code (headless coding agents), wizard (setup automation). When a new source value appears, it stays excluded until someone classifies it. We'd prefer briefly undercounting a new surface than silently count machines as customers.
Dates to know: source stamping is newer than the events themselves, and older events weren't updated. query executed carried no source before March 2026, and $mcp_tool_call none before 2026-08-17 (#72941) – the same date desktop, slack, mobile and self_driving first appear. Historical windows crossing those dates need source IS NULL OR source IN (...) for the older period only – today's source-less events are exactly the background paths the allowlist exists to exclude.
Consuming data
| Event | What fires it | Captured from | |---|---|---| | query executed (allowlist) | Backend query runner, once per insight/SQL query executed for an authenticated request | Server – multi-surface; source says which (includes MCP) | | logs query executed (allowlist) | The Logs API returning results for a user's query. Live-tail refresh polls are excluded at the capture site. The Logs API bypasses the generic query runner, so query executed doesn't cover it. | Server – multi-surface (includes MCP) | | $mcp_tool_call where source in mcp, slack, posthog_ai | Once per tool call an agent makes. The filter matters: scouts and headless coding agents fire this event too. | MCP server | | insight viewed | Opening an insight in the app | Browser | | viewed dashboard | Opening a dashboard (legacy event name) | Browser | | recording viewed | Opening a session recording | Server – app-driven | | chat with ai | A Max conversation turn | Server – app + Slack; carries no source | | error_tracking_issue_viewed | Opening an error issue's detail page | Browser | | llma single trace loaded | Opening an LLM trace | Browser | | web analytics filter applied | Changing a filter on the web analytics dashboard | Browser | | notebook opened | Opening a notebook | Browser | | Inbox report opened | Opening a report in the Inbox – the human end of self-driving | Browser | | heatmap screenshot generated | Generating a heatmap screenshot | Browser | | pr_merged where origin_product = 'signal_report' | A customer merging a scout-authored PR into their own repo. Merging is a human act accepting PostHog's work – the strongest self-driving value signal. Only with this filter; see the exclusion list for unfiltered pr_merged. | GitHub webhook |
Creating things
Creating things counts as engagement even before any data gets consumed: a new flag or destination is the org putting PostHog to work. All server-side rows use the allowlist, including terraform.
| Event | What fires it | Captured from | |---|---|---| | insight created, dashboard created (allowlist) | API layer, when an insight/dashboard is saved from any surface. The allowlist drops source = 'wizard' – insights and dashboards the setup wizard creates are setup, not engagement. The starter dashboard every new project gets fires no event at all. | Server – multi-surface | | feature flag created, experiment created, cohort created, alert created, endpoint created, hog_flow_created, action created (allowlist) | API layer, on creation of the object | Server – multi-surface | | data warehouse source created (allowlist) | Connecting a Data Warehouse source. The allowlist excludes sources the self-driving flow connects automatically (source = 'wizard'). | Server – multi-surface | | survey created, survey launched | Creating / launching a survey | Browser (survey launched also has a small API/MCP slice) | | source created | Finishing the Data Warehouse new-source wizard in the app (Stripe, Postgres, ad platforms, file uploads, …). The browser-side twin of data warehouse source created above – same action, captured on both sides. | Browser | | Task created | Creating a task, in the app | Browser | | Signal source connected | Connecting a signal source in the Inbox UI | Browser | | Scout config changed where setting = 'enabled' and new_value = true | Turning a Signals scout on | Browser | | annotation created | Creating an annotation (in the app, or from deploy hooks via the API). No source on these yet – they're deliberate acts in practice; add the allowlist filter once the backend adds it. | Server – carries no source | | batch export backfill created | Starting a batch-export backfill. Same caveat: no source yet. | Server – carries no source |
Events that look like engagement but aren't
Each of these looks like usage but fires without a customer doing anything deliberate. Adding any one of them would wrongly mark orgs as engaged:
marketing analytics query performed – captured inside the query runner, fires on dashboard refreshes and exports, carries no source. Human marketing-analytics usage is covered by query executed.
error_tracking_issue_created – system-generated per issue.
pr_created / pr_mergedunfiltered – ingestion of the customer's own repo activity. pr_created with scout origin is also out: a scout opening a PR is machine output (the human counterparts are pr_merged with the signal_report filter, and Inbox report opened).
survey shown / survey sent / survey dismissed – the customer's respondents answering a survey, not the customer using the Surveys product.
endpoint executed – automated API traffic by design.
llm analytics usage – a backend usage rollup, not a user action.
insight refresh time, dashboard insight refreshed – auto-refresh.
first team event ingested – fires per org member, and measures ingestion, not usage.
signals_scout_* – scheduled machine runs.
Inbox onboarding decided – records which onboarding mode a user ended up with (defaults included), not a deliberate opt-in.
Toolbar events – deliberate toolbar use on the customer's own site (toolbar mode triggered, toolbar feature flag overridden, toolbar selected HTML element) would qualify in spirit, but the toolbar attaches no organization group to any of its events, so none of them can count toward an org until that's fixed. toolbar loaded (presence, not use) and toolbar token expired (fires for anonymous visitors of customers' sites; its user count roughly equals its event count – the signature of machine-generated events) wouldn't qualify regardless.
$workflows_email_opened / $workflows_email_link_clicked – PostHog's own lifecycle emails. Opens are pixel-tracked (machine-inflated by mail clients); clicks are human but measure engagement with our emails, not the product – the click lands in-app where real events fire.
Adding an event to these definitions
Before adding an event, check all four:
It carries the organization group. The group on the event records which org the action happened in, and org-level queries silently drop events without it. Joining person → org membership is a last resort: some users belong to several orgs, so a join has to guess what the event itself knows.
It fires once per deliberate action and not on background refreshes.
It's captured where the action happens (the request or UI layer), never inside a query runner or data pipeline.
It's convincing on its own. These definitions are a list of alternatives, so one bad event wrongly marks orgs no matter how good the rest are.
Server-side events also need the source allowlist. When the page changes, update the matching [RevOps def] action in the same change so the two stay identical.
Teammate invited
An org has invited a teammate if it has any of the following events: team member invited, user invited, bulk invite executed.
An org has a second teammate once any of these fire:
user signed up where is_organization_first_user = false – a new account created into an existing org (invite link, or SSO domain auto-join)
user joined organization – an existing PostHog account accepting an invite into the org
Both are server-side and carry the organization group. Invited is the weak signal (an email was sent); joined is the strong one (a second human is in the org). One gap: an existing user who auto-joins through a verified SSO domain fires no event.
An org is paying in a given month if its total_mrr (from iwa_summary_customer_month, keyed by organization_id) is greater than 0.
Startup credit orgs are identified separately, via startup_plan_start_at in prod_postgres_billing_customer.metadata This flags an org that is on startup plan and is covered by credits rather than paying cash.
Credit covered conversion: a startup plan org can still behave like a converted, paying customer even while its cash MRR is $0. We flag this by combining the startup flag above with usage data: an org counts as a credit covered conversion once, in some month, it's on the startup plan (has a non-null startup_plan_start_at) and its usage in iwa_summary_customer_month exceeds the standard free-tier allowance for any product (e.g. product_analytics_usage, session_replay_usage, feature_flags_usage, llm_analytics_usage, posthog_ai_usage, workflows_emails_usage, workflows_destinations_usage thresholds per our pricing page, since those change over time). This matters because it's a real conversion signal: the org has grown past what a non credit account would get for free even though it won't show up in cash revenue metrics until the credits run out.
Why these metrics may look different
The definitions above describe what qualifies an org for a state. Any specific tracked metric adds three more choices on top of a definition: a population (which orgs count), a time window, and whether stages are chained into one funnel or measured independently. Two metrics that both reference "setup" can give different looking answers even though neither is wrong, because these choices differ.
Time frames: "Setup" itself has no time limit, it's non-zero usage, ever. A tracked metric layers a window on top: "completed setup within 14 days of signup" (a speed-of-onboarding read) is a different number from "completed setup, at any point, no deadline" (a volume read). Both use the same setup definition, but they don't match because the window differs.
Full funnel vs. independent cutoffs: A metric can chain stages together end-to-end e.g. "signed up AND showed intent AND completed setup within 14 days AND was still engaged in week 4". In this case only orgs that cleared every gate in sequence count. Or it can measure a later stage independently, anchored to its own clock e.g. "of orgs that completed setup, what % later engaged, counted from THEIR setup date, regardless of how long signup-to-setup took." The chained version gives a strict end-to-end conversion rate vs. the independent version isolates whether a later stage is healthy without conflating it with how fast an earlier stage was. Don't assume two "engagement" numbers are measuring the same thing just because they're both built on the setup/engaged definitions above.
Intent timestamps can land late: the intent list includes both the start and the finish of flows, but start events often fire before login and miss the org group (wizard: auth complete never carries it; wizard: agent completed always does). For some orgs the first intent event we can tie to them is therefore a finish event – their "first intent" lands around setup time, and a chained metric like "showed intent then completed setup within 14 days" passes automatically for wizard orgs where a single run does both. Don't read first-intent timestamps as "strictly before setup".
If a metric doesn't match what you expected, check which population, window, and chaining choice it's using before assuming a definition changed.
RevOps at PostHog is the Product Manager for Sales, Marketing, and Executive teams. Just as PMs help engineering teams build better products by connecting user needs with technical solutions, RevOps helps go to market teams make better decisions by connecting different parts of the business together.
We do this by combining data from marketing, sales, product usage, and customer success to show what's working and what isn't. While individual teams deeply understand their specific areas, we provide insights about how different parts of the business affect each other and help teams see these connections to drive revenue growth for PostHog.
RevOps values
Make data simple
Build for self service
Automate relentlessly
1. Make data simple
PostHog has data everywhere: product usage, sales pipelines, support tickets, revenue numbers. With this wealth of data comes complexity. We turn this scattered data into clear insights teams can use.
This means:
Creating reliable, unified views that combine data from multiple sources
Building clear abstractions that hide unnecessary complexity
Maintaining source of truth definitions for key metrics
Finding useful patterns in customer behavior
Showing how each team's work affects our customers
Creating views to show total monthly MRR, per product MRR, and per product usage, and filters out the anomalies to make sure make sure analyses are accurate and consistent across teams was one of the early steps we took in this direction. Unifying data from our billing system, Salesforce, and Vitally to have full context on biggest gainers and losers queries to show full context on which customers' spend changed the most was another one to simplify access to this info and quickly take action when needed.
2. Build for self service
Teams should get the information they need without waiting for RevOps. Like engineers ship without PM approval, go to market teams should be able to analyze and act on data without asking us.
This means:
Making all our data and processes visible by default
Helping teams answer their own questions
For example, we built a self-managing lead pool where leads automatically move if they haven't been touched in 7 days. Instead of leads getting stuck with specific AEs, any sales team member can now pick up and run with these potential opportunities. This keeps leads fresh and moving while giving everyone on the team a chance to work with promising accounts, no RevOps intervention needed.
3. Automate relentlessly
Manual work wastes time and doesn't scale. If someone has to do something twice, we automate it. We rely on teams to tell us what's not working because they see the problems first.
If a team at PostHog struggles with revenue operations, we've probably:
Not automated enough tasks
Tried to automate something we shouldn't
Made data too hard to access
Miss important customer data
For example we built an automated workflow that identifies product qualified leads in real-time. When a company hits key milestones (like having 5+ active users and using multiple products) and matches our ICP they're automatically flagged as a new lead in Salesforce with their usage data so the sales team can now instantly see which customers can benefit from outreach and why instead of having to piece this information together themselves.
RevOps vision
Things we want to be brilliant at
Standardize key metrics: Own and maintain clear, consistent definitions for our most important business metrics including:
How we recognize revenue (annual vs monthly plans, upfront vs usage based payments)
Revenue retention calculations (what counts as expansion vs new business)
Customer definitions (who's an active customer, who's usage qualified)
How we forecast revenue (how do we predict future revenue based on current usage patterns, conversion rates, and expansion signals)
This ensures everyone across the company uses the same language and measures success the same way.
Connect the dots: Help teams understand how their work impacts others, things like:
Track how specific marketing campaigns drive upsell and cross sell
Measure what corraletes with strong retention rates
Monitor which product features lead to customers expanding their usage
Rapid insights: Build self service tools that help teams quickly answer their own questions:
Dashboards to easily track real time changes in key metrics
Alerts when important customers change their usage patterns
Easy ways to analyze customer behavior without needing SQL
Things we want to do next
Revenue attribution: Understand how customers move from free to paid, including what features they use, how long it takes, and what influences faster conversions. When a customer upgrades or buys more, know exactly why: was it reading docs? using a specific feature? talking to support?
Predictive analytics: Build on our work around identifying expansion signals to get ahead of customer behavior, find customers likely to buy more before they ask, and identify unhappy customers before they leave.
Things we don't want to spend time on
Being the "data police": We don't want to spend time enforcing data formats or policing how teams use tools. We focus on making it easy to do the right thing, not enforcing rules
Running reports for people: If someone regularly needs data, we should teach them how to get it themselves.
Clean up projects: If we're constantly cleaning up data problems, we've built the wrong systems, and should fix the source problems instead.
Responsibilities
What RevOps owns
Revenue insights:
Reporting company wide metrics: revenue, retention, expansion, churn
Help sales, marketing, and exec teams understand what drives revenue
Identify patterns in customer behavior
Build shared understanding of revenue and retention reporting across teams
Sales tech stack including:
Salesforce administration and optimization
Enrichment and intelligence tools (e.g. Clay, Clearbit, Sales Navigator)
Revenue reporting and forecasting: RevOps provides recommendations and improvements but does not own implementation and maintenance. This is currently owned by the .
Marketing operations: Marketing owns their campaigns and analytics, we help connect marketing data with revenue outcomes.
Product operations: Product teams own their metrics and experimentation, but we help track how they impact overall revenue.
What RevOps doesn't do
Financial accounting (though we work closely with Finance)
Individual sales deal management
Billing/invoicing platforms, and data infrastructure for revenue reporting owned by the
We use Net Dollar Retention (NDR) and Gross Dollar Retention (GDR) to track how well we're retaining and growing customer revenue over time. We use adjusted revenue to calculate these retention metrics for a more accurate picture of our business. This way, we get clearer signals about retention by removing the noise from spikes, trials, and organizational shifts.
How we calculate
We use a rolling time period approach that compares customer revenue from a base month to the current month:
For each calendar month, we look backward to identify the "base month" (3, 6, or 12 months prior)
We identify customers who were active in that base month with minimum $5K annual revenue
We compare what those same customers were paying then versus what they're paying now
NDR (Net Dollar Retention)
NDR shows total revenue retention including expansions, contractions, and churn.
If NDR > 100%: We're growing revenue from existing customers (expansions outpace contractions/churn) If NDR = 100%: We're maintaining the same revenue from existing customers If NDR < 100%: We're losing revenue from existing customers
GDR (Gross Dollar Retention)
GDR shows how much of our base revenue we're retaining, without counting expansions.
Raw revenue numbers can sometimes be misleading due to various factors that don't reflect the true health of our business. Our adjusted revenue methodology helps us account for these factors to get a clearer picture of our growth.
Why we adjust revenue
Create a more accurate representation of our business performance
Identify growth patterns by removing short term noise due to the nature of usage based revenue
Easily spot any anomalies in growth patterns
Standardize our reporting methodology
Where we use adjusted revenue
We continue to report unadjusted revenue for our top line reporting and overall growth metrics. We use adjusted revenue for retention metrics (NDR/GDR) and other business lifecycle analysis to get a clearer picture of our growth. This way we maintain standard financial reporting (unadjusted revenue) while getting a better understanding of our performance (via adjusted revenue).
Adjustments
We make the following primary adjustments to our revenue data:
1. Trial adjustments
Revenue from customers who are testing our platform with the intention of potentially moving to self hosted or another solution.
Why: Including trial revenue in our regular metrics could create an artificially inflated view of sustainable ARR, especially if we know the customer is likely to leave.
How:
We flag accounts as "trials" when we know they're evaluating our service (typically identified by our sales team)
We remove the revenue from these accounts when calculating retention and other business metrics
2. Revenue spike adjustments
One time significant increases in customer spending that don't represent sustainable revenue growth. This could be due to bot attacks, implementation errors, or sudden unexpected increase in volume on the customer side.
Why: These spikes can significantly distort our monthly growth metrics and don't represent sustainable revenue we can count on going forward.
How: We define a spike when all these conditions are met:
Customer's current month revenue is more than twice the average of the previous two months
The increase is at least $1000 in a given month
The following month's revenue decreases by 50% or more from the spike month
3. Annual plan adjustments
Accounting for the full spending potential of customers on annual plans who receive discounted credits.
Why: This gives us insight into the actual usage value customers are receiving, which is often higher than what they pay due to annual discount incentives.
How: Calculate what customers would have paid without the annual plan discount (annual_mrr_value = total_mrr / (1 - discount))
4. Account consolidations
Reconciling multiple accounts that belong to the same organization.
Why: Organizations sometimes have multiple accounts that should be viewed as a single customer for accurate revenue analysis. This way we can make sure we're tracking true customer retention rather than treating internal movements as churn
How:
identify and consolidate accounts when customers move from EU to US instances
combine revenue and usage from different teams under the same organization that may exist as separate PostHog accounts
5. One time credit / refund adjustments
Revenue credits that temporarily drop a customer’s billed MRR to zero (e.g., one time promo credit, incident credit etc.)
Why: If we count one time large credits as churn in our retention math we’ll understate our true net revenue trends. Excluding these prevents misleading dips and spikes in monthly growth patterns.
How: check for following criteria:
credit is issued for a promo, outage, or a billing correction AND
total credit amount ≥ 0.5 \* prior month revenue AND
next month revenue is >= previous 2 month avg revenue
if all three are satisfied we override that month’s revenue to equal prior month’s revenue.
We have different roles who manage customers through their lifecycle. Customers typically sign up and start paying on their own, or land via a Technical Account Executive. Once an account hits $20k a year in spend, a Customer Success Manager becomes the point of contact. A Technical Account Manager is added on top only where there's a qualified growth opportunity.
The customer journey and coverage model covers the phases an account moves through and who covers it at each one. This page covers the operational side: book planning, how TAMs get added and removed, and handover mechanics.
We're partway through this transition. Not every $20k+ account has a CSM yet, so some accounts are TAM-only for now. The rules below describe where we're headed. Where today works differently, we've noted it.
How coverage works
CSMs are the base layer
Every $20k+ account gets a CSM. They own the relationship: onboarding depth, product health, engagement, retention. If nothing else is happening on an account, the CSM is who the customer knows.
TAMs are an overlay
A TAM joins an account only when there's a qualified expansion opportunity. That could be cross-sell, workload expansion, annual conversion, or a renewal worth actively working. How to judge whether an opportunity is real is covered in how to evaluate an account's revenue growth potential. Without a qualified opportunity, the account stays CSM-only.
In customer journey terms: a TAM is on an account while it's Expanding (or Implementing, when a deal closed with a qualified opp already attached). When the account reaches Steady state, the TAM comes off. The CSM was there the whole time, so nothing gets handed over.
Where there's expansion potential but no TAM capacity yet, an account can sit CSM-only until a TAM can be added.
A note on primary products
We used to route accounts between TAM and CSM based on primary product adoption (Session Replay, Feature Flags, Error Tracking, tracked in Vitally as Paying for <Product Name>). That was the old model. Product count is still a decent rough signal, since an account paying for all three is often closer to saturated. Rather than using a strict product adoption method, we rely on the framing in how to evaluate an account's revenue growth potential to determine if there's actually expansion potential.
Churn saves
An at-risk account follows the risk mitigation and churn prevention playbook, same as always. Flag early with the Churn Risk tag, dig into the why, and run the save.
When both a TAM and a CSM are on the account, they co-own the save. Both are responsible, and neither should assume the other is handling it.
An account going at risk is also not a reason to add a TAM. Churn saves are generally not a legitimate TAM opportunity. Risk on a CSM-only account stays with the CSM unless a genuine expansion opportunity qualifies through the normal path.
Competitive renewal
Accounts owned only by a CSM can benefit from TAM overlay where we know a competitor is being evaluated ahead of renewal time. CSMs should be having renewal conversations early (3 months out from the renewal date) so that we can get a TAM involved and compete hard to win the renewal.
Trying to layer in a TAM to a competitive situation 30 days from a renewal isn't enough time to meaningfully impact the competitive evaluation.
Below $20k
Accounts below $20k don't get a CSM or TAM. The coverage map covers who (or what) handles them, including Growth TAM coverage and automation.
---
TAM book balance
TAM book size is set by ARR under management. Account count follows from that. This mirrors how CSM books are balanced, by shape as well as total.
Target: Around $1.5M to $2M ARR per TAM. This usually works out to 12-18 accounts. There is a little in-quarter wiggle room, but generally TAMs should focus on a defined book of business.
Rough makeup: 1-2 accounts around $200k ARR, 3-4 around $100k, and the rest in the $30k-$100k range.
Beyond total size, a balanced book also needs:
Billing mix. At least 40% of book ARR on monthly billing. Annual accounts still have plenty to work: renewals, cross-sells, and expanding into more of the org. But monthly accounts are where annual conversions come from, and usage growth there turns into cash faster, so a book with little monthly billing has a thin conversion pipeline.
Conversion candidates. At least 2 accounts above $100k ARR with a realistic path to an annual conversion this year.
A staggered renewal calendar. If half your book renews in the same quarter, a single weak quarter can set back the whole year, so spread renewals across the calendar.
Concentration awareness. Two $200k accounts can be a quarter of your book. That's fine, but know what losing one does to your number. Don't stack more concentration than that.
If your book is outside these bounds at quarter start, work with your team lead to rebalance.
CSM book balance
CSM books target around $2.5M ARR and are balanced by account size as well as total ARR. The current account mix and live capacity calculation are covered in how the Customer Success team works.
If your book is outside the current target at quarter start, work with your team lead to rebalance it.
Adding a TAM to an account
There is no CSM to TAM handoff anymore, because the CSM never leaves. Instead, when someone spots a growth opportunity on a CSM-covered account, they flag it for a TAM.
Anyone can flag: the CSM, a TAE, support, or automated alerts. The flag routes to a TAM in the right region for qualification.
The receiving TAM qualifies the opportunity using the growth potential framework. If it holds up, they join the account as the overlay, open the opp, and intro themselves to the customer with the CSM's help. If it doesn't, they document why in Customer Analytics and the account stays CSM-only. A documented "no" is still useful. It stops the next person re-litigating the same idea in 3 months.
We track coverage in Customer Analytics with the existing tags: CSM Managed for the base layer and AM Managed for the TAM overlay. An account with both tags has both.
---
Removing a TAM from an account
A TAM stays on an account through expansion until it's fully saturated, not just until the first opportunity closes. As long as there's a realistic next play to work (another cross-sell, a new team to land, an annual conversion), the TAM keeps the account and works it. They come off once expansion is genuinely exhausted. In journey terms, the account moves to Steady state and the overlay is removed. The CSM stays, so the customer keeps their point of contact throughout.
A TAM being willing to release an account is itself a decent signal the upside is gone. TAMs are paid on their book, so they don't give up real opportunities lightly. But treat it as a signal and sanity check it. Team leads should verify before agreeing. Team leads should post in public for visibility and approval before removing
Removing a TAM is usually a good outcome, and typically means a healthy, expanded customer. Inventing an opportunity to justify staying on is worse than coming off cleanly.
TAM removals generally happen at the end of the quarter. Accounts can be added to a book at any time, but plan removals for quarter end so books stay stable and handovers get done properly rather than rushed mid-quarter.
Keeping the context with the CSM
The CSM stays on, so nothing about the customer relationship changes from their side. But the TAM knows things the CSM doesn't, and that context has to land somewhere before they leave:
A handover note in Customer Analytics covering: what expansion plays were run and how they went, commercial context (discounts given and why, anything promised, credit terms), open threads, who the real decision makers are, and who on the customer side owns the renewal (champion or procurement, and how the last one went). Use the handover note skill.
A 15 minute call with the CSM to cover what's not in the data. Politics, sensitivities, what you'd try next if a new opportunity shows up.
The Slack channel stays open. The CSM keeps it. Don't archive it. Channel archival only applies when an account exits managed coverage entirely.
Removing the TAM in Customer Analytics. Once the note and call are done, the team lead removes the TAM and the AM Managed tag from the account, with Ben's approval.
If the same account gets a qualified opportunity later, it goes back through the normal flag and qualification path. The handover note is what lets the next TAM (maybe you) pick it up fast.
What is NOT a valid reason to come off an account
Low engagement or an account being difficult is not a reason to come off. That's the job. Specifically:
Account doesn't respond to your outreach
Champion left and you haven't re-established relationships
Low user activity or poor health score
You don't like working with them / they don't like you
If an account is struggling on these dimensions, that's a signal to invest more. The saturation checks require evidence that the opportunity is gone; an account being hard to work is not the same as the opportunity being gone.
---
Doing the allocation
Each quarter, TAM and CSM team leads review coverage and rebalance books. TAM allocation requires Ben's approval; CSM allocation requires Simon's approval. Accounts can still be added during the quarter when a handover or qualified growth opportunity requires it.
TAM allocation
A TAM is added on top of CSM coverage where an opportunity qualifies. At the start of each quarter, TAM team leads, with Ben's approval, review:
Accounts tagged tam overlay needed where a CSM has identified a growth opportunity
TAM books outside the $1.5M-$2M ARR band to identify which accounts to rebalance
Accounts where the TAM should be removed because expansion is exhausted
Once the decision is settled, the team lead updates the tags and assigns the specific TAM in Customer Analytics.
To request CSM coverage, add:
csm overlay needed when you are keeping the account but need CSM support
csm handover needed when you are handing the account over to a CSM
CSM allocation
Every $20k+ account should have a CSM. At the start of each quarter, CSM team leads, with Simon's approval, review:
The Uncovered customer backlog canvas to find accounts without a CSM
Accounts tagged csm overlay needed or csm handover needed that need a CSM assigned
CSM books outside the current target to identify which accounts should be rebalanced
For accounts with no previous owner, use PostHog GeoIP data to identify the account's primary region. The relevant team lead then assigns the CSM in Customer Analytics.
Once a day an automation runs which adds a region tag to the account to assist in routing to the correct team.
To request TAM coverage for an account with a qualified growth opportunity, add the tam overlay needed tag in Customer Analytics.
Mid-quarter TAM changes
Account removals should only happen at the end of the quarter so that quota can be calculated correctly. However, accounts can be added to your book at any time if you're confident there's growth potential.
If you're assigned an account with a previous owner, work with them on a proper handover. If the customer isn't in a healthy state (usage and engagement-wise), push back and ask the previous owner to get them to a good state first.
New accounts with no previous owner come with a 3 month grace period – if they churn in that initial period, they won't count against your quota. Don't ask for the AM Managed tag to be added until you're confident there's growth potential.
---
Top 40 account management
Our highest-spend customers (~Top 40 by ARR) get special consideration. Adding or removing a TAM on a Top 40 account is decided directly by Ben and team leads rather than the standard Team Lead process. The bar for change is higher here. Sometimes a TAM stays on a saturated account because the relationship is strong and there's long-term strategic value.
---
Handing over customers
To help the new owner hit the ground running, we should make sure the customer is in a good state and a warm introduction happens.
TAE handoff goes to a CSM, always. This typically happens when onboarded, around 3 months after the initial credit purchase, or 12 months after the initial credit pre-purchase if the TAE retains the account against a specific opportunity (see the journey page ownership rules). If a qualified expansion opportunity exists at handover, a TAM is added at the same time.
TAM add and removal aren't handoffs, since the CSM stays throughout. See Adding a TAM and Removing a TAM above.
For accounts who will be landing at $100k+ a year or have high expansion potential after the initial deal, we should involve a TAM early in the process to ensure a smooth transition. See the section further down this page on how this works.
When in doubt, ask yourself: do I see this account growing in the next year? If not, it doesn't need a TAM
For handover to take place there should be an Account Plan (saved as a note on the account in Customer Analytics) and the customer should have been onboarded properly to the products they are currently paying for.
All open invoices should also have been paid before handing over. It makes sense to use existing relationships to chase payments, rather than the new owner's first action needing to be chasing payments/suspending access for non-payment.
For TAE accounts being handed over to a CSM, add the csm handover needed tag in PostHog Customer Analytics and flag it with the relevant CSM team lead. There's no need to wait for the end of the quarter. The team lead will review the plan and current state of the customer, then assign a new owner with Simon's approval.
Account Plan
Every account being handed over should have an up-to-date Account Plan saved as a note in Customer Analytics. The existing owner should ensure that this is current and schedule a handover call to walk through it with the new owner. Feel free to push back and ask for it as the new owner if this doesn't happen! Ask your team lead or Simon for help with this if you're not getting the information you need from the previous owner.
Product Onboarding
Before handing over a customer, the existing owner needs to ensure that the customer is onboarded properly to the products they are paying for. We should first ensure that they are only paying for what they need to as detailed in the health checks section of the handbook and then ensure the following steps have been completed, depending on the products they are paying for:
This is an initial pass at what good onboarding looks like for each product. We will refine this checklist as we learn what works.
General principles
They are aware of how to get support both via Slack and in-app and where in-app is more appropriate.
They have the correct owners and admins set up in their PostHog organization.
We have the correct finance contact details in Stripe.
Product analytics
They have set up tracking, implementing posthog.identify() and posthog.group() correctly where appropriate.
They are aware of the difference between anonymous and identified events.
Event capture is tuned and automatic events have been turned off where not wanted.
We have completed training for the core user base, so that they are aware of concepts such as Actions, Cohorts etc.
They have set some insights and dashboards aligned with their use case for PostHog.
Session replay
They have set up tracking using posthog-js.
They are aware of the different recording controls and how to use them.
They have implemented privacy controls where necessary.
We have completed training for the core user base so that they know how to find specific recordings, as well as navigate from other products to session replays (e.g. from a funnel)
Feature flags
They understand how to integrate feature flags into their workflow.
Feature flag calls are implemented correctly so as not to artificially inflate the bill.
They understand the current targeting mechanisms which are available.
We've conducted training on how to set up Feature Flags and Experiments.
Data warehouse
They have connected up the sources they need to.
They are aware of the difference between incremental and full sync and the impact on billing.
We've conducted training on using SQL in PostHog, creating views and joining on person data.
Error Tracking
They have set up tracking using posthog-js.
---
Account handover checklist
Every account handover should include a 15-30 minute call between the outgoing and incoming owner. This checklist helps you prep for that call and make sure nothing falls through the cracks.
When to use this
When a TAE-led customer is being handed over to a TAM after the initial contract is signed
When a TAM is taking over an account from another TAM or TAE mid-lifecycle
As a prep guide for the 15-30 minute handover call between outgoing and incoming owner
Before the handover call
The incoming TAM should prepare by reviewing the following in Customer Analytics and SFDC before the call, so the handover conversation can focus on context that isn't in the data.
Self-serve research (do this first)
[ ] Customer Analytics account overview – review the account profile and available customer context
[ ] Product adoption – which products are they paying for? What's underutilized?
[ ] Usage metrics – active users, project count, Feature Flag requests, Session Replay volume, insight/dashboard engagement
[ ] Support history – recent tickets in PostHog Support, tags, priority, resolution status
[ ] Conversations & notes – read all Customer Analytics notes, meeting summaries, and conversation history
[ ] Customer Slack channel – scan the shared channel for who's actually active on the customer side, what issues have come up, and any open threads worth asking the previous owner about. This is often where the most useful context lives.
[ ] Internal Slack discussions – search our own Slack (outside the shared channel) for mentions of the customer. Engineering debates, pricing conversations, support escalations, and context from the previous owner often surface things that were never written down in Customer Analytics.
[ ] SFDC opportunity – deal value, stage, next steps, close date
[ ] Admin emails & user list – identify who's active, who has admin access, what domains are in play
[ ] The customer's product – sign up or browse their website. Understand what they do and how they make money
Prepare questions based on gaps in the data. The handover call should focus on things you can't learn from Customer Analytics.
Handover call agenda
This isn't an exhaustive list and not every item needs to be covered every time. Use your judgment based on what's relevant to the account.
1. Relationships & people
This is the most valuable part of the handover – relationship context doesn't live in any tool.
[ ] Who is the champion? Name, role, communication style, what motivates them
[ ] Who is the economic decision-maker? Who signs off on renewals and expansion?
[ ] Who are the power users? Engineers, PMs, analysts – who lives in PostHog daily?
[ ] Expansion potential – realistic growth ceiling? New teams, new brands, new products?
3. Technical & product state
[ ] Implementation maturity – basic tracking or advanced setup?
[ ] Known technical issues – open bugs, workarounds, or frustrations?
[ ] Integration landscape – what else are they using? Any competitors still in play?
[ ] Product gaps – feature requests or limitations that are blockers? Note any features with committed delivery timelines from our product teams
[ ] Onboarding completeness – per the onboarding checklist, which products are properly onboarded?
4. Risks & opportunities
[ ] Top risks – what keeps you up at night? Champion risk, competitor risk, budget risk?
[ ] Top opportunities – lowest-hanging fruit for expansion or deeper adoption?
[ ] Unfinished business – anything you wanted to do but didn't get to?
[ ] Anything I should avoid? Sensitive topics, past friction, internal politics?
After the handover call
Immediate actions (within 1 week)
[ ] Update Customer Analytics – ensure New Owner property is set, update account plan note with handover context
[ ] Save an account plan – create or update the account plan as a Customer Analytics note, incorporating handover insights
[ ] Introduce yourself to the customer – warm intro (ideally the TAE introduces you) or cold intro via Slack/email
[ ] Follow up on any open items – pick up in-flight proposals, unresolved tickets, or pending conversations
Tips for a good handover
Focus the call on what's not in the data. You can read Customer Analytics yourself – use the call for relationship context, political dynamics, and unwritten history.
Ask "what would you do next if you were keeping this account?" This often surfaces the most actionable insight.
Move fast on your intro. The longer the gap between handover and first contact, the more momentum you lose.
Keep the previous owner in the loop for the first few weeks if there are open commercial conversations. In some cases they can also serve as a secondary support point for timezone coverage or as an escalation contact.
Unassign yourself in Customer Analytics
Once the handover is complete, the outgoing owner should unassign themselves from the account in Customer Analytics. This keeps Customer Analytics accurate about who is actually on the account.
---
Receiving an account as a CSM
CSMs receive every $20k+ account, whether from a TAE at close or when a TAM comes off. Accounts arriving from a TAM should generally be in a steady state: using the products they need, engaged, no major unresolved issues. It's worth looking beyond the surface to make sure that's actually the case. These aren't a rigid checklist. They're things to dig into that can surface problems which are otherwise easy to miss.
Billing and commercial
Open invoices — verify these have been resolved per the handover requirements above. You don't want your first interaction with a customer to be chasing payment.
MRR trajectory — is spend steady, declining, increasing, or swinging around? Declining or volatile MRR is worth digging into before you take over.
Credit purchases — if they've pre-purchased credits, does the amount actually line up with what they're spending month to month?
Non-standard discounts — review the contract for anything unusual or undocumented. If discounts exist without clear documentation, get context from the previous owner.
Product adoption
Core product coverage - see How coverage works. Receiving accounts with only 1 core product adopted is normal. It just means the previous owner determined there isn't a realistic path to expand right now, and that reasoning should be documented.
Deployment health — if the customer doesn't have basic recommendations in place (e.g. session replay minimum duration, high identify call volume), that's a flag. Check the customer deployment health check guide and the Metabase dashboard to assess this. The product onboarding checklist is also a good reference for what "properly set up" looks like.
Unexplained usage changes — big spikes or drops that aren't documented, or where there's no record of a conversation with the customer about them. These can indicate problems nobody's looked into yet.
Engagement
One-sided relationship — is there a pattern of outreach from our side with no customer engagement? If it's been a one-sided conversation, understand why before you take over.
User concentration — is usage concentrated among fewer than 3 users? That's inherently risky. Have there been attempts to engage beyond those users? If so, why haven't they been successful?
Account documentation
Account plan — one should already exist per the handover requirements above. Check that it's actually there and current — don't assume.
Lower priority
Worth being aware of, but less likely to be blockers:
Open support tickets — any unresolved tickets or known frustrations with specific products?
Upcoming features — anything in the pipeline that's relevant to this customer and worth proactively sharing?
Pushing back
If you're seeing multiple flags — declining usage, no engagement, concentrated users, missing account plan — push back. An account with several of these signals isn't in steady state and probably needs more work from the previous owner before it's ready for CSM. Talk to Dana if you're unsure whether to accept an account.
---
High potential customers
For TAE-led customers who will be landing at $100k+ a year or have high expansion potential into new product areas, we should introduce a TAM earlier on than normal.
The prime time for this is when the technical win is confirmed - the TAM should be introduced to the customer by the TAE in an evaluation or POC wrap-up call when we know that the customer has selected PostHog.
The introduction is purely for relationship building and continuity purposes so that the TAM can hit the ground running with the customer after the initial credit pre-purchase is signed. It's still on the TAE to work with the customer on the deal, and as such only the TAE will be recognized on the initial deal for commission purposes. After the initial deal is closed won the TAM will take over the account in their book of business.
The TAE and TAM should use their overlapping time to work with the customer on a documented onboarding plan per the above guidance.
This account planning framework is designed to help you quickly get up to speed on accounts and consistently think through a set of questions that deepen the partnership with your accounts. It encourages a proactive approach to identifying expansion and cross-sell opportunities, driving growth and customer success. This template was initially developed for managing a book of business primarily consisting of smaller startups. It will likely need modification to be useful for larger, more enterprise, accounts.
Here are some times where it may help:
When onboarding a new account.
As part of a regular account review cadence (e.g., quarterly).
When a significant change occurs within an account (e.g., new funding, leadership change, new strategic initiative, product launch).
To proactively identify and strategize on expansion or cross-sell opportunities.
Any other time you want to. Or not. No one is checking your work.
Account planning template
I. Business info:
Name:
Description:
Website:
HQ location:
Business type: B2B SaaS, E-commerce, Marketplace, Developer Tools, Fintech, Healthcare, etc.
Goal: Identify typical key metrics and challenges for this company type/stage (e.g., MRR, CAC, LTV for SaaS; GMV, AOV for E-commerce).
A. Business stage:
Businesses have different goals and constraints based on funding and stage. A venture-backed early-stage company may be very cash-conscious and focused on product-market fit, while a more established enterprise may be more focused on scaling, efficiency, and locking in multi-year discounts.
Current stage: (Seed, Series A/B/C+, Public, Bootstrapped, Acquired by X)
Funding:
Investors:
B. How they make money:
Key product(s) or services they offer: List their main offerings that their customers use.
Pricing, if available:
C. Vibe-based matrix:
Refer to the vibe-based sales matrix (internal only) - where does this account fit?
Potential ways to cross-sell:
Main risks:
II. Product impressions:
You should always try out a customer's product where possible, as it can give you useful context. It helps you identify best practices we can recommend, understand their user experience firsthand, and spot potential cross-sell or value-add opportunities for PostHog.
Personal impression/user experience notes: Your observations as a potential user – what was intuitive, confusing, delightful? Any obvious pain points or areas for improvement? How do they handle onboarding, core workflows, etc.?
Potential areas where PostHog could provide insight for their product development/UX: "Their checkout flow has 5 steps; Session Replay could help them identify drop-off points." "They just launched a new mobile app; Product Analytics is crucial for tracking adoption."
Their product roadmap: What do you see on their roadmap that PostHog can enable for them?
III. Hiring roles / goals:
Review their careers page, LinkedIn job postings, and any announcements about team growth. Hiring trends can tell us what the business will be focused on in the next 12-24 months, what skills they're prioritizing, and what type of growth the business is forecasting.
Roles currently hiring for:
Goals associated with these new roles: (Document Product and growth related goals. This tells us what the business will be seeking)
Skills associated with these new roles: (Are there specific technical skills required? This can educate us about the customer's tech stack.)
How to position PostHog as an enabler for these roles/goals:
IV. Business objectives :
Collect as much context as you can about the customer and their goals. Look for opportunities to align PostHog to those goals.
What are they trying to achieve with PostHog? / What larger business goals does PostHog support? Increase feature adoption by X%, reduce onboarding drop-off by Y%, identify top 3 user paths to conversion, validate hypotheses for new product Z.
Do they feel the value from PostHog aligns with their expectations and investment? Yes/No/Partially. Are they happy with the value received?
What obstacles are they facing?
In using PostHog effectively: Technical hurdles in instrumentation, knowledge gaps in using advanced features, specific feature limitations for their use case, not enough time/resources allocated.
In their overall goal achievement (where PostHog might help but isn't fully leveraged): Lack of engineering resources to implement new tracking, siloed data preventing holistic views, difficulty translating data into actionable insights.
Are there upcoming constraints? Budget freezes, code freezes, headcount restrictions, technical migrations, major product re-platforming, seasonality impacting their business.
What do their future needs look like (6-18 months)? Where does PostHog fit into their roadmap? Scaling analytics capabilities, new product launches requiring instrumentation, desire for A/B testing at scale, moving towards a more data-driven culture, interest in predictive analytics.
How healthy do they think the relationship is? Have they enjoyed their interactions with us (Sales, Support, CS)?
V. Stakeholders and power users:
For key contacts:
Name & role / title:
Priorities & Goals:
Attending any trade shows/events where PostHog might be?
Preferred Communication Channel / Cadence:
VI. Current PostHog products in use:
This can be easily checked in Vitally. Thinking through this in a structured fashion may be helpful when taking on a new account.
Asses the usage or maturity level for each product: Basic (simple insights), Intermediate (custom events, funnels), Advanced (correlation analysis, complex flags)
A. Underutilized products & cross-sell mapping:
In Vitally, you can often easily identify which products are underutilized or not adopted. It may be beneficial to map these out in a more general sense.
Product 1 (e.g., surveys):
Potential use case: "Gather qualitative feedback on new feature X." "Run NPS surveys directly in-app."
Next step to introduce/drive adoption: "Share case study on Surveys." "Offer to help set up their first survey."
Relevant case study / content:
Product 2 (e.g., A/B testing):
Potential use case: "Test different onboarding flows." "Optimize CTA button placement."
Next step to introduce/drive adoption: "Discuss their experimentation roadmap." "Show demo of A/B testing setup."
Relevant case study / content:
B. Optimization opportunities (for existing products):
"Not using custom events enough; could help them track X more granularly." "Could benefit from more complex funnels to understand Y." "Haven't explored correlation analysis for Z." "Feature flags could be used for targeted rollouts to segment A."
VII. Context / suggestions from others at PostHog:
Check Active Conversations in Vitally, support ticketing, Slack channels, CRM history.
VIII. Open requests and feedback
Has the customer submitted any feature requests or other relevant feedback?
IX. Risks:
Aware of any risks to this account's renewal or growth? Champion leaving, key user turnover, budget cuts, low adoption/engagement, unresolved issues, evolving needs, upcoming renewal date with low perceived value, negative sentiment.
This is a high level overview of where leads and customer accounts go at different stages of their interactions with us. We use various criteria to figure out where the best place is for a customer to go. You find further details in this section of the handbook.
As we grow, this will keep changing!
flowchart TB
A@{ label: "<b>New business leads<br></b>- Booked a demo (organic, paid ads)<br>- Emailed sales@<br>- Used >50% startup credits + invoice >$5k<br>- 'Cool company' in ocean.io<br>- Using PostHog, $0 spend, trigger for hiring increase, web/social increase, fundraise" } --> C["TECHNICAL ACCOUNT EXECUTIVE"]
B["<b>Expansion leads</b><br>-MRR $500-1,667, > 50 employees, > 7 users, ICP country, paying > 3 months<br>- High ICP score + Scale plan<br>- Off startup plan in next 2 months + last invoice >$1500<br>- >$1k MRR + >50% change"] --> D["TECHNICAL ACCOUNT MANAGER"]
n1["<b>Manual leads</b><br>- Anyone can create - use your discretion"] --> C
n2@{ label: "<b>Onboarding leads<br></b>- First bill of $100 + business email<br>- Not otherwise a lead" } --> n8["ONBOARDING SPECIALIST"]
C --> n4["$20k+ potential? (TAE decides)"]
n4 -- No --> n3["SELF SERVE"]
n4 -- Yes --> n5["Close then nurture for 12 months"]
n5 --> n7["Using replay + flags + error tracking AND expanded to full potential? (Simon decides)"]
n7 -- No --> D
n7 -- Yes --> n6["CUSTOMER SUCCESS MANAGER"]
n8 --> n9["$20k+ potential? (Onboarding/BDR decides)"]
n9 -- Yes --> C
n9 -- No --> n3
n3 -- "Organic growth to<br>$2k+ MRR" --> n14["Account review<br>(Simon decides)"]
n14 -- "TAM criteria met" --> D
n14 -- "Not yet" --> n3
D --> n10["Expanded to full potential? (TAM proposes, Simon signs off)"]
n10 -- Yes --> n6
n11["BDR"] --> n9
n3 -- "Some become..." --> B
n12["<b>Manual leads</b><br>- Anyone can create - use your discretion"] --> D
n6 -- If drops <$20k --> n3
A@{ shape: rounded}
B@{ shape: rounded}
n1@{ shape: rounded}
n2@{ shape: rounded}
n8@{ shape: rect}
n4@{ shape: diam}
n3@{ shape: rect}
n5@{ shape: rounded}
n7@{ shape: diam}
n6@{ shape: rect}
n9@{ shape: diam}
n10@{ shape: diam}
n11@{ shape: rect}
n12@{ shape: rounded}
As Vitally connects all of our Product, Stripe, Zendesk and HubSpot data together it's the best place to trigger automations via Playbooks. These Playbooks can call a webhook after Accounts or Users meet certain criteria. This allows us to call out to Zapier to use their inbuilt actions to update Zendesk, HubSpot, Slack and more. We use Zapier extensively throughout the company for automation. There is a shared Zapier login in 1Password.
Connecting everything together
Vitally requires a consistent external_id to be present to link everything together. For Accounts, we use the posthog_organization_id and for Users it's their email.
Vitally Segmentation
Vitally uses Playbooks to put Accounts and Users into Segments, which are useful for reporting as well as targeting of Playbooks. We have the following Segmentation Playbooks defined:
Segment Name: $60K ARR
Playbook Link
Criteria
Account not in Startups Segment
ARR >= $60K
Segment Name: $20K ARR
Playbook Link
Criteria
Account not in Startups Segment
ARR >= $20K AND ARR < $60K
Segment Name: Startup Plan
Playbook Link
Used to track companies either on PostHog for Startups or the YC Program
Criteria
Stripe Account Balance < 0 (e.g. they have credit remaining)
Stripe Credit Expires at > 0 days from today (e.g. it hasn't expired yet)
Stripe Is Startup Plan Metadata is not false or null (e.g. they haven't been marked as being on a paid annual plan)
Segment Name: Annual Plan
Playbook Link
Criteria
Stripe Subscription interval is yearly
OR
Stripe Account Balance < 0 (e.g. they have credit remaining)
Stripe Credit Expires at > 0 days from today (e.g. it hasn't expired yet)
Stripe Is Startup Plan Metadata is false or null (e.g. they haven't been marked as being on the startup plan)
Segment Name: Active Trial
Playbook Link
Criteria
Free Trial Until is greater than 0 days from now (comes from the Billing Postgres connection)
Segment Name: First payment forecasted this month
Playbook Link
Criteria
Lifetime Value (LTV) is 0 (e.g. they have never paid us)
Stripe current period end is greater than 0 days from now
Forecasted MRR > $1
Vitally -> Zendesk/HubSpot Automation
As Vitally has Subscription/Segment information it's the best place to drive Zendesk tagging and other activities.
Ensuring that Vitally Accounts have corresponding Zendesk Organization and HubSpot Companies associated with them
The New Orgs to Zendesk and HubSpot via Zapier playbook triggers on Accounts where there is _no associated Zendesk ID_ but there _is a Stripe Customer email_, so that we can look up the contact and company information in HubSpot. When these criteria are matched the playbook sends the following traits to a webhook which triggers the Vitally Webhook to New Zendesk Org and HubSpot Zap:
orgName - PostHog Organization Name
orgID - PostHog Organization ID
customerID - Billing Customer ID
email - Stripe Email
siteURL - the URL of the PostHog Cloud they're on (useful to have in Zendesk)
The Zap then:
Tries to find a HubSpot contact matching the email
If successful, looks up the associated HubSpot Company
Sets the posthog_organization_id property in HubSpot so that Vitally will be able to link to the Company
Creates a Zendesk Organization with the following properties:
name - Billing Customer ID - PostHog Organiation Name (e.g. 12345 - PostHog) which guarantees uniqueness
external_id - PostHog Organization ID
ph_external_id_org - PostHog Organization ID custom field (because external_id cannot be used in triggers and automations)
domain - The domain name from the HubSpot Company Object (which might not exist - see below)
There are some scenarios (e.g. gmail signups) where HubSpot doesn't have an associated company record and as such there won't be a domain to supply to Zendesk. In this case the automation completes but also adds the Email and Zendesk org information to the Zendesk Orgs Without a Domain table. For each row there are two buttons:
Add Domain to Org - Will fire a Zap to extract the company name from the email and set it on the Zendesk Organization. Use this one if it's clearly the right company domain.
Add User to Org - Will fire a Zap which adds that individual user to the Zendesk Organization. Use this if it's a webmail provider (e.g. gmail) as we don't everyone with a @gmail.com email creating tickets for this Organization, but do want this user to get the right level of support for their Organization.
Tagging Zendesk Organizations based on Segment and Subscription information
As Vitally is the best source of truth for Active Subscription / Payment information which informs our Zendesk ticket prioritization, there are a number of Vitally playbooks which will trigger the webhook associated with the Vitally Webhook to Zendesk Tags Zap, passing along the following traits:
zendesk_id - The Zendesk Organization ID (internal, not external_id)
playbook name - The tags to set on the Zendesk Organization
The Zap then updates the specific Zendesk Organization with the requested tags.
Zendesk Tag: priority_customer
Playbook Link
Criteria
Account is PostHog
Account not in Startup Plan Segment
ARR >= $20K
Zendesk Org ID is set
Zendesk Tag: paying_customer
Playbook Link
Criteria
Account not in Startup Plan Segment
ARR > 0 and < $20K
Zendesk Org ID is set
Zendesk Tag: non_paying
Playbook Link
Criteria
Account is not PostHog
Account not in Startup Plan or Active Trial Segments
ARR = 0
Zendesk Org ID is set
Zendesk Tag: churned
Playbook Link
Criteria
Account is not PostHog
Account not in Active Trial Segment
Stripe Subscription Status is Cancelled
Zendesk Org ID is set
Zendesk Tag: startup_plan
Playbook Link
Criteria
Account in Startup Plan Segment
Zendesk Org ID is set
Zendesk Tag: trial
Playbook Link
Criteria
Account in Active Trial Segment
Zendesk Org ID is set
Setting the correct organization in Zendesk for new tickets
Zendesk uses the requester's email domain to associate the ticket and the requester with an organization in Zendesk. To mitigate the problems this causes, we have a Zap named Set user's correct organization ID which:
Checks each new ticket for a value in the custom ticket field organization_id. (This ID is added to each support ticket submitted via our Help sidebar Email an engineer form, and community questions.)
Looks for a Zendesk org with an external_id which matches the value of the custom ticket field organization_id
If no match is found, the Zap stops and does nothing
If a match is found, the Zap sets the user's Zendesk organization accordingly, and then sets an org-checked tag to prevent the Zap from running repeatedly on the same ticket.
[Deprecated] HubSpot and Zendesk tagging
The Zaps in this folder have been mostly turned off in favour of the Vitally automations above, however there are some which are still enabled as we need to figure out how to handle them via Vitally.
Billing trial activated event -> HubSpot and Zendesk
_This needs to be moved to Vitally_
This Zap is triggered when a trial is activated in the Billing UI (triggered by the Billing trial activated action).
Looks up the associated email in Clearbit
Continues only if there is an associated Company in the Clearbit payload
Calls the Update tags on Zendesk org Sub Zap to create/update a Zendesk org with the Name and Domain from Clearbit and Organization ID as the Zendesk External ID (so that it will link the Zendesk org to the Vitally Account)
Finds the Company by name in HubSpot
Sets the Organization ID and Trial end date in HubSpot.
Creates an engagement (Task) in HubSpot for Simon reminding him of the trial end date.
HubSpot Automation
There are three zaps in this folder which create follow-on deals when any hands-on pipeline deal is closed:
They're triggered by a deal closing in the respective pipeline. It figures out the new deal close date based on the term in the existing deal (1,2,3 years) and then creates a new deal in the renewal pipeline, with amounts and ownership copied over too.
Sales Pipeline Events to PostHog
This folder contains Zaps which ensure we are tracking pipeline updates as PostHog events, so that we can model our sales pipeline as a funnel.
Calendly Event Scheduled to PostHog
This Zap is triggered when a new event is created via Calendly, this:
Looks up the PostHog Distinct ID via the email address of the person
Captures a calendly.event_scheduled event in PostHog with either the Distinct ID above or email address as the Distinct ID if there wasn't a match.
HubSpot Deal Stage Changes to PostHog
This Zap is triggered when a deal stage is updated in HubSpot, this:
Transforms the HubSpot ID of the Pipeline and Stage to the names via lookup tables and only carries on if matches are found
Gets the Deal Contact and Owner information
Captures a <pipeline-name> <stage-name> event in PostHog with the Contact email as the Distinct ID
Annual Plan Automation
To ensure consistency in the setup of annual plans we have Zapier Automation to take care of all of the Stripe-related object setup.
If the Customer has an existing record in Stripe (e.g. they are already subscribed to PostHog) then copy their Customer ID (starts cus_) from Stripe to the _Stripe Customer ID_ column. If they don't have an existing Customer in Stripe then click the _Create Stripe Customer_ button in the table to trigger a Zap to create one. The Zap also automatically adds the ID to the table.
Create Invoice
Once you click the Create Invoice button this Zap will create a Stripe Invoice in draft format. The following table fields need to be populated for this to work so check them before clicking the button:
Start Date
Term (months)
Credit Amount
Price
Once it's completed it'll populate the table with the Invoice ID and Link. Review this in Stripe, and when you are ready send the Invoice to the customer.
Note: You need to send the invoice to the customer before you apply the credit below. If you apply the credit whilst the Invoice is in a draft state it'll just pay the invoice with the credit, which defeats the purpose
Apply Stripe Credit / Zendesk Tags
Here you can click _Apply Credit_ to trigger a Zap which applies the Stripe Credit and Zendesk tags using the corresponding Sub Zaps. It will apply the priority_customer tag if the price is above $20k, and paying_customer otherwise.
Schedule Subscription
If the customer doesn't already have a running monthly subscription this Zap will create one with the desired configuration of paid products. Select the products you want to include and then click the Schedule Subscription button. It'll create a Subscription which is either Scheduled if the Start Date is in the future, or live if it is in the past.
Remember to update the Subscription in the Billing Admin Portal
Note: It has the current default Stripe Price IDs hardcoded in the Zap so if we update those we need to remember to update them in this Zap too.
YC Program
This process is documented on the YC Onboarding page.
PostHog for Startups
_Work in progress_
Sub-Zaps
These are used in a few different places to ensure we do things in a consistent manner. It also ensures repetitive tasks are easy to update if needed.
[Deprecated] Update tags on Zendesk org
_Mostly deprecated as we use Vitally for this now_
This Zap ensures that a Zendesk org is created and tagged correctly
Accepts the following inputs:
Company name (required)
Domain (required)
Tags
Organization ID
Instance
Startup plan or Trial ends at
Formats tags and startup/trial ends at in case of missing data
Formats startup/trial end in YYYY-MM-DD
Creates or Updates an organization with the information above
Apply Stripe Credit
This Zap applies credit and associated metadata to a Stripe Customer object
Accepts the following inputs:
Duration (e.g. 1 year or 6 months)
Stripe Customer ID
Amount (dollars)
Description (optional)
Credit start date
Is startup credit
Calculates the credit end date from the Start Date + Duration
Converts Dollars to Cents (for Stripe)
Adds the credit balance via the Stripe API
Updates the following metadata on the Customer Object:
This section explains how PostHog's billing system works. Most billing operations described below are handled exclusively by the and are not self serve. Sales should coordinate with the billing team for any billing modifications, pricing changes, or technical billing tasks rather than attempting to implement these directly.
All PostHog instances talk to a common external Billing Service. This service is the single point for managing billing across PostHog Cloud US, PostHog Cloud EU (and ,formerly, self-hosted customers).
The Billing Service is the source of truth for product information, what plans are offered on those products (eg a free vs a paid plan on Session Replay), and feature entitlements on those plans. Our payment provider Stripe is the source of truth for customer information, invoices, and payments. The billing service communicates with Stripe to pull all the relevant information together before responding to customer requests.
Credit-based Plan Automation
To ensure consistency in the setup of credit-based plans we have Zapier Automation to take care of all of the Stripe-related object setup.
Loading contract details
Once an Order Form is closed in PandaDoc, Zapier will add a new row to the Credit-based Plan Table with the PandaDoc ID of the document. The table will have the following information automatically filled in: PandaDoc Order Form, Company Name, Customer Email, Credit Amount, Discount, Price, Start Date, Term, PostHog Org ID.
Upfront Payment Setup
Step 1: Update Zapier table with existing Stripe ID
If this is a new contract for an existing customer, you will need to add their existing Stripe Customer ID manually to the table. You can find this information in Vitally under Traits. If this is a brand new customer, click “Create Stripe Customer” button to assign them a new ID.
Create a draft Invoice object against the Stripe Customer Object.
Add the ID of the Invoice to the table (for easy review later on). The due date of the invoice will be the Contract Start Date + 30 days which are our standard payment terms. You might need to manually change this if we have different terms with the customer.
Step 3: Verify invoice details and send
Click the invoice link in the table to open it in Stripe, or use the Invoice ID to locate the invoice in Stripe.
Ensure all details are correct, particularly the Customer’s Billing/Shipping addresses and Tax ID on the Customer object.
If the customer has an existing credit balance in Stripe (common for renewals), remove the credit before sending the invoice. Otherwise, Stripe will automatically apply the credit balance to the invoice. After the invoice is sent, you can reapply the credit.
Send the invoice to the customer and wait for the payment to be completed. Ensure that the customer is aware that payment is via Bank Transfer only (no checks).
Do not proceed to the next steps until invoice is finalized. Any credits added to an account gets automatically applied to outstanding invoices. If you add credits before payment is completed, the credits will settle any existing debts, and customer will not be able to make a payment.
For customers using Bill.com for payment, when they submit the invoice to the Bill platform it strips out the Stripe virtual account details. You'll need to ask them to follow the instructions in this help article to set the correct bank details for us in the Bill.com platform. The account details is provided in the invoice sent over. They'll need to make sure they use the original contact information and not your email if you're set as signer on the contract so we can process payments in the right account. In case they don't do this, we have a default customer account on Stripe which the money will go to. If this happens, mark their invoice as paid manually and then generate a new one against our default customer account to use the funds.
How do I know if a customer is using Bill.com for payment? You should try and get ahead of this by asking your customer whether they use Bill.com or ask to be connected to their finance team if unsure. Bill.com invoice notifications are sent to sales@posthog.com from account-services@inform.bill.com. The sales Google group archives them, so you can search the archive directly for subject lines like "Acme Inc sent you a payment" or "A payment from Acme Inc should arrive shortly". Note any that match accounts in your book.
Step 4: Apply credits
Make sure that the payment is fully processed to avoid any automatic deductions.
If customer wishes to begin using credits immediately: return to the Zapier table after you’ve verified payment completion and click the "Apply Credit" button.
If customer wishes to begin using credits in the next billing cycle: ask the RevOps team to apply the credits at the end of the current billing cycle.
Step 5: Schedule subscription
If the client has an existing subscription, no further action is needed.
If this is a brand new account:
Select checkboxes for all the products the client intends to use as part of their subscription.
Click the "Schedule Subscription" button. Using the data from the table row where the button was clicked, this will:
Consolidate all of the Price IDs into a query string which the Stripe API accepts.
Create a Subscription Schedule (as it may start in the future) containing all of the prices. We calculate the number of iterations based on the term of the contract. An iteration in this case is 1 year, the maximum allowed by Stripe.
Add the ID of the Subscription Schedule to the table
Failed/late payments
We define late payments as follows:
For credit-based customers, that have not made payment on an invoice and their due date has passed. The first invoice is usually 30 days from the contract start date (Net 30) although can differ based on other contractual terms. This rule applies to all payment terms, including and not limited to annual and quarterly, regardless whether there are still credits available or not.
For pay-as-you-go usage-based customers, we will attempt 4 automated payments using the card we have on file. Each failed payment sends an alert to the #sales-alerts Slack channel. After 4 failed payments we will stop attempting to take further payments.
In either of the above scenarios the account owner as defined in Vitally needs to take action to ensure that payment is made. If there is no owner in Vitally, Simon will handle this process. If you are an AE, remember this also has impact on your commission, as we don't pay out until the customer has paid their invoice.
You can find a list of failed and overdue payments in PostHog
Step 1 - On the day their payment becomes late
As the account owner you will be assigned a risk indicator in Vitally, as well as being tagged in an alert in #sales-alerts. For unmanaged accounts with a failed payment of $1500 or more Simon and Dana are tagged instead.
You should reach out to any known contacts, as well as any finance email addresses we have in Stripe asking for payment to be made immediately. For credit-based customers, you can download the Invoice PDF from the Stripe invoice page, and for monthly customers you can get the payment link from the Stripe invoice page. To get a payment update link, click on the subscription, then click actions in the top right corner and choose share payment update link. Make it easy for them to make payment by including these details in your email.
Make it clear in this outreach that if we don't receive payment in the next 7 calendar days, their user access will be suspended. If they come back to you with genuine reasons why they need more time, use your discretion with the next steps.
Step 2 - 1 day before suspending user access
Reach out to all active users on the account, and let them know that access will be suspended tomorrow due to the failed payment. This often creates urgency and will get any late payment resolved.
Step 3 - Suspending user access
To prevent users from being able to log in you need to go to the Django admin panel for their organization, then set the "Active" field to "No", with the reason selected from the dropdown: "Access revoked due to an unpaid balance." Then, hit save.
After completing this, email or Slack all users in the organization letting them know that access has been suspended and what they can do to rectify the situation. Also make it clear that if this isn't resolved within the next 7 days we will revert them back to the Free tier and they be subjected to the usage limits of that tier (e.g. they are likely to lose tracking data).
If they do pay after this point make sure to re-enable user access by reversing the above in Django admin.
Step 4 - 1 day before cancelling their subscription
Reach out to all contacts letting them know that due to the failed payment we will be terminating their subscription tomorrow.
Make it clear in this outreach that once the subscription is terminated they will be subject to the free tier usage limits and we won't store any data above that limit.
Step 5 - Cancelling their subscription
You can cancel their subscription in Stripe - navigate to their Stripe customer page, and then click the ... next to their active subscription to find the Cancel option.
At this point they will be notified about this automatically via the billing service.
Repeated failed payments
A customer has repeated failed payments when payments have failed across three or more consecutive billing periods, or when a second late payment occurs within six months of a previous one that reached Step 3 (suspended access).
At this point, catching up on the overdue balance isn't enough. We need payment predictability before restoring access, otherwise we're back here next month.
Step 1: collect the overdue balance. Access stays suspended until the outstanding invoice is paid. Send the payment link and the invoice PDF from the Stripe invoice page.
Step 2: require a contract pre-commitment before restoring access. Move the customer off pay-as-you-go onto a contract with payment upfront. The account's sales contact can size the commitment with the customer to base it on their trailing usage and what's realistic for them.
Make it explicit in your outreach that if we can't agree a pre-commitment, the account will be downgraded to the Free tier and subject to that tier's usage limits.
Step 3: set a drop dead date. Once the overdue invoice is paid, give the customer a specific calendar date roughly 4 weeks out to get the contract signed or move to Free. Put the date in writing. If it passes with no commitment, downgrade.
Restoring access before the contract is signed is a judgement call for the account owner, but set and communicate the drop-dead date at the same time.
RevOps will follow the routine upfront payment setup so the invoice is sent, credits are applied and the subscription is scheduled correctly.
India-based customers
GST: India-based customers are required to provide their GSTIN when signing up. The customer is liable to manage all GST under the Reverse Charge Mechanism.
3DS payment failures: Indian banks require 3DS (one time password) for international card payments. The customer is responsible for completing the 3DS step (our billing system sends a couple of reminders) without which the payment will fail.
Withholding taxes
PostHog Inc is a US incorporated company and a US tax resident and we do not claim benefits under any Double Taxation Avoidance Agreements (DTAA). To support this, we provide:
Our Tax Residency Certificate
Our no PE (Permanent Establishment) Certificate
These documents are available in the shared Finance drive. You can share them with the customer on request.
The full invoice amount is due. Any tax withheld is exclusive of the invoice, which will be treated as outstanding.
Stripe Products & Prices
⚠️ Product and price modifications are restricted and handled exclusively by the . These changes are only made in rare cases and require billing team approval and implementation. Do not attempt to modify products or prices directly - contact the billing team for any pricing-related requests.
Each of our billable Products has an entry in Stripe with each Product having multiple Prices. We use a billing config file to determine what is shown in the UI and how billing should behave. We use very limited metadata on some of these prices to allow the Billing Service to appropriately load and offer products to the instances:
Image: Stripe products
Custom metadata
On Stripe Products
posthog_product_key: posthog_analytics | session_replay | ... -> This allows PostHog to find and map the relevant products. Important: There should never be more than 1 Stripe product with the same posthog_product_key. The list of keys is defined in the main billing config.
On Stripe Product Prices The following keys are used to manage Startup prices:
plan - Any Startup plan prices must have the plan metadata set to startup to have their subscription automatically moved to the default (paid) prices. If not, when their subscription ends they will instead be switched to the free plans for all products.
valid_days -> The number of days a price is valid for, before automatically switching to another plan (the default plan unless move_to_price_id is set). Useful to create pricing that is only valid for a specific period, e.g. for the startup plans. Note: if more than one price with valid_days is added to a subscription, the validity period will be the shortest of the two, before resetting all plans to the default ones
move_to_price_id -> Can be used to specify if the customer needs to be moved to a specific pricing, rather than the default one, at the end of the subscription period.
Working with pricing
Each Product has multiple prices that can be used in a subscription. Which price is default depends on the billing config file. The default price in Stripe does not affect the actual default price for a product. This is instead defined in the billing config. In general, if coming from the UI, a customer will subscribe to certain prices depending on the config. There are special prices named Free which can be used to give a product for free. These can be added manually and are typically used for Enterprisey customers who pay a flat fee up-front and $0 for the actual usage (which we still want to track but not charge for).
Types of billing plans we support
We generally support the following types of billing plans:
Standard metered
This includes usage-based and metered, even if it has custom price tiers or is a special program like the Startup program.
Metered, but with discount coupon
Flat first tier, metered after
Up-front payment, $0 first tier, metered after
Flat up-front, no metering (renegotiate contract if they go over)
If at all possible, it's best to stay with these types of billing plans because we already support them, and adding extra stuff will increase complexity. If you do need to add a different type of billing plan, chat with the before agreeing to anything with a customer to make sure it's possible!
Coupons and Discounts
As much as possible the existing prices should be used in combination with Coupons to offer custom deals to customers. Coupons are applied to the _Customer_ in Stripe, not to the customer's subscription.
Visit the customer in the Stripe dashboard.
Select Actions -> Apply Coupon.
Select the coupon to apply.
The UI should soon reflect the change. If you need it to reflect immediately, use the "Sync selected customers with Stripe" action in Django Admin.
When calculating usage limits, discounts are taken into consideration _before_ the limit is calculated. This means that if the customer sets a billing limit of $200 and has a 20% discount, they will get charged $200 for _$250 worth of volume_.
Creating new or bespoke prices
Go to the appropriate product in question (do not create your own Product)
Click "Add another price"
Important: For metered products (e.g. Product Analytics, Session Replay), set up the price as follows:
Select Recurring, Usage-based, Per tier, and Graduated.
Image: image
Under Advanced, set the "Metered usage charge method" to Most recent usage value during period. This is crucial as the Billing Service will send the correct number of units (events, recordings, etc) every day, so any errors that caused excess usage to be reported can self-heal with the next reporting cycle.
Image: image
Expand the additional options and add a straightforward Price Description like Custom - {date of creation}
Add the tiers as you see fit
If the custom prices are for a product and addons (eg. Product analytics and Group analytics) the tier volumes need to be exactly the same between the two products/prices. If tier 3 for Product analytics is up to 15M and tier 3 for Group analytics is for 16M, you'll get errors from the billing service).
If you are making a custom price for just one product (ie. someone is getting special pricing for Product Analytics but will get the normal pricing for Group Analytics), make sure the tiers match up between the main product and the addons.
Add custom metadata if needed.
Plans
⚠️ Plan modifications are handled exclusively by the . Do not attempt to modify plans directly, contact the billing team for any plan related requests.
You can find a list of available plans in the billing repo. These are found inside costants/plans, divided by folder. Each plan can have a list of features, and a price. Features are used to infer which features are available in the product, for a customer on that plan. You can manually change the plan for a customer by updating the plans_map in the billing admin panel.
Paid features for employee side projects
Employees can get access to paid features (like Boost) on personal or side projects. Ask in #team-billing with your organization ID and someone can set this up. There are two approaches for platform packages:
Special billing-only plan: Add a plan like boost-addon-20250602 to the customer's plans_map in the billing admin. These plans exist only in the billing system and grant features without a Stripe subscription.
Long trial: Create a trial that does not auto-convert with a long expires_at date. This works well for temporary access or when you want a clear end date.
Side projects on a long trial meet the same spend caps as a prospect on Replay Vision, Desktop, PostHog AI, and Inbox. They reach them quickly. To lift them, add the organization to the billing-trial-expanded-free-allocation feature flag in PostHog. It is an organization group flag, so target it on organization.$group_key with the organization ID. That gives the side project ten times each product's free allocation instead of twice it.
The flag only changes what a trial lends where the customer set no limit. If the side project has a spend limit of its own, that limit still governs, so clear it first.
Updating subscriptions
Stripe subscriptions can be modified relatively freely for example if moving to a custom pricing plan.
Image: Stripe subscription update
Look up the customer on [Stripe dashboard][stripe_dashboard] using their email address or Stripe ID (this can be found in the Billing Service admin under Customers).
Click on the customer's current subscription.
Click on _Update subscription_.
Remove the old item from the pricing table and add the new item.
Enterprise: Use existing enterprise prices or create new ones.
Startup plan: Use existing Startup plan prices.
Click on _Update subscription_. Do not schedule the update for a later time. There will be unintended side effects if the changes are not applied immediately.
Do not prorate the subscription.
The changes should be reflected for the user within a few minutes.
NOTE: Removing a metered product price (events, recordings) and adding a new price will likely reset the usage. This is fine as the Billing Service will update it during the next sync.
Self-hosted differences
Self-hosted billing is no longer supported except for legacy customers who were using the paid kubernetes deployment.
Billing for data pipelines
For information about data pipeline pricing and billing, please visit our pricing page.
Communication templates for new feature adoption (TAMs)
Marketing drives awareness at scale. TAMs help customers get value in their own projects. This page gives a simple plan to turn new launches into real outcomes for specific customers.
Audience: Named accounts and real people, not a marketing list
Goal: First use of new feature and proof of value, not clicks or reach
Tone: Consultative, specific to their setup
Channel: Slack if shared
Cadence
Before new feature launch: internal heads-up TAMs get notified early about a launch. Understand why it matters, what it does, and who benefits. Write a few short notes for target accounts.
Launch day Marketing sends the announcement.
After the marketing launch: personal nudge Send a short note right after the marketing announcement to build on the awareness. The TAM message should tie the feature to the customer’s stated goal and give one clear action they can do now in their own PostHog project.
Example
“Last quarter you set a goal to reduce activation drop-off. We just shipped [new feature]. You can turn it on in your project and try it on your onboarding flow. I recorded a 30-second Loom in a demo project: {loom_link}. If helpful, here is the direct link: {project_link}.”
A week or two after launch: data-triggered follow-up Look at usage in their project. Follow up based on what happened.
Adoption detected
“Looks like [new feature] is on in your project. Is it moving {goal metric}? If you have notes, I will pass them to the product team.”
No adoption
“Was thinking about your goal to achieve [goal metric] and how [new feature] might help with that. So I wanted to send a nudge in case it fell off the list. You can switch it on here: {project_link}.”
Next QBR after launch Bring the feature as a solution to the overall strategy, not a simple list of new features to go through. “Given your target to improve {goal}, we can be more relevant with these improvements: [selected new items].”
Realistic examples
Experiments → no-code experiments “You said you want to lift {goal}. No-code experiments lets PMs ship A/B tests without engineering. Turn it on here: {project_link}. Start with {page_or_flow} where we saw friction. Check {metric} in this view: {report_link}. Short Loom with the steps: {loom_link}.” See: no-code web experiments and getting started with experiments.
Feature flags → quick holdout “You’re planning to roll out {feature_or_copy_change} to improve {goal}. Keep a {holdout_percent}% holdout on the flag so you can see real lift before full rollout. Flag settings: {project_link}. First results show here: {report_link}.” See: feature flags and holdout testing tutorial.
Session replay paired with an insight “We saw a drop-off at {step_or_page}, which blocks {goal}. Create this funnel {event_sequence} and open replays linked to step {step_number}. Start here: {report_link}. This pairs the number with the clips so you can see why.” See: session replay.
Workflows “Follow-ups after {event} are manual today, so {goal} slips. Turn on a workflow that triggers on {event_or_property} and sends {message_or_action}. Enable here: {project_link}. First run appears here: {report_link}. Adjust, then expand.” See: workflows – start here.
AI Observability “You’re aiming to increase {success_rate_metric} for {ai_feature} and keep {cost_metric} in check. Turn on AI Observability: {project_link}. Watch prompts, responses, success rate, and cost per {n} prompts. First view to check: {report_link}.” See: AI Observability – start here.
Heatmaps “People hesitate on {page}, which hurts {goal}. Open heatmaps: {project_link}. Compare {version_or_date_range} to see what changed. First view: {report_link}. Use this to pick the next tweak.” See: heatmaps.
Potential measurement
Feature adoption rate in the targeted accounts
Time to first use from the launch-day note
Built-in product surveys
Some areas collect feedback in product. Watch for those notifications from your accounts.
Potential user segmentation for message adjustment in the future
Power users and beta candidates “You are a heavy user of {area}. [New thing] is ready. You can turn it on here: {project_link}. If you want a head start, I can share a tiny checklist.”
Flag users without experiments “You already ship behind flags. Add a small holdout on the next release so you can prove lift before rollout. Here is the page in your project: {project_link}.”
Single-product users with nearby needs “You use {current module} to hit {goal}. {Adjacent module} helps with the next step. Short Loom with setup: {loom_link}. Direct link in your project: {project_link}.”
Adoption laggards on the core path “Checking in on [new feature]. You can enable it here: {project_link}. If it is not a focus right now, all good.”
High-traffic, low-conversion areas “{page or step} has volume and a drop-off. Try [new feature] here first. I can share a minimal setup so you see a signal this week.”
Automation ideas
We should use Vitally and data from their PostHog instance to get automated account recommendations for which accounts would benefit from which new features the most.
When a PostHog customer raises a new round of funding, gets acquired, or goes public, it’s a major moment for their team. Our goal is to celebrate the milestone in a way that’s genuine, brief, and human, not transactional or opportunistic. We avoid product pitches, feature plugs, or follow-up asks in the initial message.
1\. Communication principles
Keep it human, not salesy The first message should feel like a note from one person to another—not a brand announcement. Congratulate them sincerely, acknowledge their achievement, and stop there.
Example: “Massive congrats on the Series C\! I imagine this is a huge moment for you and the team — hope you’re all taking time to celebrate.”
Timing matters
Day-of: Congratulatory message (no CTA).
\~3–4 weeks later: Follow-up that references specifics from the company’s press release, interviews, or roadmap to open a thoughtful, relevant conversation.
Personal \> Personalized We avoid template-like phrasing. If we can’t find something personal to say about the customer or their journey, it’s better to say less.
Channels
Slack (preferred, if shared).
Email (if Slack unavailable).
Optionally LinkedIn comment/like from company handle (but no DM from AE unless relationship exists).
2\. Follow-up framework (3–4 weeks later)
Use their own public statements as the hook. Reference their goals, product direction, or challenges expressed in press coverage or announcements, and connect them meaningfully to where PostHog can help.
Structure:
Open by referencing their recent announcement and one or two specifics (quote, metric, or goal).
Briefly connect that to how PostHog can support those goals.
Ask a question or offer to share something relevant (not a demo or pitch deck).
Example: “Hey — congrats again on the Series B\! I read about Heidi’s plans to scale your AI work globally and tackle latency head‑on. We’ve been working on similar challenges at PostHog around speed and reliability for teams deploying AI at scale. Let’s talk about what’s worked for other customers in keeping things fast and cost‑efficient as usage grows — when’s a good time to connect?”
3\. Key takeaways
Don’t sell in the moment. Celebrate authentically.
Follow up with relevance. Use their words, not ours, to frame the value.
Keep the tone human, concise, and professional.
When in doubt: err on the side of sincerity over specificity.
When things go wrong, our priority is simple: keep customers informed, quickly and clearly.
This section covers how we communicate during service disruptions, from small hiccups to major outages. We aim to be transparent, human, and proactive — sharing what we know (and what we don't) in plain English.
PostHog customers rely on us to power their products, so we provide honest, timely updates through the right channels — usually Slack or email, and occasionally SMS for high‑touch accounts.
Core principles
1\. Transparency \> Perfection
Share what we know, when we know it, clearly and without “status-speak.”
2\. Human-centric
Messages come from people, not “The PostHog Team.” Show empathy and ownership (“I know this might interrupt your work; here’s what we’re doing.”)
3\. Consistency
Use a consistent structure and timing so customers know what to expect.
4\. Proactive by default
Reach out before customers ask, even if it’s just to say, “We’re aware and investigating.”
Severity levels
| Level | Description | Examples | Channels | Cadence | | ----- | ----- | ----- | ----- | ----- | | SEV 0 – Emergency | Existential service failure; all or most customers impacted with no workaround. CMOC sends immediately via broadcast. Account owners do not gate comms. | Full platform outage, data loss, security breach with active customer impact. | Slack message → Email → DM/SMS | Immediate broadcast, then every 15–30 min; postmortem within 24h | | SEV 1 – Critical | Major outage or data loss; widespread impact. | API unavailable, ingestion halted, login failures. | Slack → Email → (DM or SMS if needed) | Every 30–60 min; postmortem within 48h | | SEV 2 – Major | Partial degradation or downtime; workaround available. | Replay or query delays \>30 min, flag evaluation slow. | Slack or Email | Every 1–2 hrs | | SEV 3 – Minor | Limited impact or slow recovery. | Billing sync delays, isolated org issues. | Slack | Start and close | | SEV 4 – Informational / Planned | Maintenance or recovered incidents. | DB upgrade, scaling events. | Email or Slack broadcast | Before \+ after window |
Templates
Emergency (SEV 0)
This overrides the standard workflow. CMOC sends directly to all affected Slack customer channels without waiting for account owners. Account owners follow up individually once online.
Initial message (Slack):
We're investigating a major incident affecting [feature/service]. [Symptom — e.g., "Event ingestion is fully stopped" or "The PostHog app is unreachable."]
Our engineering team is actively working on a fix. We'll post updates here every 15–30 minutes until this is resolved.
Update template:
Update on [feature/service]: [Status — e.g., "Root cause identified. Fix is being deployed." or "Still investigating. No ETA yet, but narrowing it down."]
Next update in ~[15/30] minutes.
Resolution template:
[Feature/service] is back online as of [time UTC].
Root cause: [one-line summary]. Duration: [start–end]. Impact: [brief description of what customers experienced].
We're monitoring closely. A full postmortem will follow within 24 hours.
If you experienced data gaps or have concerns about impact to your project, reply here and your account owner will follow up directly.
Critical
Subject: PostHog Outage – We’re investigating
Hey \[Name/Team\],
We’re investigating a major outage affecting \[feature\]. You may see \[symptom\]. Engineers are on it — updates every 30 minutes until resolved.
We know this may disrupt your work — thanks for your patience while we get things back online.
— \[Your Name\], PostHog
Follow-Up (Resolution): Good news — the issue is resolved. Root cause: \[summary\]. Duration: \[start–end\]. Impact: \[brief effect\].
We’re monitoring and will share a full write-up within 48 hours.
Major
Subject: Performance issues in \[Feature\]
Hey \[Name\],
We’re seeing performance issues in \[component\]. You might notice \[impact\]. We’re mitigating and will update within the hour.
Thanks for your patience\! — \[Your Name\], PostHog
Minor
Subject: Slower performance in \\\[area\\\]
FYI — This shouldn’t block you, but we’re monitoring closely. I’ll update once it’s stable.
Planned maintenance
Subject: Maintenance – \[Service/Region\]
Heads up — maintenance on \[system\] from \[time window\]. No downtime expected, but queries or replays may be briefly delayed. We’ll confirm once complete.
Tone and voice
| Principle | Example | Avoid | | :---- | :---- | :---- | | Direct | “Event ingestion is paused.” | “We are experiencing an issue affecting a subset of users.” | | Empathetic | “I know this blocks work; it’s our top priority.” | “We apologize for the inconvenience.” | | Plain English | “Dashboards might not update.” | “You may experience degraded query latency.” | | Ownership | “We identified a config issue on our side.” | “A third-party dependency caused an issue.” |
Coordination within GTM
Engineering manages detection and resolution (see engineering incident handbook). GTM ensures clear, consistent customer updates, without duplication or coverage gaps.
Goals
Keep a single source of truth for comms, managed by the CMOC.
Maintain global coverage so customers always hear from us.
Enable fast, clear handoffs between teams.
Roles & responsibilities
| Role | Responsibility | | :---- | :---- | | Communications Manager On-Call (CMOC) | Activated for any incident requiring GTM notification. Drafts all comms using handbook templates. Coordinates with engineering for context and keeps a central log of who’s been notified. Manages regional handoffs if incidents span time zones or owners are offline. | | AM/AE/CSM | Sends comms to their accounts using CMOC drafts. If offline (PTO, off-hours, or time zone), CMOC assigns a regional backup. | | Regional Backup (Americas / EMEA / APAC) | Covers accounts when owners are offline. Takes handoff from CMOC, sends comms, and ensures follow-up continuity. | | Engineering Incident Lead | Owns technical response and provides updates to CMOC for accurate messaging. |
All coordination between CMOC and Account Owners should happen in #group-cs-sales-support transparently so that everyone who manages customers is in the loop.
Workflow
SEV 0 override: For SEV 0 incidents, the CMOC skips steps 4–5 and sends the initial message directly via Slack to all affected customer channels. Account owners are notified in #group-cs-sales-support simultaneously, and take over individual follow-up threads once online. The CMOC continues to own broadcast updates until the incident is resolved or downgraded.
Incident declared (Engineering).
CMOC activated, notified of impact.
Assess customer impact, this insight (or this Google Sheet as a backup) will help you understand which customers are using which components in which cloud environment.
CMOC drafts message and shares with the Account Owner (the person responsible for the affected accounts).
Account Owner sends the message to their customers. Example outbound: “We’re investigating an outage affecting event ingestion. Updates every 30 minutes.”
During: “Root cause identified (Redis queue saturation). Fix in progress.”
Resolution: “Resolved at 11:42 UTC. Write-up soon.”
We've put together suggested communications templates that TAMs can draw on for various situations like startup plan roll off, incidents, churn risk increase, or new feature rollouts.
These templates are not meant to be restrictive, but a general idea of how we communicate with customers.
We are transparent about how we contract with customers, including what discounts are available. It's better for them, and better for us. We are allergic to the phrase 'let me talk to my manager and see what we can do' - we follow a principled approach.
Discounts
We don't offer discounts to customers paying monthly, irrespective of commitment.
Although our standard monthly pricing has volume discounts built in, it's common practice when negotiating software contracts for the customer (and their procurement team) to ask for a discount. We follow the 4 discount levers framework, being transparent about what drives our discounting:
The discount levers & why they matter to us
Our general principle is that discounts are earned, not given. Each lever represents real benefit to both parties:
Volume: The amount of credits purchased. Larger deals have economies of scale. Our cost to serve a $500k customer is not 10x a $50k customer, so we can share those savings
Timing of Cash: When we receive payment. Money today is worth more than money tomorrow. Cash in hand lets us invest in product, hire engineers, and grow the business faster
Ability to Forecast: Mutual agreement to timing. When both parties commit to specific dates (contract close, renewal timing), it helps us plan resources and helps customers secure budget
We don't use the framework's fourth lever, length of commitment - see contract term length below.
How our discounts work
In our consumption-based pricing model, the first way for a customer to reduce spend is to ensure that they are only sending data to us which is valuable to them. There is different guidance here depending on which product(s) they are looking at.
Beyond optimization, we offer discounts based on three levers:
1. Volume discount (based on credit purchase amount per contract year - Customers must qualify for this discount before receiving discounts 2 and 3)
$25-59k: 20% base discount
$60-99k: 25% base discount
$100-249k: 30% base discount
$250-499k: 35% base discount
$500-999k: 40% base discount
$1M+: Contact us for custom pricing
Two things to be clear on when working out which tier applies:
- It's credit value, not cash. The tier is set by the amount of credit the customer receives (the pre-discount, list-price value), not the amount they pay us after discounts.
- It's per contract year, not per term. On a multi-year deal, use the credit allocated for a single contract year. A 2-year deal with $250k of credit a year sits in the $250-499k tier at 35%, not the $500-999k tier at 40% — the reward for paying for more of the term upfront is the timing of cash lever below, not a bigger volume tier.
2. Timing of cash discount (additive)
Net 30 (our standard): No additional discount
Multi-year deals: +2.5% per additional year paid upfront (+2.5% for 2 years, +5% for 3 years. capped at +5%)
Extended payment terms: -2.5% for every 15 days beyond Net 30 (e.g., Net 60 = -5% from total discount)
Note: We require upfront payment for all discounted contracts. Quarterly or split payment terms are not available as they impact our cash flow and add administrative overhead. If the full projected amount exceeds budget, customers can purchase fewer credits upfront at the corresponding discount tier and then add more later.
3. Ability to forecast - mutual commitment to timing (additive)
For monthly-to-annual conversions & net new agreements: +5% additional, non-recurring discount
Available when both parties commit to specific, mutually agreed date for contract signature (this is not an end-of-quarter discount)
To include the 5% discount on the order form, we require written confirmation by the customer's designated signatory of the customer's intent to sign an order form by a specific, mutually agreed upon date - _this needs to come from the person who will actually sign the order form_
This is about creating predictability for both sides, not artificial deadlines
This is a one-time discount, which will be offered once during a monthly-to-annual conversion or net new agreement cycle
Not available while the customer can claim a further partner-program credit grant (for example, a renewed YC deal grant) during the proposed contract term. This discount buys a firm conversion date, and a customer with another free grant on the way has no single conversion moment for us to secure. Once the customer is no longer eligible to claim the grant again, they count as ordinary net new and the discount is available.
Doesn't stack with the startup plan roll-off offer — a converting customer gets one conversion incentive, not both.
For renewals: +5% additional discount
Early renewal commitment. Available in the last 6 months of the contract term and 60+ days before it expires. For a standard 12-month term that means months 7-10, up to 60 days out.
Eligibility is measured against the current term's natural end date, not against when the customer's credits happen to run out. A customer who consumes credits early can top up or start a new term early, but that doesn't move the window.
Eligibility is judged at signature. The customer must still be on prepaid credits when they sign. If credits ran out first and they've already rolled onto pay-as-you-go, the +5% doesn't apply, because that's a re-entry into a credit plan rather than an early renewal. A customer who signs inside the window and then runs out before the new term starts keeps the discount.
This discount applies to the full credit purchase on the order form. On a multi-year renewal the +5% applies to the whole term's credits. This is deliberate: an early, fully prepaid, multi-year renewal is the best deal we offer.
If timelines change: We will handle these on a case by case basis, but the default is to withdraw the additional discount if the customer does not sign an order form by the time that was originally agreed.
You shouldn't offer discounts above the levels outlined here. If you go outside of these rules without clearing it with Ben Bradley (TAEs or TAMs) or Simon Fisher (CSMs), you should assume by default that the deal will not count toward your quota.
Contract term length
Our standard contract term is 12 months. Terms of up to 36 months are available on request, either invoiced annually or paid upfront. A multi-year term invoiced annually prices the same as consecutive 1-year terms, while extra years paid upfront earn the timing of cash discount above. We reward the prepayment rather than the signature because cash in hand is a stronger commitment than a promise to pay later.
We cap terms at 36 months because our products and pricing evolve quickly: a contract that outlives the pricing model it was signed under can create confusion and manual work for both sides, and since credits are dollar-denominated, a long lock may imply less certainty than it appears.
Customers wanting a better rate can buy more credits (lever 1), pay for more of the term upfront (lever 2), or commit to a mutual timeline (lever 3).
One-off credits
One-off free credits appear on order forms in three cases: contract buyouts, new business renewal credits (competitor win-backs), and startup plan roll-offs. We don't generally add free credits to close a deal, bridge a coverage gap, or substitute for a discount the levers don't provide. A one-off credit is a larger discount wearing a disguise, and it breaks the transparency the levers exist to protect.
Why we require up-front payment for credit purchases
We've found that split payment terms create friction for both teams – customers chasing internal approvals, us chasing invoices, nobody focused on delivering value. When customers pay quarterly or monthly, they often consume credits faster than they pay for them, effectively turning us into a line of credit. We are vendors, not lenders. Our focus is on building the best product, not managing accounts receivable. Up-front payments keep everyone focused on customer success and let us invest cash immediately into building features and support. If a customer needs payment flexibility, we're happy to adjust the credit amount and discount, per guidelines above, to fit their budget while maintaining up-front payment.
Credit for case studies
We don't offer additional discounts in exchange for a case study, as paying for case studies can devalue them. We should be working to get our customers to a state of happiness such that they are willing to tell everyone how great PostHog is without needing to pay for it.
Self-serve discounts
We also offer a way for customers to receive discounts on their usage without talking to sales or being on an Enterprise plan. In PostHog, if a customer meets certain criteria, they will see a banner on their billing page with a call-to-action (CTA) to "buy credits". The form they fill out will be auto-populated with an estimated number of credits based on their last 3 months of usage, but they can adjust this value as needed. They will have the option to pay with the card on file or to receive an invoice. Credits will be applied to their account once the invoice is paid.
Requirements for self-serve discounts:
3 or more paid invoices
Average of $280 or more across the last three invoices
No open invoices
Not currently on the up plan, a legacy plan, or having existing credits
Additional notes on self-serve discounts:
For credit purchases below $25,000, the discount is 10% off. Credit purchases of $25,000 and above follow the standard volume discount structure above.
Instead of providing all credits upfront, we apply 1/12 of the credits each month for the next 12 months. These credits do not expire for 1 year after they've been applied.
If a customer uses all credits in a month, they will be billed for extra usage at the standard rate.
Non-profit discounts
We offer additional discounts to non-profits:
For credit purchases below $25k: 15% discount (instead of standard 10% self-serve or no discount)
For credit purchases $25k - $100k: An additional 5% on top of standard volume discount
For credit purchases above $100k: Standard volume discounts apply (no additional non-profit discount)
We use tax law in the country of origin to determine what is a not for profit entity. If a customer can provide proof they fit their country's definition, the discount is applicable subject to the guidance above.
When evaluating a discount, it’s important to review our margin calculations to ensure we remain margin positive, especially for larger accounts.
Non-profit discounts only provide an additional 5% on top of standard volume discounts, and only for credit purchases between $25,000 and $100,000.
Legacy discounts
You might see some customers with a 30% discount on their monthly Stripe subscription. These were added when the only way we billed for PostHog was through event pricing. This was originally designed to offset the cost versus competitors who had unbundled Group Analytics or Data Pipelines. These customers will typically be on a higher per-event price plan, so we should look to get them migrated to standard pricing as soon as possible.
Startup plan discounts
For customers on our startup plan, we offer two months free credit when signing a prepaid deal. This encourages startups to use their credits to understand usage, and then commit to a longer term plan with PostHog. This offer is available until the first billing date after the credits expire. If a customer has used up their credits before the expiration date, they still have until the original expiration date to decide and claim the offer. The amount of free credits is determined by how much they purchase on a prepaid plan. By default, we work with customers on prepaid plans that will cover their usage for the next 12 months.
The offer bridges a single expiry cliff: the startup credits expire once, and the free months reward committing to a prepaid plan before they do. It's therefore not available while the customer can claim a further partner-program credit grant (for example, a renewed YC deal grant) during the proposed contract term — with another grant on the way there is no cliff to bridge, and the incentive buys nothing. Once the customer is no longer eligible to claim a grant again, they qualify like any other roll-off. This offer also doesn't stack with the +5% forecast discount for conversions above — a converting customer gets one conversion incentive, not both.
Important clarification: operationally this is implemented as free credits applied before the contract start date, not as extra credits inside the contract term unless a specific dollar amount for the free credits is explicitly included under Special Terms.
You should follow the same inbound sales process and work with the customer on understanding and optimizing their usage. Then follow these additional steps take to present the prepaid plan + free credits option(s):
Review the customer's average monthly cost
Estimate the prepaid equivalent for 12 months of coverage (e.g. [monthly cost x 12])
Inform them they can take advantage of this offer, which allows them to:
purchase credits equivalent to ~12 months of usage (expiring 12 months after the contract start date), and
receive ~2 months of additional usage for free, applied before the contract start date.
If the customer wants to purchase fewer credits than the option above, then they will receive an additional 1/6 of the amount they wish to purchase for free.
All free credits associated with startup plan roll-offs are one-time only, and should be denoted in the special terms of the contract as "An additional credit in the amount of XXXXX (offered to customers in exchange for rolling off the Startup plan) to be applied to Customer's account upon signature with the same expiration date."
For contracting purposes, these free credits should either be applied before the contract term or included in the 12 month credit amount. If they are being applied before the contract term, adjust the contract date to start 2 months later and the one-time credits can be applied to cover the 2 invoices before the contract start date. In this case, the credits do not need to be called out in the contract, and the opportunity owner can add these credits as a one time credit in billing admin.
How to structure free credits in special terms
There are three ways we structure free credits, and it's important to be clear which one applies, because they're added at different times and treated differently at contract start:
Fixed amount included in the 12 month term. The free credits are part of the contract term and are added to the customer's balance alongside the purchased (prepaid) credits at contract start. Use this when a specific dollar amount of free credit is explicitly called out under Special Terms as part of the term.
Coverage for a specific number of months. The free credits are not part of the contract term. We add enough free credits to cover the promised period (for example, up to the contract start date), top up if the customer comes up short before then, and add the prepaid credits only when the contract actually starts. Any free-credit balance still remaining at contract start is removed at that point. These credits can be added via billing admin as a one time credit and don't need to be called out as part of the term.
Fixed amount included in an extended term (contract buyouts). The free credits are part of the contract term, but the term itself is longer than standard because it absorbs the buyout period: 12 months of paid usage plus a 6 month buyout becomes an 18 month term. Use this whenever we're buying a customer out of a competitor contract. See contract buyouts for how to build the order form. Note that this means you won't be able to top up free credits if customer uses them faster than originally planned. If you think this may be the case, default to option 2.
Margin negative deals
In exceptional circumstances, we may explore providing additional discounts which eat into our operating margin for the following cases:
They are a strategic logo we'd like to land as a brand-new customer.
We are taking their business from a competitor.
We are preventing them from churning to a competitor.
For the avoidance of doubt, these types of deals are very rare (~1 per year), and not offered to customers with standard usage volumes.
If you believe you have a customer who falls into one of these categories and would like to provide additional credit/discount then in the first instance run through the opportunity details including margin calculation with your manager, who will then clear it with Simon (CSMs) or Ben (TAEs/TAMs).
Additional credit purchase
It's often difficult to right-size the credit needed for a longer term plan, so customers can buy additional credit in the first half of a contract term (e.g. 6 months for an annual plan). See when they don't have enough credit to cover their term for how those purchases are priced. Within the first 6 months given our billing usage reports we should be able to predict whether the customer is going to run out of credit or not. There are also alerts set up in #sales-alerts to help notify account owners about this.
Price guarantees & lock-ins
We do not offer price guarantees for the following reasons:
We sometimes lower prices, which would result in higher costs for customers who've locked in a price
We occasionally split or restructure products (e.g. Data Pipelines unbundled), which makes guarantees administratively complex
Customers are in full control of their usage and can thus adjust their spending patterns as needed
This request most often comes from procurement teams unfamiliar with our pricing philosophy. Address it proactively in commercial discussions, but if there is push back, reference the above points. As an example:
"We've dropped Events pricing [X]% over [timeframe]. A price guarantee would have cost you more. We're committed to matching the cheapest at every scale—if we're not, tell us. Our prepaid credits for usage based pricing gives budget control without betting against our commitment to low prices."
Multi-year credit allocation
Paid up-front
We will allocate all the credit purchased to the Stripe account when the contract is signed. As above, they can purchase additional credit in the first half of the contract term and take advantage of the same discount as specified in the original contract.
Paid yearly
We will allocate the credit for that year to the Stripe account when the contract is signed, and then again when subsequent annual invoices are raised.
If a customer wishes to use subsequent year's credit early they must agree to pay the invoice for that year early before the credit is transferred.
The additional credit purchase applies to each year separately, e.g. they can purchase additional credits at the same discount level in the first 6 months of each year.
You can see a signed multi-year contract set up in this way by navigating to Documents -> Examples (folder) inside of PandaDoc.
Uptime SLA
Customers only get an uptime SLA if:
They have subscribed to the Enterprise package; or
You agree it with them as a special term as part of their contract if they are spending $100k+ ARR _post_ discount (i.e. $ spend, not credit usage).
An uptime SLA are not available to customers outside of these cases. You should certainly not agree to an SLA for customers on regular monthly contracts, and even for annual contracts it is not a given - it's one of multiple pieces you may have in play as you negotiate terms (much like a case study).
More details on how exactly the uptime SLA works can be found in our terms.
Payment method
For customers paying monthly, we only accept credit card payments, which will be taken automatically via Stripe at the end of their monthly billing period.
For customers purchasing credits upfront, we only take bank transfers because:
For large payment amounts, the fees we incur are higher for credit card payments.
Our Sales Ops automations are set up to handle bank transfer payments.
You should confirm ahead of the customer signing the order form that they are happy and set up to pay by bank transfer. If they are absolutely unable to accommodate bank transfer we can accept credit card payments under the following conditions:
We have a card on file which we can immediately charge for the full invoice amount.
They pay immediately on signature, not on the contract start date (i.e. no Net 30).
The order form says so. The default order form template keeps our standard Net 30 bank transfer terms, so you must change them on the document you generate from it (never on the template itself) to Payment Terms: Net 1 from Signature Date and Payment Method: Bank Transfer or Credit Card. If the order form still says Net 30, the customer can hold us to Net 30, whatever we agreed in conversation.
If your customer must pay via credit card, you absolutely _need_ to let RevOps team know ahead of the order form being signed as there is a lot of manual work needed up front to make this work.
We absolutely do not allow payment by check. This is made clear on order forms.
Contract buyouts
Are you a potential customer who wants to speak to us about a contract buyout? Get in touch with the Sales team via your shared Slack channel, or reach out directly.
Sometimes customers will be locked into a contract with a competitor, but want to switch to PostHog when their contract is up. In this case, we are willing to give them free PostHog credits for up to 6 months of their total PostHog contract value. This is beneficial to PostHog as well, as we can get them set up and using PostHog sooner, capitalizing on the momentum of their interest today, and giving them more time or resources to get comfortable with the platform.
The guiding principle: The buyout amount needs to make financial sense
When considering a contract buyout, the goal is for PostHog to pay a little up front to make more money over a long-term customer relationship. It doesn't make sense to buy out a contract for $60k if the customer is only planning on spending $20k annually with PostHog.
Some rules:
They need to share a copy of their current contract/pricing/bank statement as proof.
They sign up to an annual contract worth $20k+/year, paid up front.
Their usage in the overlap period needs to be proportionate to the contract they've signed with PostHog, ie. if they sign a $50k PostHog contract and have 6 months to run, they get $25k of PostHog credit for free.
The competitor they're using has to be 'real', ie. not some random side project. As a general rule, anyone we have written a comparison article about counts.
Any buyout is subject to team lead approval before it goes on an order form.
We have final discretion on deciding who gets the deal.
We can still provide a standard free trial period of 2-4 weeks before they sign the contract, as they will likely need to figure out whether PostHog is right for them before committing.
Normal commission rules apply here - commission is paid in the quarter in which the customer pays their invoice.
How to structure a buyout on the order form
Buyouts used to get papered in one of two ways: future-dating the order form so the term began when the incumbent contract expired, or sprinkling extra free credits onto an otherwise normal order. Both cost us — the first is effectively extended payment terms and delays when the deal counts, the second cuts order value hard enough to flirt with margin negative. Neither is how we do it now.
Instead, fold the buyout period into the contract term:
Contract term = standard term + buyout period. A 12 month deal with a 6 month buyout is an 18 month term. A 2 year deal with a 6 month buyout is a 30 month term.
Credits are calculated as usual — 12 months of estimated usage, multiplied by the number of years — and then the pro-rated buyout credit is added on top.
Exclude the buyout credits when calculating the discount we offer the customer. The buyout credit is not a lever for a bigger discount.
Show the contracted discount on the order form, not the effective discount. The effective discount (total paid ÷ total credit) will always look larger than the contracted one because of the free buyout credit. Quoting the effective number sets a false floor for the renewal.
Everything else is standard — term start date, payment terms, and signature dates all follow our normal rules. There is no future-dating and no separate payment schedule.
Call out the buyout credit in Special Terms: _"In consideration of Customer migrating to PostHog from its incumbent provider prior to the expiration of Customer's existing agreement with that provider, PostHog will provide a one-time credit in the amount of $NNNNN."_
As a worked example: a customer expected to use ~$100k of credit a year, with 6 months left on their incumbent contract, at a 30% discount. They buy $100k of credit for $70k, we add $50k of buyout credit on top, and the order form is an 18 month term for $150k of total credit at a 30% discount. The effective discount lands north of 50%, which is expected and stays off the order form.
If a customer is currently _not_ a paying user of PostHog, but is a user of one of our competitors, about to renew, and is shopping for a better deal, we are willing to significantly undercut the quoted renewal price. This is because those customers are not that likely to move over to us anyway, and quoting them a lower price works out in our favour either way:
If the competitor matches our much lower offer, and the customer accepts, we've reduced their revenue by a significant amount
If the customer accepts, we've gained net new revenue we otherwise would have missed out on, and we have the opportunity to sell more.
In order for this to not mess up later renewals, the way we do this is by giving them credit for the first year in order to reach a total discount of 40%. For example, if the quote from the competitor is $50k, and the total cost for our product (including other discounts) is $40k, we will give them additional credits worth $10k, in order to undercut the total quote by 40%.
In order to qualify for this, the customer needs to send us the full quote document from the competitor.
Contracts for customers on time-limited plans
Some customers are on a plan that is cheaper than list pricing and has an end date — a campaign coupon (Lenny's Newsletter grants a free Scale package and 2x free tier limits for 12 months), a beta plan for a product we haven't finished pricing, or a promotional increase to their free tier. These customers are paying us today, and they will pay more for the same usage once the plan ends.
This covers pricing packages granted in Billing, not the Stripe coupons and discounts we apply per contract (legacy 30% off, non-profit discounts, and so on). This is also not the same situation as the startup plan. Startup credits make usage free, which is why we future-date that contract to sit after the free period.
Don't touch the plan to close the deal
Don't extend, swap, or cancel a customer's coupon or beta plan as a negotiating lever, or promise to carry its benefits into the contract term. Campaign benefits expire automatically and move the customer onto the standard paid plan with nobody doing anything. Every manual exception replaces that with a bespoke plan configuration plus something a human has to remember to undo months later, which is how we end up with legacy plans we then spend months migrating people off.
Because the plan may end partway through the term, credits burn at one rate before that date and a faster rate after it. Sizing on today's spend may undersize the deal.
If the plan has a known end date you can blend the two rates:
(months remaining on the plan × current monthly run rate) + (remaining months of the term × post-plan monthly run rate)
Apply your usual growth assumption to both halves. The post-plan run rate is their current spend plus whatever the plan is currently absorbing: the list price of any free add-on, and the usage that currently falls inside an inflated free tier.
If the plan has no fixed end date (e.g. beta plans where we may change pricing at any time) don't guess. Size on current usage, tell the customer that pricing isn't final, and use the additional credit purchase provision to right-size once pricing changes.
Tell the customer about the step-up
Their costs rise on a known date whether or not they sign, so it belongs in the conversation. It's a reason to commit now, rather than something for them to discover at renewal. Sizing it properly often moves them into a better volume discount tier as well, which is a much better trade than giving away the plan benefits.
Credit over/under usage for contracts
Starting a new term early
Sometimes a customer's usage grows faster than the credits they bought, and they exhaust the term's credits with months left to run. They have two options.
Top up the current term. They buy additional credits that expire with the existing term on a new order form. Available in the first half of the term.
Start a new term. The current order form is replaced by a new term. The new purchase must be sized in good faith against the full new term: a credible forecast of usage across all 12 months, not a bridge to the next conversation. A customer expecting their usage to settle below its current peak can price against that, provided they're candid about the assumption.
Running out of credit early neither creates nor destroys eligibility for the early renewal discount, because eligibility is always measured against the term's natural end date. A top-up prices on the volume lever alone. A new term earns the +5% only if it's signed inside the normal early renewal window — in the last 6 months of the original term, 60+ days before its natural end date, and while the customer is still on prepaid credits. Burning through credits faster than planned doesn't open that window sooner.
When they don't have enough credit to cover their term
We have CreditBot alerts set up in #sales-alerts when a customer is going to run out of credit before their contract term ends, with the estimated runway remaining. The Vitally account owner (AE or CSM) will be tagged in this message. It's best to be proactive here so that the customer is right-sized well before the credit runs out:
If they run out of credit in the first half of the term, they can purchase additional credits that expire with the current term. Each purchase is priced independently — we don't add it to previous purchases to reach a higher discount tier. The customer gets whichever of these two is better for them:
The tier from their initial order form
The tier the additional purchase amount qualifies for by itself
Example: a customer buys $105k of credits (30% tier). Later they add $400k, which qualifies for 35% on its own (not treated as $505k). If the same customer adds $30k in credits, that qualifies for 20% on its own, which is lower than the original purchase tier, so they keep the original 30% rate from their initial order form.
If they will run out of credit in the second half of the 12 month contract term, they should sign a renewal order form. Signing 60+ days before the current term ends while still on prepaid credits qualifies for the early renewal discount. The renewal order form can start when the credits run out rather than waiting for the original end date.
If credits run out before a renewal order form is in effect, the account rolls onto our standard pay-as-you-go rates until the new term starts. We don't cover gap usage for free. CreditBot gives account owners months of runway warning, so a customer paying list price for a gap is a customer we failed to engage early.
When they will end the contract term with credit remaining
If a customer ends a term with unused credits and signs a renewal of equal or higher spend, we roll over part of their _remaining_ (unused) credits into the new term. The pre-paid plans doc is the source of truth for the exact amount and the customer-facing wording, so keep the mechanic there and link to it rather than restating it here (this is where these two pages had drifted).
We scale the rollover to _remaining_ credits rather than the original order form amount. For a customer who underused and renews at equal spend, rolling a share of the original on top of the renewal stacks up more credits than they were ever going to use, which rewards a mis-sized deal with a bigger pile and makes the account harder to expand later. Scaling to what they actually didn't use keeps the balance proportionate.
Where the underuse was outside the customer's control (a PostHog-side incident, a data issue on our side, or a documented disruption on theirs), we can roll over more than the standard amount, up to the full remaining balance, or extend the window to use existing credits. We handle these case by case based on what was logged at the time, so flag it early.
When a customer doesn't renew their credit purchase
When a customer chooses not to renew a prepaid credit contract we automatically remove any remaining credits on the expiry date. Their account will then roll onto our standard monthly plan and they'll be charged for usage. It's the customer's responsibility to stop sending us events or cancel their subscription and downgrade to the free tier if they don't want to keep paying.
Varying contractual terms
When we vary terms
If a customer wants to vary either our standard template DPA, BAA, or MSA terms, it is a substantial effort for our legal team to review these suggested changes (also known as "redlines").
At a minimum, we will only do this for contracts above $20k a year, and we should expect even higher amounts of committed revenue if they are asking for big changes (e.g. changing significant provisions, adding Service Level Agreements, etc.). A customer needs to either be spending this amount at present, or agree to commit to this spend via an annual contract, in order to initiate legal review of suggested changes. We evaluate all requested changes proportionally against their annual committed spend with PostHog. A customers annual committed spend needs to be defined before proceeding to a negotiation over legal terms, otherwise there is no frame of reference for the negotiation.
We also sometimes receive unsolicited requests to vary our terms. In these instances the legal team will redirect the customer to work with their PostHog contact person for this, as we will only review redlines for a managed customer or opportunity where the potential annual revenue is understood.
See the guidance below if the customer asks to use their own contract instead of ours
How customers should suggest requested terms
The customer should redline the current .docx version of the document in question. You can find the latest versions of the templates in the Legal Documents tab in the #group-cs-sales-support Slack channel, or here — MSA, DPA, NDA (do not save versions locally).
Never send a template from a local copy, a previous deal, or a forwarded thread. The templates are revised regularly and sometimes materially. Sending a stale template means negotiating from terms we no longer offer, and it's a lot of wasted legal time to unwind.
We don't accept redlines on our standard terms of service and if a customer has proposed this you should share the correct templates with them before involving legal.
Once they have returned the redlines to you first check to ensure that they have used the template which you provided, and then share the document for review in the #legal channel. There will usually be a few rounds of back and forth as we converge on an agreement. You will continue to represent PostHog's position to your customer throughout the negotiation. Please work with #legal on the appropriate responses and speak clearly to our customers.
What customers should expect
PostHog evaluates legal risk assumed against annual revenue received. In other words, contractual terms will be varied in proportion to the customer's committed annual spend with PostHog.
To illustrate with examples:
A customer committing to spend just $20k USD annually should not expect significant deviations from PostHog's standard terms. Minor, clarifying edits will be acceptable. We will not spend our time going back and forth for this amount. We may respond to significant changes with a polite, "no," rather than negotiating, to communicate clearly.
A customer committing to spend $80k USD annually would be able to request slightly more sigificant deviations from PostHog's standard terms, and we will evaluate the suggested terms through the lens of legal risk assumed against annual revenue received. This will be a negotiation, and we will represent PostHog's position clearly as we go along.
A customer committing to spend $160k USD annually (or more) would be able request even more sigificant deviations from PostHog's standard terms, and we will evaluate the suggested terms through the lens of legal risk assumed against annual revenue received. This will be a negotiation, and we will represent PostHog's position clearly as we go along.
At any potential level of annual spend, PostHog will not proceed under unreasonable legal terms. Certain suggested terms may be non-starters for PostHog.
Varying terms for trials and proofs of concept (POCs) for prospective customers
We don't vary PostHog's standard terms for trials and proofs of concepts (POCs) for prospective customers.
All prospective customers are welcome to try PostHog for free and under our standard terms (including our standard DPA and BAA, if applicable).
We don't negotiate terms for trials and POCs for three reasons:
Unlike many of our competitors, an annual subscription is not required to access PostHog, so a negotiated agreement is not necessary to use our services. Our product-led motion is designed to support customers trying PostHog.
Because prospective customers are paying us $0 for a free, sales-led trial or POC, there is no frame of reference for us to evaluate any potential custom terms. Spending our time and legal resources negotiating these terms is premature when a prospective customer doesn't know that they want to proceed with PostHog at all, much more at a qualifying level of annual usage.
Once the trial concludes, and per our guidance on varying terms, we will be happy to evaluate custom legal terms for an otherwise qualified PostHog customer.
Using non-PostHog contracts
If a customer requests to use a non-PostHog drafted contract for documents such as a DPA, MSA, Order Form, or BAA, we generally decline, except in special circumstances (see 'When we vary terms for customers'). We avoid doing this as it adds too much risk for us, and also because reviewing and negotiating non-standard terms introduces significant operational inefficiencies and doesn't scale well as we continue to grow. We typically do not even consider using customer paper unless the deal is over $200k annually or involves an extremely blue-chip company. It is best to manage this expectation early and just avoid entertaining the idea with customers as soon as possible.
We are somewhat more flexible when it comes to NDAs. That said, since we contract through our U.S. entity, we require customer NDAs to be governed by U.S. law. This is necessary to maintain consistency and ensure we’re not taking on legal or operational risk in jurisdictions where we don’t operate or fully understand the legal landscape. This is mainly about ensuring we can review and manage agreements efficiently with our limited legal resources.
For customers who want to sign up for an annual (or longer) plan there is some additional paperwork needed to capture their contractual commitment to a minimum term, and likely custom pricing as well. At a minimum, they should sign an Order Form which references our standard terms and privacy notice. In addition, they may want a custom Master Services Agreement (MSA) or Data Processing Agreement (DPA).
Multi-year deals and credit allocation
The credit term only extends beyond 12 months (e.g. to 24 months for a two-year deal) if the customer pays the full amount for the entire term upfront (e.g. the full two-year amount paid upfront). How the credits are allocated depends on how the customer pays:
Paying all upfront for the full term: the customer gets the full credit amount added in bulk at the start, with an expiry set to the full length of the term (e.g. a two-year expiry for a two-year deal paid upfront).
Paying per year (or in tranches): the extended term does not apply. Credits are granted in tranches allocated on each renewal date, each with a 12-month term. For example, a two-year deal split evenly grants half the credits in the first year and half on the renewal date at the start of the second.
Customers with organizations in more than one region
If the customer needs an organization in more than one region (for example the US cloud and the EU cloud), agree on the billing configuration before the order form goes out. Read customer billing configurations for the two options and their limits. If you keep the credits separate, write the credit split for each organization on the order form. For either option, get the organization ID for each region before contract setup.
What about monthly customers?
Anyone on a monthly plan simply agrees to our terms and privacy policy when they sign up.
QuoteHog pricing calculator
While we offer transparent pricing available to all, you can use QuoteHog for customers who need a "formal quote," or who have very high volumes, or otherwise have bespoke needs.
Sign into QuoteHog via your PostHog Google account/SSO. Upon login, you will see a list of existing quotes, sorted by the created date. You can view a previously created quote or create a new quote using the "New Quote" button at the top right.
The quoting interface is intuitive and, of course, uses the same pricing we display publicly. Feel free to involve a customer in creating a quote if the opportunity presents itself and you think it would build trust.
Be sure to always click the "Save" button after making changes to a quote. QuoteHog does not autosave.
Quotes can be shared externally or embedded in an external source. Clicking the Dot Menu from a Quote and click "Share". If someone asks for a PDF version of a quote, you can view the external version and print it to PDF.
QuoteHog also provides Stripe reported usage and spend for existing customers. To do this, you need to first connect QuoteHog to Salesforce from the profile page. As you build a quote, click "Add customer info" and search for your customer account. This also allows you to link the quote to an existing Salesforce opportunity.
When building a quote for an annual plan conversion or renewal, consider:
How is usage trending? Looking at the past 6 month's of usage (usage history tab in QuoteHog):
If usage is trending up, calculate the growth rate and project expected volume for a year.
If usage is stable, project based on the latest month's volume or the average or the maximum.
Note: QuoteHog's input expects monthly volume, so after estimating annual volume, don't forget to convert it to monthly volume.
Is there opportunity to adopt additional products? How does that affect future usage?
Is the customer on a plan that expires partway through the term? Campaigns, beta plans, and promotional free tier increases all suppress usage today and step up on a known date, so their current spend is not their post-plan spend. See contracts for customers on time-limited plans.
You can create quotes with multiple options: e.g. one based on current usage, one with a higher tier to account for growth potential.
The legacy pricing calculator is available here.
Order form
An order form is a lightweight document that captures the customer details, credit amount, discount, term, and signatures from both PostHog and the customer. They are either governed by our standard terms or a custom MSA (see below).
You will likely need to use QuoteHog to get the correct credit amount to be included in the order form.
Creating an order form
We use PandaDoc to handle document generation, routing and signature. Ask Mine Katsu or Simon Fisher for access if you don't have it.
The order form template to use is titled [Client.Company] PostHog Cloud Order Form - <MMM YYYY>
When looking at the template, click the link to Use this template in the top bar.
In the Add recipients box which pops up:
Replace <MM YYYY> with the month and year the contract starts (e.g. March 2023)
Add the Client email, first and last name
Add the PostHog Signer email - normally the team member who is responsible for the customer (AE or CSM).
Click continue
In the pricing table, set the total amount of credit in the Amount box next to PostHog Cloud Credit
Remove the Enterprise Plan line item if not needed.
At the bottom of the pricing table, set the Discount % just above the Total
On the right of the screen there is a sidebar, select the Variables tab and populate them as follows:
Client Address Information - Needs to be their legal correspondence address (check with your customer contact)
Client.Company - The legal company name
Contract.Discount - The discount % (appears in the Additional credit purchase section)
Startup credits - If the customer qualifies for the 2 free months when rolling off the startup plan, add up their total and discount as normal, and then add a note about the free credits in this format: "An additional credit in the amount of XXXXX (offered to customers in exchange for rolling off the Startup plan) to be applied to Customer's account upon signature with the same expiration date." For example, if a customer is signing a standard $20k annual contract to get the 20% discount, the total will be $25k, 20% discount of $5k, total cost to the customer would be $20k. In the notes, you would write: "An additional credit in the amount of USD $4,166.67 (offered to customers in exchange for rolling off the Startup plan) to be applied to Customer's account upon signature with the same expiration date."
Contract buyout credits - If the customer is buying out a competitor contract, add the buyout credit to the Special Terms in this format: "Customer will receive a one-time and additional PostHog Cloud Credit of $XX,YYY (the "Contract Buyout Credit") to be applied against monthly usage expiring on the Credit Allocation Date." Any buyout is subject to team lead approval before it goes on an order form.
Contract.EffectiveDate
Set the start date of the contract in the format DD MMM YYYY (e.g., 01 Feb 2023). For a new customer, this would be the date they choose to start their subscription. For an existing customer, we have two options:
Immediate Activation: If the customer wishes to start using the credits immediately, set the start date to the beginning of their current billing period. This backdating ensures that the credits are applied correctly to the current billing cycle.
Next Billing Cycle: If the customer prefers to begin their annual plan at the start of their next billing cycle, set the start date accordingly. This option aligns the contract start date with the upcoming billing period.
For example, let’s say it’s October 15 and you’re setting up an annual plan. You have a pay-as-you-go subscription that started on September 1, and the next billing date is November 1.
If a customer wants to start using credits immediately for the October cycle, your contract start date should be October 1.
If a customer wants to start using credits starting the next billing cycle, your contract start date should be November 1.
If you set the start date correctly, our Zapier automation flow will create the invoices with correct dates so our revenue calculations are not affected from the transition.
Do not backdate beyond the current billing period. You can only set the start date as far back as the beginning of the current, not-yet-invoiced billing period (Immediate Activation above). Never set it into a period we have already issued an invoice for. Doing so rewrites an issued invoice and breaks revenue recognition, which is not something we support.
Renewals: Salesforce auto-populates the renewal opportunity with the anniversary date (the day the previous term ends), but don't assume that's the correct Contract.EffectiveDate. The same rule applies as above: the start date must match the beginning of the billing period the new credits need to cover. If the customer has run out of credits on their existing plan and there's an open billing period the renewal credits should cover, backdate the start date to the beginning of that period — which may be up to a month before the anniversary date — so the new credits map to that invoice. Only start the renewal on the anniversary date itself if the customer's existing credits carry them cleanly through to it. If the order form won't be signed before that period's invoice is issued, don't hold the backdated start date. Move the start date to the beginning of the next billing period instead, and tell the customer the new credits apply from then. See contract timing rules below, and timing your renewals with billing for how to avoid getting into this position.
Note: Pay-as-you-go products are charged after the end of the period, while flat-rate subscriptions are charged at the beginning of the period. As a result the first two payments on a monthly schedule may occur within the same billing period as part of the transition. Make sure to send a note to the customer to ensure they're fully informed!
Startup credits - If the customer qualifies for the 2 free months set the start date of the contract for 2 months in the future, to account for the two free months ahead of the contract.
Campaigns and beta plans - Do not apply the startup rule above. These customers are already paying us — their plan makes usage cheaper, not free — so future-dating the term would leave them on undiscounted list pricing until it starts. Set the start date normally and size the credits for the point at which their plan expires instead. See contracts for customers on time-limited plans.
Contract.Term - The term in months of the contract (12 months by default)
If they are buying credits upfront but must pay by credit card, change:
Payment Terms to Net 1 from Signature Date.
Payment Method to Bank Transfer or Credit Card.
If an MSA is being used rather than the standard terms you will need to replace the following text:
PostHog Cloud License Terms appearing at: https://www.posthog.com/terms and Privacy Policy appearing at: https://posthog.com/privacy (collectively the “Agreement”)
with either
PostHog Master Services Agreement (Cloud License) entered into by and between the Parties on or about the date hereof and Privacy Policy appearing at: https://posthog.com/privacy (collectively the “Agreement”).
or, if the Customer insists on including the exact date of the MSA to remove ambiguity,
PostHog Master Services Agreement (Cloud License) entered into by and between the Parties on or about [INSERT DATE OF EXECUTION OF MSA] and Privacy Policy appearing at: https://posthog.com/privacy (collectively the “Agreement”).
You should link the order form to the opportunity record in Salesforce using the Contract Link field in the "Opportunity Closure Details" so that we have a reference to the completed paperwork from our CRM.
Routing an order form for review and signature
When viewing the order form, check the recipients tab in the sidebar. The Client and PostHog roles should be filled in.
A signing order should also be set, with the Client signing first (so they can review it before we sign).
Ensure Document forwarding and Signature forwarding are set to on so that our Contact can re-assign the document if needed.
Click Send at the top of the document and add a message explaining the context of the order form.
Once the Client and then PostHog have signed it you should get an email to confirm completion.
Don't forget to link to an opportunity in Salesforce and mark the associated opportunity as Closed Won.
We prefer to keep all signatures in PandaDoc, but sometimes clients may prefer to sign a PDF copy. One way to minimize this is to send contracts for initial review via PandaDoc when possible. It is ok to have multiple drafts in PandaDoc as long as we have the final signed copy in there as well. When a client signs an order form outside of PandaDoc, please follow these steps to complete the process:
If you have previously created a draft, find the document from the Documents page in PandaDoc (note: you cannot change the status from Home or inside a document).
Select "Change Status" from the three-dot menu on the right.
Upload the signed PDF of the document.
Mark the status as completed.
Check Audit Trail to make sure the signed version is uploaded correctly.
Link to an opportunity in Salesforce and close the associated opportunity as Closed Won.
If no draft exists, upload the signed document directly ad a new document in PandaDoc.
Mark the status as completed.
Link to an opportunity in Salesforce and close the associated opportunity as Closed Won.
Once you the signed form in PandaDoc is marked as complete and the Salesforce opportunity status is set to Closed Won, the RevOps team will get a notification and handle setting up the subscription and invoicing. See the Billing page for steps on how the billing setup works for more information.
Using prepaid credits to cover an existing pay-as-you-go invoice
When a pay as you go customer wants to sign a prepaid contract and use their new credits to cover an invoice that is about to be issued, timing is important. Credits can only be applied cleanly to an invoice _before_ that invoice is finalized.
Flag insufficient credits before the invoice is issued
Monthly invoices are generated automatically at the end of each billing period. As the account owner, if you know a customer intends to purchase more credits to cover their current usage, you should check before the invoice issue date whether they will have enough credits on the account to cover it.
Credits added before billing period ends are applied automatically and the customer never has to pay the PAYG charge out of pocket. No further action needed here.
If they won't have enough credits to cover an invoice and won't sign before the invoice issue date, ask the billing team to pause collection. Flag it as early as possible, because billing can only pause an invoice that hasn't been issued yet. A pause lasts 48 hours, and each invoice only gets one pause. Once the contract is signed and the credits are added, billing releases the invoice and the prepurchase credits cover it.
Contract timing rules
For newly purchased credits to cover the intended invoice automatically, both of these must be true:
Contract start date must match the first billing period the customer wants to cover. For an existing customer this usually means backdating the Contract.EffectiveDate to the start of the current billing period (see Immediate Activation above). If the start date doesn't line up with the period being covered, the credits won't map to that invoice.
Contract must be signed before the period_end date of the invoice they want to cover. If it's signed after the period closes and the invoice has been issued, the automated flow can no longer apply the credits.
You can only backdate to the start of the current, open billing period, never to a period that has already been invoiced.
Master Services Agreement (MSA)
Occasionally, customers will want to sign an MSA instead of referencing our terms in an order form.
Download a fresh copy of the PostHog Cloud MSA as a Word Document (legal teams prefer this format) and share it with your Customer contact. Download it from Drive every time — never reuse a copy saved locally or one from a previous deal, as the template is revised regularly.
They may want to propose changes (also known as 'redlines'). Work with Hector or Fraser to get these agreed.
Create a new document in PandaDoc, you can choose to either import from Google Drive or upload from your local machine. This should be the clean, non-redlined document as agreed by both parties.
Change the name to be PostHog Cloud MSA - CUSTOMER LEGAL NAME.
Add the Client and your name and PostHog email as roles.
Add a Signature, Name and Title field for both PostHog and the Customer.
Check the signing order (Client, then PostHog normally).
Send for signature - so long as any proposed changes have been reviewed and approved by Hector or Fraser, you are free to sign on behalf of PostHog
Sometimes large customers will ask for changes to our MSA. We have a list of the kinds of changes we will/won't consider in a private repo in the company-internal sales contract changes directory that you can generally agree to without the Ops team reviewing. However, if you are ever in doubt, ask in #legal in Slack
Business Associate Agreement (BAA)
We offer HIPAA Compliance on PostHog Cloud and as such health companies will require us to sign a Business Associate Agreement with them. As this means we take on increased financial risk in case of a breach we ask them as a minimum to subscribe to one of the platform packages which is a guaranteed monthly payment. A maximum of one BAA per organization will be signed. Under most circumstances, it should be the company that owns the org/pays us.
Ask the customer to subscribe to a platform package (as well as any other paid plans they wish to use).
Create a new document from the PandaDoc template.
All you need to do it set the Client.Company variable and then send it to them for review and signature.
It has been pre-signed by Fraser and will automatically add today's date as the date of signature for PostHog.
You'll get a notification when everybody has signed it - we have automation in place to ensure that the HIPAA BAA Signed Date property on the customer's Salesforce Account record is updated.
We only provide our default BAA for platform package subscribers - customization requires >$20k annual spend. The BAA only remains active for as long as the customer is subscribed to a platform package - if they unsubscribe, we send them a message that their BAA will become inactive at the end of the month in which they cancelled. Customers on a platform package trial are not eligible to sign a BAA. You'll need to convert their trial to a regular subscription first, before they can sign it. If the lead is not sure whether they will need a custom BAA and their usage wouldn't put them at $20k, then it is worth pushing them to get legal feedback by sending them our BAA before moving forward, else you risk spending a lot of time on an evaluation that ends up at $250/month.
Non-disclosure Agreement (NDA)
In some cases, prospective or current customers require a mutual Non-disclosure Agreement (MNDA) in place before conversastion or product activity can proceed. Terms already specify Confidentiality and if there is still a situation where a documented agreement is requested this can be easily accommodated.
Access PandaDoc and Create a New Document
Use the current PostHog - NDA template, which is kept in Google Drive — pull it fresh rather than reusing a copy from a previous deal
Add your desired contact as a recipient and follow the usual PandaDoc process
When document is complete, it will be stored in the Document library and can also be attached to the Salesforce account for future reference
Trust center approvals
Requests that originate from the Trust Center automatically get sent an NDA in the request from SafeBase to PandaDoc. Once the document is fully signed, access will automatically be granted.
We use Salesforce as our customer relationship management ('CRM') platform. If you need access, you can ask Mine Kansu for an invite.
As a first step, make sure you connect your Gmail account under your Salesforce settings. Go to Settings → Connected Accounts → Gmail and connect it. This ensures all your customer emails sync automatically with Salesforce. Next, make sure your Gmail account is connected in Vitally. This is essential so that we capture the full customer context and avoid duplicate or conflicting outreach.
As a general principle, we try to make sure as much customer communication as possible is captured in Salesforce rather than in individual email inboxes so that we make sure our users are getting a great experience (and not confusing or duplicate messages from different team members!). You should use the channel that suits the user, not us. Just make sure you keep Salesforce up to date with your interactions. We’ve found Slack messages usually get better response rates than email.
For existing customers, you'll sometimes send emails directly from Vitally. To ensure these also make it to Salesforce, first look up your _Email to Salesforce Address_ from the personal settings page in Salesforce, and then add it to your Vitally gmail settings.
All Slack messages sync up with the corresponding account in Salesforce. We use SupportHog for this sync, so make sure SupportHog is added to the customer Slack channel and the channel's name is recorded on the relevant Salesforce account record for the sync to work smoothly.
You are most likely to use the following regularly:
_Tasks_ A task represents a potential sales follow up or engagement. Every new inbound inquiry (via form or email) is now created as a task on an account and contact.
_Opportunities_ - An opportunity is a qualified lead that has been assessed and is considered a potential sales deal (with an estimated revenue and an expected close date). This is where we manage our customers through their buying cycle.
_Contacts_ - Contacts are individuals who use PostHog or contacts we interact with. You can create contacts manually or convert a Lead to a Contact after evaluating the lead and deciding to continue working with them.
_Accounts_ - You will also create an account record to associate with any contact. You can associate multiple contacts with a single account. If you enter the company's domain name, we have data enrichment in place to pull in additional data on the organization.
Salesforce offers a ton of resources if you want to dig deeper.
Managing our CRM
People currently come into Salesforce through one of the following ways:
Email inquiries: messages sent to sales@posthog.com
Website forms: when they complete a contact or demo request form on our website
Product sign ups: All signups are saved as a contact record in Salesforce
Manual Entry: When a team member manually adds a contact, such as meeting someone interested in PostHog at an event
New PostHog signups
When a user signed up (Cloud signup) event is ingested into PostHog, a data pipeline destination ("Salesforce create contact for signups") creates a contact record in Salesforce with Record Source set to product-signup. It maps the following Salesforce properties if they are set on the PostHog event or person:
role_at_organization - the role they self-selected when signing up (used in lead scoring)
is_organization_first_user - whether they have created a new organization or joined an existing one
The PostHog organization ID and name
Marketing opt-in, the signup URLs, and the PostHog distinct ID
Completed contact form
We have a contact us form on posthog.com where we ask users can get in touch with us. The sales@ alias gets an email notification and a notification is also sent to #sales-leads in Slack when one of these forms is submitted.
Each submission sends a server-side PostHog event and a webhook into our lead routing pipeline (Default). The lead-gateway then creates or updates the Salesforce contact, links it to the account, and creates a Lead Task. Tasks are then automatically assigned to the right team member based on account ownership and territory (see below).
If the submission is clearly a support or billing request, you don’t need to reach out manually:
On the task, select the disqualification reason Billing Support Request or Support Request.
This automatically creates a Zendesk ticket for the correct team.
No manual outreach is needed; automation handles it.
Leads from support tickets
If the support team spots a sales opportunity in a support ticket, they post it in #group-cs-sales-support for sales/CS to pick up (see handling sales leads). If you pick one up, add it to Salesforce as described in manual entry.
Forwarding sales opportunities
If you are not in the sales team but are engaged with a client and identify a sales opportunity, forward the email chain to sales@posthog.com. A new lead will be automatically created in salesforce and assigned to the appropriate AE based on existing criteria. This way we can smoothly hand off potential opportunities and track things properly!
Important: The email must be forwarded (not replied to), and sales@posthog.com must be in the "To:" field—not CC or BCC—for the automation to work correctly.
Task assignment logic
When a new task is created, we first check whether the associated account already has an owner:
If the account has an owner, task is automatically assigned to that person.
If the account is unowned, account and task are assigned to a salesperson via round robin within their territory.
This ensures we avoid double assignments and maintain clear ownership.
Territories
U.S. West
U.S. East
Europe & Africa
Asia & Middle East
Australia & New Zealand (ANZ)
Territory 1 (U.S. state unknown)
Territory 3 (Unknown, but otherwise qualified)
Each territory runs its own round robin assignment for new, unowned accounts.
Stale task reassignment
If a task is assigned to a someone but remains untouched for 10 days, it will be automatically reassigned once via round robin. If it remains untouched after reassignment, it will be automatically disqualified with the Stale – Autoclosed reason.
Converting tasks to opportunities
If a task represents a qualified opportunity:
Open the task and check the box labeled “Create new opportunity.”
Choose the appropriate Opportunity record type:
New Revenue for brand-new customers.
New Revenue – Existing Customer for upsells, cross-sells, or expansions.
Existing – Convert to Annual for pay as you go customers moving to an annual plan.
Renewal for existing annual customers renewing their plan.
This automatically creates and links the opportunity to the task.
You can then click the opportunity link to add deal details (value, close date, etc.)
Use the following criteria (loosely based on traditional BANT qualification) to determine when a task should be converted to an opportunity:
You've had at least one call with the customer to establish a relationship.
There's a clearly identified problem that PostHog can solve.
They have acknowledged that the problem is important enough to work on solving now.
You've had a rough pricing discussion, and confirmed that their budget is in the same ballpark.
The person you're in touch with is the decision maker, or has committed to introducing you to the decision maker.
You have an agreed next step which moves things forwards such as:
Signing up for a PostHog organization
Implementing PostHog
Getting an MNDA in place
Accepting a Slack Connect invite and asking questions in a Slack channel
Accepting a call invite with their boss/buying committee
All of the above criteria should be met before creating an opportunity. By doing so you drastically increase the odds of bringing them onboard as a successful customer.
If you aren't able to confidently say that you have covered the above, you should keep them as a Lead in the Nurturing stage.
Task disqualification reasons (reference)
When you disqualify a task, choose the picklist reason that best matches the situation. Salesforce groups reasons into categories; full definitions are on the field in Salesforce. This table is a quick map so the team uses the same buckets.
| Category | What it means | Reasons (picklist) | | --- | --- | --- | | Auto-Dispositioned | System closed the task or sent auto emails without hands-on sales triage. | Below Threshold – Auto; Stale – Autoclosed | | Re-route | Send the conversation to another PostHog team. | Support Request; Billing Support Request; Existing Customer Inquiry; Event Request; Partnership Request | | Not a Lead | Not a commercial sales opportunity for this path. | Spam; Duplicate Lead; Non-Commercial; Startup Plan / YC; Self-Hosted Requirement; Business Closed; Feedback; BAA / DPA Request | | Unreachable | You cannot reach them or they stopped responding; split by whether they are worth revisiting. | No Response – Pass; No Response – Prospect; Invalid Contact Info | | Fit | You could assess fit; outcome is ICP, product, technical sponsor, or competitive situation. | Below Sales Assist Threshold – Pass; Below Sales Assist Threshold – Prospect; Not a Good Fit; No Technical Resource; No Product Fit; Using Competitor / Unsolicited RFP | | Timing / Economics | Fit may be fine later; budget, timing, or capacity block a deal now. | No Budget; No Current Need; Resource Constraints | | Other | None of the above; use sparingly. | Other |
Splits and follow-ups (pick Pass vs Prospect carefully so reporting and nurture stay accurate):
No Response – Pass — No response and no meaningful signal (e.g. low lead score, no usage); terminal for active pipeline.
No Response – Prospect — They showed qualifying signals but went dark; create a follow-up task with a date (revisit in roughly 3–6 months).
Below Sales Assist Threshold – Pass — TAE judged under ~$20K potential with no signals worth revisiting.
Below Sales Assist Threshold – Prospect — Same economic band but signals worth another pass (ICP, growth, usage); create a follow-up task (e.g. BDR or named list). If nothing happens within ~90 days, revisit whether this split is useful.
Using Competitor / Unsolicited RFP — Locked in or chose a competitor; set a reminder to check in about 9 months (see new sales playbook).
Other — Requires a free-text comment when selected; if a large share of disqualifications land here, propose a new reason.
Manual entry
If you meet a potential customer elsewhere (e.g., events, introductions, referrals):
Create the Account and Contact manually.
Assign the correct Lead Source from drop down.
Create a Lead Task for any action item or sales follow up.
Support and billing routing
For support or billing questions submitted via the sales channel, disqualify with Support Request or Billing Support Request as in Completed contact form (Zendesk ticket automation). If you still see legacy lead records from older flows, the same reasons apply; ticket creation may use this Zapier path for some automations.
Billing vs. finance: who owns what
Billing and finance questions look similar but go to different teams. Route by what the customer is actually asking for:
Invoices → billing team Questions about what an invoice says or what information goes on it — line items, amounts, dates, the entity we bill under, or adding a PO number to an invoice. The owns the invoice itself.
Collections → finance team Anything about getting paid or where an invoice needs to go — requests to upload an invoice to a customer's payment portal (e.g. Zip, Coupa, Ariba), supplier-onboarding or vendor-setup forms, requests for extra documentation or information from us, and chasing overdue payments.
A quick test: if the question can be answered by reading or correcting the invoice, it's billing. If it asks us to send the invoice somewhere specific, complete a form, or provide extra information, it's finance.
Tax is owned by finance, who handle tax determination and compliance via Anrok. Billing only gets involved when a specific tax amount has to appear as an explicit line item on an invoice. For anything about tax rates, treatment, or whether tax applies, ask finance.
This comes up most with managed customers, where POs and payment notices sit at the intersection of sales, billing, and finance. These often arrive via the sales channel (the contact form or sales@) even though they belong to billing or finance — disqualify and re-route them using the split above rather than working them as leads.
Below Threshold – Auto (Customer.io)
When you should route someone to self-serve onboarding instead of hands-on sales, mark the task Below Threshold – Auto. That triggers the automated onboarding flow in customer.io, which guides them without manual outreach. Manual TAE judgment under the sales-assist threshold uses Below Sales Assist Threshold – Pass or Below Sales Assist Threshold – Prospect (see splits above), not this auto reason.
Spam
These mostly come into the sales inbox rather than the contact form. Whilst there is a Spam disqualification reason in Salesforce we can also prevent users from emailing the group again by banning them in the Sales Google Group. If you do ban someone bear in mind they won't be able to email our sales email until the ban is lifted so only use this for genuine spam (e.g. people trying to sell us competitor user lists).
Lead qualification criteria
Do they match our ideal customer profile?
Do they have a need that PostHog can help with?
Have they shown interest in our product/service?
Are they looking to make a purchasing decision within a reasonable timeframe?
Best practices
Make sure all new leads are contacted within 24 hours.
Keep all lead information up-to-date and accurate in Salesforce.
Periodically review lead statuses and update them as needed.
If you are actively working an existing customer as a lead make sure you add yourself as the Account Executive in Vitally (to avoid double assignment).
Handling time off (PTO)
By default, when you are out leads will still be routed to you, and as we have no expectation of you being available whilst on PTO leads may be missed and not followed up on. To mitigate this we need to temporarily remove you from lead round robin:
If you are out for 1 consecutive day or less:
Ensure your calendar is up to date with your time off, so that Default doesn't schedule meetings for when you are out.
If you are out for longer than 1 consecutive day:
Ensure your calendar is up to date with your time off, so that Default doesn't schedule meetings for when you are out.
Let Mine or Simon know 2 working days before you leave that you are out and need to be taken out of the round robin temporarily
Mine or Simon will then set you to inactive on the Leads assignment tracker in Salesforce.
They will also set a reminder to re-add you the day before you are back.
Opportunities
Opportunities track potential deals in Salesforce. Managing opportunities effectively is important for tracking progress, forecasting revenue, and ensuring accurate reporting. In our sales process, for each lead conversion we create an Opportunity. Correctly identifying the appropriate opportunity record type is important to optimize our processes.
Opportunity record types
New Revenue: Select this type when engaging with a customer who has never paid us before. This includes new customers and startup customers transitioning to a paid plan for the first time.
New Revenue – Existing Customer: Choose this type for additional credits to a customer who is already paying us. This includes upsells, cross sells, or expansion within the same account.
Existing - Convert to Annual: Choose this when discussing an annual contract with a pay-as-you-go customer.
Renewal: Choose this type when an existing customer is renewing their contract or subscription for our products or services. We automatically create a renewal opportunity if an 'Annual Plan' type opportunity is Closed (more on these later).
Opportunity types
Annual Plan: Select this type when the customer agrees to pay for a year-long+ subscription to our services.
Monthly Plan: Choose this type when the customer opts for a month-to-month subscription to our services. Amount field still reflects ARR here.
How to create an opportunity
Convert a task
If you're working a lead and want to create an opportunity from a task, simply check the Create New Opp checkbox and select the appropriate Opportunity Record Type from the dropdown.
This ensures the Lead Source is correctly carried over to the new Opportunity, and the task and opportunity remain linked for full visibility.
Creating an opportunity from scratch
You can also create an opportunity directly from scratch, but make sure to connect it to a Contact and an Account so all relevant data is linked properly. To do so:
Go to the Opportunities tab by clicking on the App Launcher (the grid icon) and searching for "Opportunities."
Click the "New" button and select the correct record type
Fill in Opportunity Details:
Opportunity Name
Close Date: Choose the estimated date when the opportunity is expected to close.
Term (Months): Default is 12, update for multi year deals. For contract buyouts, this already includes the buyout period (e.g. 12 standard + 6 month buyout = 18 month term), see contract buyouts and one-time credits below.
Total Credit Amount: Standard, discountable credit the customer is paying for. Does not include one-time/free credit, buyout or startup rolloff credits are tracked separately (see below).
Discount (%): Contracted discount rate applied to Total Credit Amount, this is what goes on the order form. Excludes any one-time credit.
ARR Discounted: Automatically calculated annualized revenue after discount.
Contract Start Date: Date the contract begins.
Contract End Date: Automatically calculated based on Start Date + Term.
One-Time Credit Amount: For deals with a buyout, startup rolloff, or other one-off free credit listed under Special Terms on contract. See contract buyouts and one-time credits below.
One-Time Credit Type: Buyout, Startup Rolloff, or Other. Only used when One-Time Credit Amount is populated.
Buyout Period Months: Only for Buyout type, how many months of Term (Months) the buyout credit covers. Leave at 0 otherwise.
Effective Discount Rate: Automatically calculated (amount paid ÷ total credit including the one-time credit)
Stage: Select the current stage of the opportunity in the sales process.
Type: If you know whether they're interested in paying on a monthly or an annual basis (if blank this will be Monthly by default)
Connect to an Account: In the "Account Name" field, search for and select the account associated with the opportunity. If the account does not exist, create a new account first.
Connect to a Contact: link any specific contact you're in touch with regarding this opportunity by adding them to the "Contact Roles" list.
Opportunity stages
Stages will differ depending on the chosen Opportunity Record Type. The following stages are for the New and Existing Business Record Types:
Problem Agreement - Buyer explicitly acknowledges they have a meaningful problem that can be qualified (e.g. "What happens if you don't solve this problem?")
Exit criteria:
Identified & implicated pain with specific, quantifiable metrics (time/money/risk)
Answer to "What happens if you do nothing?" documented with real consequence
Buyer explicitly said "This is a problem we need to solve" (not just "interesting")
Solution Agreement - Buyer confirms our solution is best suited to solve their problem. Can be as simple as "We think PostHog will work for us"
Exit criteria:
Active product usage OR completed POC/trial
Clear, documentable decision made for PostHog (with or without comparing alternatives)
Economic Buyer identified (name + title)
Champion identified (name)
Priority Agreement - A senior decision-maker acknowledges the problem as a priority and validates our solution.
Exit criteria:
Budget confirmed (amount range OR "yes, funded")
Decision process mapped (who approves, what steps, timeline)
Economic Buyer said this is a priority (exact quote documented)
Compelling event known (deadline: budget cycle, launch, renewal, etc.)
Commercial Agreement - Mutual agreement is reached on price and all contractual terms.
Exit criteria:
Price agreed in writing (email/quote with amount + terms)
All commercial terms agreed (payment terms, contract length, prepaid amount)
Paper process mapped (legal, security, procurement steps + owners + timeline)
Vendor Approval - Buyer completes internal processes (legal, security, procurement) and contract is executed.
Exit criteria:
Contract signed
Closed Won (100%) - They have signed the contract and are officially a PostHog customer.
Closed Lost (0%) - At some point in the pipeline they decided not to use us. The Loss Reason field is required for any opportunity to be marked as Closed lost.
Duplicate opportunities should be deleted, not marked as Closed Lost. A duplicate isn't a real loss, so marking it Closed Lost pollutes our loss data and skews win/loss reporting. Delete the duplicate record instead. Only use Closed Lost when a genuine opportunity didn't work out.
Bolded exit criteria indicate the minimum standard for the opportunity to advance stages (for typically smaller, more transational deals). More detail is available on the stages and the exit criteria for each state in this spreadsheet
Forecast categories
Commit: PostHog is integrated and the buyer has stated an intent to purchase within the Close Date quarter.
Best case: PostHog is or is being implemented, volume justifies an annual commitment, and the buyer has stated interest in purchasing with the Close Date quarter.
Pipeline: Buyer is actively evaluating PostHog or intends to evaluate PostHog within the Close Date quarter and early volume/discussion indicates an annual contract could be justified.
Omitted: Not used. You can omit from Forecast by moving the Opportunity to a new quarter or marking it as Closed - Lost.
Forecast categories should be re-evaluated on an ongoing basis. While it is not ideal for Opportunities to move to an earlier category, we should do so if this reflects reality, especially as quarter end approaches. In addition, we should think about what we can do differently in future to make the forecast more accurate.
Renewal pipeline
When an opportunity with Annual Plan type is Closed Won, a Salesforce flow will create an opportunity associated with the contact and account from the original opportunity. The following fields will also be set:
Amount - Copied over from the original opportunity
ARR up for renewal - Copied over from the original amount; so that we can track expansion/churn
Close date - 4 weeks in the future (may need adjusting if the opportunity record isn't closed on the contract start date)
Keep the renewal opportunity dates in line with the dates we actually invoice against. If the contract dates and the dates in Stripe disagree, the account owner must add a comment on the opportunity that records both dates and the confirmed one, and then correct the opportunity dates. See when the contract dates and the billing dates don't match.
The renewal pipeline stages are:
Qualification (10%) - They have just became a PostHog customer and we're helping them getting set up.
Meeting booked (20%) - They have reached a steady state where we consider them self-sufficient with PostHog.
Product Evaluation (50%) - This step becomes relevant if decision makers have changed in organization or if new teams within the company are considering using us.
Commercial & Legal Review (80%) - We are now working with them on contractual items such as custom pricing, MSAs etc.
Closed Won (100%) - They have signed the contract.
Closed Lost (0%) - At some point in the pipeline they decided not to renew. We should make a note as to the reasons why and optionally set a reminder task to follow up with them if we have improvements that could change their mind on our roadmap.
Opportunity notes
The "Opportunity Notes" section is to track key actions and next steps to manage an opportunity and avoid missed follow-ups. It has the following fields:
Next Steps: Add actions or tasks required to move the opportunity forward. Be clear and concise to ensure anyone reviewing the opportunity understands what needs to happen next.
For the New Business Sales Team, the Next Step should have three specific elements: 1) a timestamp -- when was this change made, 2) the owner at the customer for the next step -- who do we expect to take the action? 3) a binary outcome - (what will we/you get) related to the stage, with the next step date reflecting when the outcome is expected.
Next Step Date: Enter the date by which the next step should be completed. This helps in maintaining timelines and keeping follow-ups on track.
Make sure you accurately track known competitors in the relevant field, as we may trigger a TAE/TAM/CSM overlay to improve our chances of closing the deal.
Opportunity closure details
This section is to add additional information for opportunities that are won or lost to capture context and details to setup customer account correctly:
Loss Reason: A required field for any opportunity marked as "Closed - Lost." Pick the most appropriate option from the dropdown to help identify patterns.
Additional Loss Context: Optional field to add further insights into the loss. It's great to include specific customer feedback if available.
Contract Start Date: Especially important for correct account setup and tracking renewals. This date must match the start date of the customer’s current billing period for which they intend to apply credits. Setting this correctly ensures that any purchased or applied credits can be used immediately for the intended billing cycle.
Example: if a customer’s billing period runs from September 21 to October 21, and they purchase credits on October 15, the contract start date must be September 21 for credits to be applied to their current billing period. If instead the start date is set to a later date, credits would only apply to the next billing period, meaning the customer won't be able to use them right away. see more info on under contracts
Products: Select the products discussed/planned to be used as part of the opportunity. Make sure to include all addons so RevOps can ensure the customer’s subscription is set up correctly.
Contract Link: Link to the contract in PandaDoc for easy access and reference.
Self-serve opportunities
If you feel like a customer doesn't fit a hands-on flow, then you mark the lead or opportunity as self serve. There are two ways to do this:
1. Self serve - no interaction
Use this checkbox when you decide to move a new lead to the automated self serve flow without any personal interaction or discussion. You can use this checkbox when a lead does not meet the necessary qualifications for direct engagement and the automated self serve emails would be sufficient for successful onboarding.
How to use:
Go to the lead record in Salesforce.
Click the checkbox labeled "Self Serve - No Interaction" under the Lead Details section.
Once marked, the automated self serve email flow will be triggered, no need to do anything else.
2. Self serve - post-engagement
Use this checkbox if you have engaged with the lead in some form, such as a demo or discussion, but you believe they can proceed without further involvement.
How to use:
Go to the opportunity record in Salesforce.
Click the checkbox labeled "Self Serve - Post Engagement" under the Opportunity Information section.
Important notes:
There are no automated email flows attached to this checkbox. Once you have spoken with a customer at least once, all future communications should come directly from you.
Separately, these customers will still receive the standard onboarding emails from the app regardless of their self serve status in salesforce.
Points to consider when marking leads as self serve:
Usage Volume: If their usage volume is around 5 million monthly events and 100,000 recordings, they should be hands-on.
Annual Commitment: If they want an annual commitment, keep them in the hands-on pipeline.
Guided Evaluation Help: If they need help with a guided evaluation and their potential value is high enough, create a Slack Connect channel to assist them during the evaluation and keep them in the hands-on pipeline.
None of the Above: If none of the above apply, move them to self-serve.
When moving someone to self-serve we should set them up for success by using the Post Demo route to self-serve. This encourages them to sign up to PostHog Cloud and provides some helpful getting started pointers. If there were any follow-up questions from initial meeting we should answer those in this email as well.
If you move an opportunity to self-serve then it won't be included in your quota retirement/commission calculation (as you aren't working on it).
All done - now what?
This is just the beginning of what will hopefully be an awesome relationship with a new customer!
We are just getting started here, but a few things that you should do:
If they are a large/target customer, they should already have a Slack Connect channel in our company workspace.
Check in with them regularly and ensure they aren't blocked by support/other issues
Some accounts have both a CSM and a TAM. The point is depth: two people sharing the load so each can focus on what they're best at, and the customer gets a better experience than one person stretched across everything.
Both of you are expected to have a relationship with the customer, be in the Slack channel and know what's going on. The difference is _focus_, not ownership. The customer shouldn't have to work out who to contact: they message either of you, and we sort it out internally.
The structure outlined on this page should be treated as a guideline & should be tweaked as needed for different accounts:
A strategic account (our Top 40 are the clearest example) with several teams and a renewal coming needs more structure.
A smaller account earlier on in their trajectory with us & with fewer users probably doesn't.
What each role focuses on for overlay accounts
tl;dr
TAM leads commercial conversations (adoption of new products, breaking into new teams, renewals, expansion, etc.)
Onboarding, getting new users set up, training and adoption of products they already have
Day-to-day responsiveness
Health of the technical implementation
Surface cross-sell signals from product usage and conversations to TAM
TAM
Cross-sell strategy and execution
Credit discount negotiation and deal structuring for new credit purchases, invoicing
Use case discovery, mapping products to problems
Multi-threading into new teams/stakeholders, building relationships with their senior leaders and managers
Account planning (updated regularly in Customer Analytics)
Stakeholder management
Both
General customer questions (whoever sees it first)
Implementation reviews
Retention (TAMs are not off the hook here - understanding health is a prerequisite for cross-selling and not something to be delegated to the CSM)
Renewal process
<summary>What good looks like</summary>
Customer reaches out to either person and gets a fast, informed response. They never think about who to contact.
Both go deeper on their focus area than either could alone
Customer knows both people, trusts both, feels like they have a team
Neither person is surprised by what the other communicated
Both are visible in Slack, not just when they need something
Both are aligned on the current state of the customer, risks, opportunities and what their counterpart is working on
TAM and CSM alignment on the account happens in public, not DMs
<summary>What bad looks like</summary>
Customer gets told "that's not my area, let me get [other person]"
Customer only hears from the TAM when PostHog wants to sell something
Customer gets asked "how are things going?" by both people in the same week
CSM discusses pricing without knowing the TAM had a deal in play
TAM sends a cross-sell email without knowing the customer filed 3 support tickets yesterday
Neither person responds because each assumed the other would
TAM checks out on health because "the CSM handles that now"
Customer has to explain the same thing twice
Where to expect overlap
There will be overlap and you'll step on each other's toes - that's by design. The goal isn't a perfect division of work between the two roles, it's to play to your strengths and hit the goals set for the account. Where overlap shows up most:
Day-to-day questions
Whoever sees it first answers. If one of you has replied and the other has something better to add, chime in anyway. Two helpful answers beats one person holding back because someone got there first.
Renewals
Renewals sit with both of you for overlay accounts. The TAM leads the commercial conversation: stakeholder approval, quotes, accounting for growth and upsells, order forms. The CSM owns the value case behind it: what the customer used, what they got out of it, and where usage is heading.
A competitor showing up before a renewal on a CSM-only account is one of the best reasons to add a TAM (Competitive renewal has more details). Between both of you, coordinating the timing is important: start the renewal conversation 3 months out, since adding a TAM 30 days before is too late to shift a competitive evaluation.
Account health
The CSM owns reading the health score and keeping it current, but it isn't the CSM's problem alone. Both of you watching it might feel like duplicated work, but you're asking different questions despite looking at the same numbers.
The score on its own also won't tell you enough, as it's only designed to answer whether an account is at risk. Product engagement makes up most of it which usually confirms something that already happened rather than warning you. Total product count, a better headroom signal for a TAM, doesn't count much towards it. And it won't show you a single team going quiet, which is most likely on strategic accounts where several teams use PostHog for different things.
A few tips to help you approach this better:
Same numbers, different questions. The CSM asks what's degrading and why. The TAM asks where the headroom is and which teams aren't in the usage yet.
Read it together on your regular sync. Consider pulling the account up and sharing your thoughts on account health.
Watch #spike-detector for your accounts. It flags usage moving sharply either way, and both directions are worth a look: a jump might be a new team or a misconfiguration, a drop might be a team going quiet.
Cost efficiency vs. growth
The CSM's job includes helping a customer spend less. The TAM's job includes growing the account. Some situations might make you both pull in opposite directions.
At the end, efficiency should win, because a customer paying for waste has a reason to leave, and a right-sized customer expands better than a resentful one. More importantly, neither of you wants the customer to find out about this first.
Here's how you should consider handling it:
Surface the suggestion before recommending. If you're about to advise something that changes what the customer spends, say so in the internal channel first. Your counterpart may have a conversation in flight you can't see.
Log the work as you do it in the internal channel and then in the account plan. Usage moves for all sorts of reasons, and a record of what you changed and when turns an unexplained drop into a known optimization.
When you disagree
Usually the lists above settle it: whoever's focus area it sits in makes the call. On shared ground, default to whoever is closest to the live conversation, and have them post what they decided and why.
Two things worth keeping to:
Work it out in the channel, not in DMs, so the reasoning is there for whoever picks the account up later.
Back your counterpart once they've committed to something with the customer, and sort the disagreement out internally. A customer is more likely to pursue something you both agree on.
If you're stuck, bring your team leads in early. Both of you care about the customer and want to see them succeed, so it's rarely a disagreement about where you're headed.
Kicking off the overlay
When a TAM joins an account, or a CSM gets added to one that already has a TAM, use this list as a guide on how to kick things off strongly. Especially for larger/strategic accounts, try to adhere to it as much as possible, but the first three need to be followed regardless of account size:
[ ] Internal Slack channel created (#customer-[customer_name]-internal). Invite your counterpart and both the team leads. Add the FDE if they're doing active work on the account, and the PostHog Slack bot (@PostHog) so you can both dig into account data without leaving the channel
[ ] Your counterpart added to the external Slack channel (#posthog-[customer_name]) with a proper introduction
[ ] Whoever has the existing relationship writes a Customer Analytics note with the history and current state of the account
[ ] Whoever is joining posts their own read of the account, plus an action item they're picking up
[ ] Regular internal sync booked with your counterpart, if you don't already have one
[ ] TAM creates an account plan note in Customer Analytics once they have a read on priorities
[ ] Two shared artifacts accessible to everyone: a light org map of users you're actively pursuing or working with, and a running task list. These can live anywhere as long as there's an easy link in the channel: Slack canvas, Customer Analytics note, Google Doc
[ ] Any important dates (renewal, 6 month discount expiry, projected credit depletion) shared in the internal channel
The internal channel replaces DMs about the account, and you're both responsible for making sure the other has enough context to be useful. Working in the open there also ensures that it's easy for anyone to look up historical context around decisions in the future.
Get current on the account
If you're new and your counterpart has the relationship
Gather as much context as you can before jumping in with questions. Share what you find, and let the gaps guide what you ask.
As a CSM, treat it like your standard deep dive when inheriting an account, pointed at where you can add value fastest:
Are there cost optimizations to surface?
Opportunities to deepen value on products they're already using heavily?
Implementation issues?
As a TAM, come at it through use-case selling. Start from the job they already use PostHog for, then work out what's missing yet adjacent to what they're using:
Which use cases are they running today, and how deep are they?
Do they have gaps that can be closed by a product they aren't using yet?
Which adjacent use cases does the wider org care about, and who owns them?
Who are the senior leaders or managers in those teams, and which of them do you need a relationship with?
Cross-reference what you find against recent Slack threads and Customer Analytics notes. You want a current read on the account that your counterpart can sense-check.
Ideally, you come up with a recommendation for a first action item to share with the customer. Then post in the internal channel with your questions, ideas, and that action item (example).
Your goal: create value fast while learning as much as you can about your customers' business & usage, so you can start building rapport immediately with them.
If you're the one with the relationship
Share whatever's top of mind in the internal channel as a starting point. If there's context a quick call would convey better than the paper trail, do that.
Your counterpart is already gathering context from what's written, so don't be exhaustive. Focus on:
Key issues or active threads they must know about
Context around their business that cannot easily be deciphered from public info
Specifics around important relationships or stakeholders
Implementations in progress or recently completed
Add your counterpart to the external Slack channel (#posthog-[customer_name]). Use your judgment on when to introduce them to the wider customer team, and say what you're thinking so you stay aligned on timing.
When you do introduce them, frame it positively: the customer is growing and we want to support them better by having more hands on deck, not that they're being handed off (here’s a solid example).
Run the intro past your counterpart first. They'll often spot something that makes it warmer: history with a similar customer, a specialty that lines up with what this one struggles with, or calling out their experience for clout. A customer who's excited to meet someone starts better than one politely acknowledging a new name.
If you know of low-hanging fruit that would land well, hand it to your counterpart and let them deliver it. It's a cheap way for them to start on a good note, and it's worth more coming from the person who needs to build the relationship.
Your goal: share as much helpful and relevant context as possible with your counterpart, focusing on the things that aren't easily figured out by scanning the customers' site, usage or existing notes.
Staying in sync
To make sure you're both on the same page and to ensure continuity if someone new takes over the account, there a few things worth maintaining:
| What | Where | Why there | | --- | --- | --- | | Who's who at the customer | Org map artifact linked in the channel | One place to look, kept current | | Open follow-ups, action items & assignees | Task list artifact linked in the channel | The current list at a glance | | Per-call agenda | Thread in the internal channel | Tied to a date, and notifies you both | | Any info that anyone outside of you needs about this account | Account plan note in Customer Analytics | Easily searchable, and lives outside the channel |
Before a call
If you're both joining, start a thread in the internal channel a few days ahead and draft the agenda together: who covers what, who leads which section, and roughly how long each part gets. Sorting that out beforehand will make for a much more impactful call.
Make sure you both get at least some time to speak, even if one of you doesn't have an explicit agenda item. Two voices helps break the monotony if you're both on the call.
Use this same thread to also keep in touch while on a call. While Slack can be distracting on a call, having the thread opened up in a new window can help you both coordinate while on the call.
After a call
Update both artifacts: add anyone new to the org map, and add a dated section to the task list with the assigned follow-ups. Same after an async exchange that moved something along.
A post-call debrief huddle or thread in the channel is worth it too: what happened, what's next, who you think should pick up what and feedback on the call. Proposing the split is easier to react to than a list of notes your counterpart has to divide up themselves.
Tracking people and tasks
Either of you should be able to answer who someone is, or whether something got done, without asking the other. So each internal channel wants two links that are easy to find, pinned or bookmarked:
A light org map. Who you've met or who you're pursuing, what they do, and which of you has the relationship.
A running task list. Added to rather than rewritten, so you can see what got done as easily as what's outstanding. Dated sections work well: a one-line heading for what happened, then the follow-ups underneath.
Use whatever you'll both keep current: a Slack canvas, a Customer Analytics note, a Google Doc. The examples below use canvases because they sit where the conversation already happens. On a smaller account, one pinned message often covers both.
<summary>Example: an org map as a canvas</summary>
A canvas called [customer_name] - People, with a table in it:
| Name | Title | Who has the relationship | | --- | --- | --- | | Ana | VP Engineering, exec sponsor | TAM | | Dev | Staff engineer, owns the implementation | CSM | | Mo | PM, heaviest Experiments user | CSM | | Sam | Data lead, team we haven't landed yet | TAM |
You're not mapping the whole org, just keeping something easy to refer back to. Add people as you meet them.
<summary>Example: a running task list as a canvas</summary>
A canvas called [customer_name] - Tasks. After every conversation, add a dated section at the top with a one-line heading for what happened, then a checklist of follow-ups with the CSM or TAM against each:
Sep 12, 2026 - Call with champion re: renewal prep and Experiments issues
[x] Send the event volume breakdown ahead of the call (CSM)
[ ] Follow up with Sam's team on the warehouse question (TAM)
[ ] Get the flag naming convention written up (CSM)
Aug 28, 2026 - Implementation review with the platform team
[x] Walk through the replay sampling config (CSM)
[x] Intro the TAM to the data lead (CSM)
Older sections stay put. That's what makes the list useful three months later, when you're trying to remember if anyone ever answered a specific question.
Recording who has the relationship is very useful in the org map because it means they should flag if that contact goes abnormally quiet.
On tasks, keep the newest ones at the top and make sure someone's assigned to each one. If something has sat unchecked for a while, have a chat in the internal channel with your counterpart on whether it's still important
Neither doc is searchable the way Customer Analytics is, so roll the developments that matter into the account plan note as you go.
Sharing DMs
DMs with customer contacts happen, and that's fine. What you want to avoid is the account picture living only in one person's DMs.
Post a short summary in the internal channel whenever a DM changes the plan, surfaces a risk, or commits PostHog to something. Your counterpart needs to know what shifted or if there was a win in the DM, especially if there are joint follow-ups coming out of it.
Who joins which call
On strategic accounts, default to both of you on most calls. We don't run many in the first place, and the context you each pick up will be very helpful even if you don't have anything to discuss.
On smaller growth accounts, both of you joining every call is likely overkill. One of you running a routine check-in is fine, as long as the follow-up lands in the internal channel.
Either way, the calls worth both of you being on are the ones where the relationship or the commercial picture is changing: renewals, business reviews, potential expansion conversations, competitors surfacing or anything going sideways.
Sync cadence
Meet at least once a month, or more often if you need to. Either way, what comes out of it should land back in the internal channel, since most of it feeds account planning.
How you create value together
Two people on an account buys depth and breadth: relationship-building, use case optimization, implementation audits, and much more. To get that, have good communication on who's doing what.
A good starting point is to find the gaps in coverage and the open threads, then prioritize. Here are some questions worth working through together:
Is the customer struggling with a specific product? (example)
What frustrations have they surfaced recently?
What expansion opportunities are there?
Is their implementation healthy? Are they due for a health audit? (example)
Any cost optimization opportunities? (example)
Prioritize together, then explicitly assign each other paths to run with. Think of it as delegating what you'd otherwise do yourself if you were alone on the account. Give each other the work streams where you're each most likely to succeed, and if a TAM already has a warm relationship with the champion for an expansion, they should keep it rather than hand it off mid-flight.
<summary>An example of both of you creating value in separate product areas at the same time, while playing to your unique strengths as a TAM and CSM</summary>
Customer is a heavy Experiments user, and they run into a lot of issues because of their sophisticated setup. But they're concentrated on that product, so we're also thinking about expansion opportunities to derisk the account.
The CSM could focus on deepening the value the customer gets from Experiments by scheduling 1:1 feedback calls with power users to better understand their pain points and work on fixes.
The TAM can focus on a net new cross-sell opportunity into AIO with a different set of stakeholders and deepen the value from other products that have been adopted.
In this scenario, your parallel efforts unlock goodwill from the customer, bandwidth for the TAM to grow the account, and space for the CSM to go deep on debugging and instrumentation on their existing product adoption.
The net effect: customer feels supported on multiple fronts.
None of this is a hard rule (CSMs on instrumentation, TAMs on expansion). You'll overlap and switch at times, and be more siloed at others. Bigger accounts need the split made explicit because there's more in flight while on a smaller one, it's often obvious enough to leave alone.
Here's a good way to test this: ask yourself whether you can say what your counterpart is working on right now? If not, ask in the internal channel more often. What you're avoiding is duplicative or irrelevant work, so honor each other's time by communicating clearly and often.
Guidelines for stepping on toes
How can you both be the driver if there are two people in the same car? It's okay to step on toes as long as you don't stomp each others' feet or trip over each other. A few habits that protect your autonomy without blocking each other:
Post often in the internal channel: what you're thinking about, who you have a call scheduled with, open questions, an opportunity you're chasing down... anything. Write as generously and freely as you would on a private scratchpad - it's the closest thing we have to a shared brain.
Document as much as you can in Customer Analytics, the artifacts and the internal channel: details, developments, learnings and plans from your internal threads should end up as a note on the account in Customer Analytics.
Use each other to sense check: consider a monthly call where you catch up on your shared accounts. Talking through what you're thinking often reveals parallel work streams.
Debrief after customer calls: this is where you'll feel the superpowers that come with a CSM + TAM overlay - give each other feedback, get clear on next steps, and review how the call went.
Tag team follow ups: one of you plugs something in the customer channel; the other stands by to chime in with a follow-up to get a response. Works like a charm for unresponsive customers.
Here's how to respond to common customer requests. These usually arrive in the form of new contact form submissions but may also be asked by existing customers too.
Can you increase my rate limits?
Here's how we'd break down use cases:
if the use case is exporting all the data so they can do further transformation or activation in other tools -> use batch exports
if the use case is ultimately going to be accessing our API programmatically with a pre-defined query -> use endpoints product
if the use case is essentially wrapping PostHog and allowing the customer to query whatever they want (in other words, if they want a different UI for querying PostHog data) -> use /query API endpoint
flowchart TD
A{Is the API hitting <code style='padding: 4px; border-radius: 8px;'>/query</code> rate limits?}
B{Does the use case fit endpoints?<br />(i.e. B2B2C user-facing analytics, data-powered APIs, internal home-grown dashboards)}
C["Explain the use case in #team-data-modeling <br />(we're keen to talk to beta users!)"]
D{Should they use batch exports instead?}
E[Redirect them to start paying for batch exports.]
F[1. Assume we're not increasing rate limits.<br />2. Reach out to #team-clickhouse with query details.]
G["Go to the relevant team for that API<br />(Feature flags, Surveys, ..)"]
A -->|Yes| B
A -->|No| G
B -->|Yes| C
B -->|No| D
D -->|Yes| E
D -->|No| F
Do you have plans to add more hosting options outside of the US and EU?
Right now, no. The vast majority of our customers are happy to host on one or the other, with EU being the preferred domain for GDPR compliance. This is not a "never", just not in the near future.
Do you have a dummy account we can mess around with?
No, the best way to trial PostHog is to start sending your own data into it. When a trial is filled with dummy data, which isn't relevant to the specific team, the overall engagement and success of the trial is lower.
Does PostHog follow the MEDDPICC sales methodology?
Yes! But like everything we do here, it's not what you would expect. At PostHog, MEDDPICC means "Make every deal a delightful PostHog implementation - Charles Cook"
We have thousands of customers in PostHog, many of which are in similar industries. As CSMs having an understanding of our customers' industries can help us better be an expert on how PostHog works best for their specific use cases. This page serves as a resource for us to be able to collect and share industry specific vocabulary, important metrics, PostHog best practices, etc. that allow us to quickly ramp up on the industry to better engage with those customers.
Industry segment list
These segments can change as our customer data evolves, but the following serve as a starting point:
Eventually each industry listed above will be linked to its own playbook with details its specifics. The following is a template that can be used to create the playbook:
### Description (general overview of what the industry is and the businesses it consists of)
### What they care about (i.e. what is most important to their business success)
### Industry terminology
### Common software used
### Important business metrics and data
#### Metrics
#### Data (event taxonomy, person profiles, groups)
### PostHog products they should be using
#### Product
##### Best practices
##### Common challenges
##### Cross product use cases
Industry segment
Industry segment is a customer property that we use internally at PostHog.
<summary>AI and data playbook</summary>
AI and data description
Companies that exist in different parts of the AI value chain. There is significant potential to develop further playbooks for each sub-segment.
Sub-segments
| Sub-segment | Examples | Description | |:------------------------|:-----------------------------------|:---------------------------------------------------| | Hyperscalers | AWS, GCP, Oracle, Azure | AI services in the cloud | | Frontier model labs | OpenAI, Anthropic, Cohere, Mistral | Foundation models with proprietary architectures | | Generative | ElevenLabs, Runware, Runway, Luma | Product suites around output | | Inference | Replicate, fal\.ai, Together\.ai | Host / serve other models, making them easy to run | | AI-native applications | Cursor, Perplexity | End-user tools where experience is driven by AI | | Data / machine learning | Databricks, Hugging Face | Orchestration, system management |
What they care about
They share a developer-centric focus on adoption and retention. The higher-order sub-segments (hyperscalers, frontier model labs, inference) care about competitive parity and platform stickiness. Generative and AI-native application segments care about feature adoption, generation metrics, unit economics, and retention.
Sub-segments differ on what they track as output. Generative customers measure the artifact itself, like whether a change increased how often users download an image after generating it. AI-native application customers measure task completion rates and time saved.
Industry terminology
Observability – Monitoring model performance, token use, latency, unit economics, and hallucination rates in production. Most relevant to teams shipping features that interact directly with users.
Feature store – Centralized system for serving, storing, and managing machine learning features that are used in training and inference. These are more commonly found with mature data organizations.
Tokens – Units of processing/billing for LLMs. Can vary based on segment. Other variations would involve count, prediction, job, credit.
RAG (Retrieval-Augmented Generation) – An architecture pattern where an LLM pulls from external knowledge sources before generating a response. For segmentation, RAG-based products have unique infrastructure needs like accuracy of retrieval and context window usage.
Benchmark – A standardized test set for comparing model capabilities.
Latency – Time between sending a request and receiving a response.
Throughput – Number of requests/tokens processed per unit of time.
NLP (Natural Language Processing) – Branch of AI that enables computers to understand and generate human language.
Embedding – Representation of data (text, image, user actions) as vectors used for recommendation, search, and classification.
Common software used
_Note: This list is incomplete, ongoing, and has overlap. It is meant to serve as a directional guide versus ground truth._
Data warehouse: Snowflake, Databricks, Firebolt, BigQuery
Unit economics: FinOps tooling, Helicone, LiteLLM, OpenRouter
Data pipeline: Atlan, Alation, dbt, FiveTran, Apache Airflow, Stitch
You should make yourself familiar with how each of these products stacks together in a customer's value chain. It's a "current events" practice that will allow you maximum ability to speak to how customers can turn a disparate system of tools into one AI and data centric Howitzer.
Important business metrics and data
Metrics
| Metric | Measurement | Business context | |---|---|---| | Cost per action | Infrastructure cost to serve a particular user action (cost per image generated, cost per second of video generated, cost per query, API call) | User interaction drives margin | |Feature margin|Revenue against how much it costs to run the feature | Can be complex if infrastructure does not support granular definition of feature |
Data
Event taxonomy
AI and data customers should be running AI Observability. It sets the taxonomy: with the SDK you get structured generation, trace, and cost events out of the box. Without it, taxonomy falls back to whatever the customer wires up by hand. Those structured events are also what PostHog's agentic products read, so clean instrumentation is the prerequisite for any self-driving analysis on top.
Without the AI Observability SDK:
Autocaptured clicks and pageviews on AI features (button presses, route changes)
Custom events the customer wired up by hand, like chat_message_sent or prompt_submitted
Whatever properties a customer should choose to attach
With the AI Observability SDK:
$ai_generation – one row per LLM call with model, input/output tokens, cost, latency, and provider
$ai_trace and $ai_span – parent/child structure for multi-step agents and tool use
When companies look at their event data in this segment, they're trying to answer "who did this?" and "who are the power users?". Tie every generation to a person profile, and give that profile a defined user_role (admin, for example) alongside aggregations like total_api_calls or total_tokens_used. Without it, you can see that tokens are being burned but not who is burning them.
PostHog products they should be using
Lead with AI Observability. It's the one product built for how these customers make money: it captures every model call as a structured event with cost, latency, tokens, and provider. That event stream is the foundation everything else builds on, from cost analysis to experimentation to the self-driving loop. Get the customer onto it first, then layer the rest.
AI Observability
Best practices
Instrument model calls server-side with the AI Observability SDK, where the model actually runs, and identify on the same authenticated request so every $ai_generation ties to a person.
Attach model, provider, and feature (or prompt version) as properties on the generation, so cost and latency can be sliced by what the customer ships.
Capture cost on the generation event itself. Don't reconstruct it later from token counts.
Set person properties from the server-side source of truth, not client state. Use $set_once for immutable values (signup date, acquisition channel) and $set for mutable ones (plan tier, role, last active feature).
Common challenges
High event volume meets cost sensitivity. LLM apps are chatty and margin-conscious, so ingestion cost gets scrutinized. Lean on sampling, ingestion filters, and dropping high-cardinality properties they'll never query. Don't re-send person properties ($set) on every high-volume event, since that inflates ingestion for no analytical gain.
The events that matter fire server-side. Client-only instrumentation misses the actual model calls, so identify on each authenticated server request.
Environment density. Staging, eval, and simulation traffic pollute production data. Split by project or enforce a strict environment property.
Cross-product use cases
AI Observability – join $ai_generation cost back to person properties for cost-per-segment, or to identify which plan or role is burning the most tokens.
Feature Flags and Experiments – gate new models behind flags, run A/B tests on prompt changes, hold out high-value users from risky rollouts.
Surveys – trigger feedback prompts after a generation, collect CSAT on AI features, run PMF surveys against power users.
Session Replay – filter to recordings of users hitting prompt failures or specific $ai_generation errors.
Replay Vision – run scanners over those recordings to auto-flag dead ends and prompt failures, then query the results back as PostHog events.
Error Tracking – group exceptions by plan, model, or role to see which segment hits a bug.
Data Warehouse – sync events for joins against billing or model cost tables, then pipe insights back.
Self-driving – point the self-driving loop at these signals: agents investigate the reports, open pull requests for fixes, and measure whether they worked.
<summary>E-commerce playbook</summary>
E-commerce description
Online retail businesses including direct-to-consumer brands, marketplace platforms, and omnichannel retailers selling physical or digital goods through web and mobile.
What they care about
Conversion rate optimization across the entire funnel
Cart abandonment reduction
Customer acquisition cost (CAC) vs lifetime value (LTV) balance
Site performance impact on sales
Mobile vs desktop performance disparities
Seasonal traffic and sales patterns
Inventory turnover and demand forecasting
Return rates and reasons
Cross-sell/upsell effectiveness
Industry terminology
AOV (Average Order Value): The average dollar amount spent each time a customer places an order.
PDP (Product Detail Page) / PLP (Product Listing Page): PDP is the individual product page with detailed information, images, and add-to-cart button. PLP is the category or search results page showing multiple products in a grid or list format.
SKU (Stock Keeping Unit): A unique identifier code assigned to each distinct product and its variants (size, color, etc.) for inventory tracking.
Drop-off rate / Abandonment rate: The percentage of users who leave a process (like checkout) without completing it. Cart abandonment specifically tracks users who add items but don't purchase.
Retargeting / Remarketing: Advertising strategy that shows ads to people who previously visited the company's website or app, aimed at bringing them back to complete a purchase.
Attribution window: The time period after a user clicks or views an ad during which a conversion (purchase) will still be credited to that ad. Common windows are 1, 7, or 30 days.
ROAS (Return on Ad Spend): Metric measuring ad campaign effectiveness by dividing revenue generated by the cost of ads.
Common software used
Platforms: Shopify, WooCommerce, BigCommerce
Analytics: Google Analytics 4, Contentsquare, Hotjar
A/B Testing: Optimizely, VWO, Shoplift
Important business metrics and data
Metrics
Conversion funnel: Homepage > Category/PLP > PDP > Add to Cart > Checkout Started > Purchase Complete
This is a rough articulation of the phases a paid and "sales-sized" customer moves through PostHog, from first signup to steady state, and which role covers them at each phase. The purpose of mapping this out is creating a shared understanding so we can better standardize how we think of and approach accounts, as well as account allocation. When you know a customer's phase and ARR band, you know who should be working with the account. For the operational process (book planning, allocation cadence, handover mechanics), see Account allocation and handover, which holds the allocation rules.
The phases
Presales
| Phase | Definition | | -------------- | ------------------------------------------------------------------------ | | Exploring | Signed up, sending events, free tier or trivial spend. No buying signal. | | Evaluating | Actively comparing us against alternatives or against not buying. | | Proving | Running a structured POC with success criteria, ours or theirs. | | Buying | Commercial negotiation. Quote out, annual terms in discussion. |
In a PLG motion most customers move through the presales phases invisibly and without contact. Our process and system should be able to capture and identify the right accounts to work with at the right time based on signals and phases. Exploring, Evaluating, and Proving are inferred from product signals unless sales is engaged. The presales phases only need to be as granular as the routing decision they drive, which is binary: automation, or a human from new biz.
Postsales
| Phase | Definition | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Implementing | Delivering a closed deal. Posthog instrumentation, onboarding and success plan, stakeholder map. | | Ramping | Usage growing, account below full TAM threshold or still climbing toward committed volume or otherwise just not at fully implemented production volume. Generally takes longer for larger or more traditional orgs. | | Expanding | A clear expansion, cross-sell, or save opportunity exists and is being worked. | | Steady state | Growth and expansion exhausted. Core products adopted, saturated across the organization, healthy engagement, no viable expansion play. |
Edge case worth noting: a pure self-serve account that crosses $20k ARR with no sales involvement skips Implementing entirely. They enter at whatever their adoption or usage indicates, usually Ramping or Expanding. This is important, though, because an account that's been self-serve and steady state in prod for 2 years doesn't need the same tactic and approach as a sales-driven "implementation" account, and our process shouldn't treat them the same.
At risk is a status, not a phase
An account in any postsales phase can be at risk. At risk does not change the phase or reassign the account. When both a TAM and a CSM are on the account, they co-own the churn save. Otherwise the current owner runs it. Going at risk is not a reason to add a TAM.
Coverage map
Who covers the account at each phase. Phases run top to bottom in the order a customer moves through them; roles run across.
✅ active coverage · 🟡 conditional (see notes) · blank = not involved
Automation is the base level everywhere a direct human coverage isn't needed. Below-$500 MRR accounts and sub-$20k steady-state accounts have no human owner by design.
TAM allocation can start during Implementing when a deal closed with a qualified expansion opp.
Growth TAM pickup can happen during Implementing for a fast-ramping sub-$20k account.
The onboarding team's coverage is wide because its trigger is first payment, which can land anywhere from Exploring through Ramping.
BDR coverage is top-of-funnel only: BDRs source and qualify accounts at Exploring (primarily via cold outbound to accounts with no inbound buying signal) and hand off to the TAE at Evaluating. They don't carry the account past that handoff.
FDE coverage is conditional where TAM, CSM, or TAE sell an FDE engagement to a customer account and then an FDE runs a short-term, hands-on technical engagement where the implementation need is more than a TAM or CSM can deliver.
The 🟡 at Proving covers the case where an FDE helps prove technical fit during a POC with a top prospect.
The 🟡 at Steady state is for a churn prevention play where an FDE has been brought in to fix issues with a customer implementation.
Ownership rules
CSM is the base layer, unconditionally. Every account above $20k ARR has a CSM from day one post-sale. The CSM never leaves. Steady state is not a handoff event, it just means the TAM/TAE overlay has been removed.
TAM coverage is the exception, not the default. A TAM is added to an account only when a clear expansion or cross-sell opportunity justifies it, and released when the opportunity is exhausted.
TAE handoff goes to CSM, always (above threshold). Optionally, the TAE can retain the account to expand it when there is a specific opportunity that justifies the retention across a 12 month window.
BDRs feed the funnel, they don't own the deal. BDRs own top-of-funnel sourcing at Exploring and hand off to the TAE at Evaluating. Coverage ends at the handoff; the TAE owns the account from there.
Our moat is that we have a fully-integrated tool that allows customers to go across Analytics, Recordings and Experimentation easily. We want new customers to see the value of this as quickly as possible when evaluating us against other solutions.
For high-touch prospective customers the following process will get them onboarded quickly so that they can experience the value we provide using their own product data.
The process should run for 2 weeks by default, but can be extended if we think it's worth the additional effort.
The aim at the end of the evaluation is to have them:
Sending in auto or custom captured event data
Enabled session recordings
Created a trend chart tracking User Acquisition
Created a funnel tracking Activation
Added the above to a dashboard
At the end of the demo call
If at the end of a demo call we think a customer qualifies for high-touch onboarding we should outline our suggested evaluation approach. If they aren't quite ready to kick the evaluation off then we should follow up with a templated email reminding them of the process, then check in with them after they've had some time to regroup.
High touch criteria
As a small team we have limited bandwidth to run customer evaluations so we need to focus on potential customers who:
Are likely to contract above $20k with us.
(Ideally we qualify this by giving indicative pricing in the demo)
Are likely to enter into an annual contract.
(This is quite a high-effort process for people just going month to month)
Are ready to get hands-on with PostHog and will make a decision in weeks, not months.
Expectations of the customer
We'll need them to be able to demo their product to us, as well as attend two or more zoom calls where we scope out the data and help them get set up.
Ideally we will also have them in Slack Connect channel so that we can provide responsive support and expose them to the wider PostHog team.
Some customers may wish to use MS Teams rather than Slack - SupportHog works in Teams too. See Using MS Teams on the shared channels page for how to get set up. Before adding the customer into the channel, remember to test it to ensure ticket creation is working correctly.
Day 0 - Session: Kick off
At the start of the evaluation, we want to review their product to understand and advise on the best approach to tracking, as well as address any privacy concerns associated with session recordings.
By the end of the call we should have a plan for event capture/opt-out capture and an agreed timeline to get that set up.
Prerequisites
The customer should come prepared to demo their product to us, where we can help figure out the key tracking events needed for the evaluation to be successful.
If they don't already know about AARRR we should share our AARRR blog post and Tracking Plan and ask them to review it before the call.
Structure
Review goals and structure of this session
Review key concepts:
Acquisition
Activation
User Identification
Cohorts
Groups
Privacy / opt out capture
Have customer demo their app to you, focusing on where the above information is captured
During the demo agree where Acquisition/Activation/Identification take place
Get the CSS selectors and pages of any items to opt-out of capture
Agree any additional properties that need to be captured
Recap and agree the tracking and other implementation details
Agree the timeline to have tracking implemented and set up the following call (ideally 3 days after capture is implemented)
Deliverables
A partially filled-in tracking plan detailing Activation and Acquisition
A code snippet showing them how to implement tracking for their product (including Identification and Groups if applicable)
Elements and pages to add opt-out-capture to
Day 3 - Session: Using PostHog
The aim of this call is to get the customer familiar with navigating PostHog as well as:
Defining Actions
Defining Cohorts
Creating Insights
Creating Dashboards
Finding Recordings
As much as possible the customer should be sharing their screen and driving the session, by teaching them to fish they become comfortable and self-sufficient with PostHog.
Prerequisites
Tracking should be set up in line with what was shared after the previous call.
Structure
Review goals/agenda
Have them share screen and guide them through:
Live events
Creating actions
(Optionally if using Autocapture) the toolbar
Creating cohorts
Creating their Acquisiton trend insight
Creating their Activation funnel
Adding insights to a dashboard
Navigate from dashboard to insight to recordings
Note any inconsistencies or missing tracking information and plan to follow-up to help get that set up 4
Show them the billing page and their projected usage (pricing discussion)
Deliverables
Updated tracking guidance based on issues discovered in the guided demo
Updated pricing quote based on volume
Next Steps
Every trial should have an end date by which time we expect the customer to make a decision on whether PostHog is right for them. If they need more time we first need to understand what they've not seen so we can proactively help them see everything they need to do make a decision (within reason).
If they do become a customer (yay!) then we should agree a regular check in call cadence with them from the start (it's much harder to do after they are in the steady state).
Customer Success-led
1-hr onboarding call
Customers with a platform package (and up) are entitled to a one hour kickoff/implementation call. This could include a high-level discussion of how PostHog fits into their stack, troubleshooting issues they've hit so far, or walking them through as they code it up, for simple setups. In practice we only need to worry about this for product-led / customers who haven't talked to sales before. [TO DO] Include a team calendly link in the welcome emails for Teams purchases or set up a separate campaign to email from a CSM.
Ongoing Training
Enterprise customers will also receive 1-2 hours of bespoke training per quarter according to their needs. This can be delivered in a few formats depending on where the customer is in their PostHog journey:
A deep-dive on a specific topic of their choosing.
Question and Answer session with their CSM.
An intro/set-up session for a PostHog product they've not used yet.
In-person visits work best for accounts paying or likely to pay $50k+/year where you've identified specific opportunities for expansion, are navigating renewal conversations, or need to overcome significant technical or organizational hurdles. They're a high-effort, high-reward play - use them strategically.
This outline of what to consider and how to plan an in-person visit is designed to provide ideas, inspiration and avoid common pitfalls. It is not a framework nor a definitive guide - your intuition and experience should ultimately guide the who, what and how of in-person meetings.
Account manager driven vs customer driven visits
Account manager driven
Sometimes you'll be the driver for the visit happening, whether by pitching a specific outcome, or offering to 'drop in' when you're around. When this is the case, it's important that you have a tight, well defined schedule and some goals (whether shared with customer or not) for the visit. Don't leave your champion(s) to do the work of planning and scheduling the sessions - you want them to be able to join the session, have a positive and productive experience, and continue evangelising us without adding to their to-do list.
Customer driven
Sometimes the purpose of an onsite is defined clearly by the customer, for example overcoming a specific technical challenge, or building an analytical framework for a new product. In this situation, definitely schedule significant time to address their primary goal, but do not underestimate the opportunity to create less formal contexts with smaller audiences, especially your champions.
Formal Sessions
This section will cover the length, audience, purpose and content of sessions that you could include as part of your onsite - pick and choose like a menu. At a minimum you'll want a broader session with a big audience and a narrow session with the key stakeholder(s) and champions to progress a relationship with an account.
PostHog user analytics jam
Length: An hour, possibly longer with a small focused audience
Audience: Users of PostHog, the more the better, armed with laptops and logged in
Purpose: To level-up how users engage with our platform, spark new ideas and inspiration for customer teams, and expand usage and impact by enabling the audience on our products.
Content: Set an explicit goal that you think is achievable within the session for you to work towards with the users. Invite ideas and suggestions to get the jam going, but make sure you have some solid ideas in your back pocket to get things started. Building a compound score (i.e Customer effort score, time to value, onboarding friction) can be a good one if the customer has no ideas. Do not start demoing, but do show users useful shortcuts (PostHogAI, Actions, Cohorts, Workflows, Realtime destinations etc) if relevant. Conclude by summarising progress, and suggesting some follow-up and continuation tasks to take it to the next level.
Check-in and planning with champions
Length: 30 minutes to an hour
Audience: The champions of PostHog at your account
Purpose: To level set about PostHog's reputation and role within the customer, and unearth any opportunities or risks, while building stronger relationships with champions. Also a chance to test the water for any cross-sell proposals, and ensure champions are aware of all of our products.
Content: Discovery and planning with the champions, potentially over a meal or in another less formal context - certainly not in front of their teams or boss, if relevant. Give the champions time to air any frustrations, and ask direct questions about renewal, their roadmap, any current or future needs in their team or beyond. This is a good time to find out where you really are with a customer and what organizational challenges you may need to navigate, as well as expand their perception of what we can do. Some good questions to ask:
-"Do you intend to renew with PostHog? If not, why not?" -"What tools are other teams using alongside PostHog data to get the full picture of user behavior?" -"What goals and focus areas are on the table for the next year? How does PostHog fit into those?"
New user demo on your own data
Length: 40 minutes with time for questions
Audience: Customer employees who do not yet use PostHog, or are very new.
Purpose: To increase the number of PostHog users at the customer, and expand laterally into teams that may otherwise not use us.
Content: A demo on the customer's data. Tailor this and create insights or show features that'll be a good jumping off point for the audience to go further on their own. Make sure to note who your audience is and check-in with any that don't start logging in within a week or two.
Executive summary
Length: 30 minutes
Audience: Senior folks - csuite or VPs
Purpose: To improve the perception of our value to senior people, while discovering our position and estimation at the decision-making layer of the customer.
Content: A punchy, direct delivery of information focused on value that connects PostHog to the key goals and objectives of our customer.
Example: Connect PostHog usage to a metric the exec cares about: "Your team shipped 12 features last quarter. Using PostHog's feature flags and analytics together, the product team can now measure impact within 24 hours instead of waiting for your monthly business review. This means faster iteration and less risk of shipping things that don't move the needle on [their key metric]."
Manufacturing Informal Access
Why this matters
The formal sessions are theater - everyone is in meeting mode, and the group is usually to large for real candor. Deeper information comes out over lunch, walking between buildings, or after a drink: you need to create contexts where people forget you're "the vendor" and just talk to you like a colleague.
Making the invitation
Bad: "I'd love to take you to dinner to discuss PostHog's roadmap" Good: "I'm grabbing dinner at [specific place] after our session - you're welcome to join if you're around" Notice: You're doing it anyway, specific location, low pressure, no stated agenda.
Common mistakes to avoid
Don't treat this as a sales pitch - if you're showing up just to close a deal, you're not expanding your relationship and understanding of the customer.
Don't over-schedule - leaving buffer time for organic conversations is often more valuable than cramming in another session
Don't show up unprepared on their data - spend time before the visit building something useful in their PostHog instance that you can show them
Follow-up
Make sure you take advantage of good will and being front of mind with the customer after the visit to followup on any outstanding goals, move any paused commercial conversations forward, or ask for access to any teams or key people you weren't able to reach while in person.
Purpose - Get new PostHog customers self-sufficient and primed to explore more of PostHog.
Format - Two live group sessions for up to 30 people across product, marketing, and engineering.
Total TAM time - ~2.5–3.5 hours live delivery, plus ~one hour prep per session.
This document tells you what to cover in a training session and why it matters. It's not a script or the only way to approach training. Consider this a good baseline but you will want to always run it in your own voice, in whatever order fits the customer's needs. Product training is a separate and optional activity you can run with an account if you believe it will increase usage and help them derive more value from PostHog.
PostHog AI and MCP should be woven into every demo and practical. Don't teach them as standalone features. Use them as the way you build things in front of the room. The goal is for everyone to leave thinking AI-assisted analytics is the normal way to work.
Pre-session work
Do this before Session 1. The prep is what separates a useful session from a product tour that is easily forgotten.
Understand what will make the session valuable
Gather answers to the following questions (you may know the answers but it's still worth asking the customer directly):
"What are the three questions about your users you can't answer today?"
"What tools are you replacing or supplementing with PostHog?" (GA4, Amplitude, LaunchDarkly, etc.)
"Who on your team do you want using PostHog daily? What are their roles?"
"How heavily have your teams adopted AI tools and workflows?" (This sets up the MCP conversation later.)
Decide what to show
If the customer already has a PostHog instance, you may want to use it for the training session. It is easier for new users to understand how PostHog works if they're familiar with the data they're looking at. Make sure you have permission from an Owner or Admin before Session 1.
Review their account in Metabase to get a better understanding of existing usage. Are events named consistently? Are they identifying users? Is autocapture on? Note the gaps – you'll address them in Session 1.
If the customer's instance has not been well instrumented (poor event taxonomy, instrumentation gaps, or limited product adoption), it may be better to use a demo instance with data that closely resembles what the customer might have. If it's really bad, consider waiting to do training until you've helped them improve it.
Prep a dashboard
Build a dashboard from their actual data (or something closely resembling it). Three to five insights that answer their key user questions above. You'll refine it live, but showing up with something already built saves 15 minutes of dead air and proves you did the homework.
Prep a session summary
Generating a session summary can take a few minutes. Instead of doing it live during training, create one ahead of time that you can show.
Confirm attendees have access
Confirm via admin panel that attendees can sign up by themselves (Authentication Domains have been configured) or that they've been invited.
Consider sending attendees a welcome email if they're new to PostHog. Use this as an opportunity to tell them what PostHog is and how they can access it.
If possible, schedule both sessions in the same week. Monday/Thursday or Tuesday/Friday. A long gap between sessions kills momentum.
Duration - 90 minutes (65 min content, 15 min Q&A, 10 min buffer).
Deliverable - A working dashboard in their project. Every attendee knows how to build an insight and watch a replay.
Why it matters
This is the only session that's guaranteed. If they never show up for Session 2, this has to be enough to make PostHog stick. Every topic here maps to the most-visited pages in our docs.
Topics to cover
Intro to PostHog (5 min)
We want to jump into the product as quickly as possible – keep this brief. It's not a sales pitch but rather an overview of the platform and why it can help product engineers build more successful products.
Avoid talking through the individual products at this point. It's better to show them.
Make sure everyone is able to sign into PostHog.
The data model (10 min)
Events
Start on the Activity page and explain that Events are the backbone of how PostHog works. Differentiate between autocapture and custom events. Open an event to show that it has properties.
Quick note on frontend vs. backend capture. Backend is more reliable. Frontend captures richer interaction data. Both have a place.
Ask PostHog AI "What are the most common events in this project?". This will orient the room and let them see PostHog AI can access and understand their events.
Persons and properties
Show the difference between identified and anonymous users. Explain how identify() stitches anonymous and known users together.
Show them a person profile and what lives there. Point out what person properties are and give examples of useful ones in the customer's context.
Cohorts
Build one live using PostHog AI: "users who signed up in the last seven days" or whatever matches their product. Give real examples of other useful cohorts they may want to explore (e.g. power users, early adopters, likely to churn, etc.)
Explain that cohorts can be automatically updated and are reusable across different parts of PostHog. Create cohorts to learn from the behaviors of specific groups of users.
Pause for questions. Allow for some awkward silence.
Building insights (15 min)
The core of the session. Don't teach insight types in the abstract. Build them around a real question from the pre-session prep.
Trends
"How many users signed up this week vs. last week?"
Show total count, unique users, breakdown by property, and aggregation of property values.
Flip through visualizations: line, bar, number. Same data tells different stories depending on the display.
Funnels
"Where are users dropping off in our onboarding flow?"
Build a three- to four-step funnel from their actual events.
Show conversion rate, the drop-off step, how to click into the users who dropped off, and tie it back to cohorts.
If the data supports it, show correlation analysis. ("Users with property X convert 2x better.")
For smaller audiences (~10 people), encourage attendees to build an insight themselves by prompting PostHog AI or clicking through the UI. Try: "Show me a funnel from page_view to sign_up to first_project_created in the last 30 days." For larger groups, this gets chaotic – demo it yourself and save the hands-on exercise for Session Replay.
Session Replay (15 min)
Connect Session Replay to the funnel you built. Show the numbers, then show the human behind the numbers.
Mention the filters: by event, by person property, by error, feature flag, rage clicks, console logs. Plant the seed that PostHog products all work well together.
Show how to create and save a playlist.
Ask the audience to build a Session Replay filter using PostHog AI or the UI.
End this portion of the training by explaining AI session summaries. Show the real example from your prep work.
Dashboards (10 min)
Take the insights you built and save them to the starter kit dashboard.
Show sharing, date range controls, and pinning.
Mention dashboard templates for teams that want something pre-built.
Show subscriptions: schedule a weekly dashboard email to their team. (Single best way to keep PostHog in people's inboxes without any TAM effort.)
Quick overview of what else exists (5 min)
Don't demo any of these. Name them so the room knows what's available and that they're tied to events.
Feature Flags and Experiments, including no-code web experiments (product + eng)
Change your app and see the impact on Product Analytics data
Web Analytics dashboard (marketing)
Understand who is visiting your site, where they're coming from, whether they're converting, and if they become active users
Surveys (product + marketing)
Collect qualitative feedback by triggering in-app surveys based on user actions
AI Observability (teams building AI features)
Understand how people are interacting with your LLM-based features
Error Tracking and Logs (engineering)
Capture errors as events so that you can see how exceptions are influencing user behavior
Data Warehouse and SQL editor (data / power users)
Query other data, such as prod dbs or Stripe transactions, alongside your Product Analytics data
MCP server (engineering teams using AI coding tools)
CDP & Workflows
Q&A (15 min)
Open floor. If nobody asks any questions, mention some of the below examples as commonly asked questions. This may make people feel more comfortable.
"How do I filter out internal users?" – Point to the tutorial. Top-10 docs page for a reason.
"What's the difference between Web Analytics and Product Analytics?" – Web Analytics is the pre-built dashboard for high-level metrics. Product Analytics enables custom insights for deeper questions.
"Can I share this with people who don't have PostHog access?" – Yes. Subscriptions, embeds, PNG exports.
"Is it possible to group related events and analyze them as one?"
"Do I need to involve engineering every time I want to track a new event?"
After Session 1
Drop a screenshot and a link of the dashboard into the shared Slack channel within 24 hours. Tag the team lead.
Send a follow-up with links to the three or four most relevant docs or tutorials based on what came up in Q&A.
Send the MCP setup and share a Loom video of accessing PostHog data from Claude or ChatGPT.
---
Session 2: Pick your track
Duration - 60 minutes (40 min content, 15 min Q&A, five min buffer).
Offered as two tracks. The customer picks one, or runs both if they have the headcount. Schedule it two to four days after Session 1.
Session 2 is optional. Hype it up, but don't treat it as a dealbreaker. If a customer only does Session 1, they're still in solid shape.
Track A: Product + engineering
Audience - PMs, engineers, data scientists. Anyone who ships features.
Deliverable - A live feature flag targeting a real user segment, plus a draft experiment with a defined hypothesis.
Feature Flags (15 min)
The gateway to Experiments. Nail this first.
Create a flag together targeting a real segment (beta users, a specific country, a percentage rollout).
Walk through the lifecycle: create, roll out to X%, check analytics, roll to 100% or kill it.
Briefly cover multivariate flags, payloads, early access feature management.
For engineering-heavy rooms: mention local evaluation and bootstrapping. These are top docs pages because engineers want flags that resolve fast on the client.
Experiments (10 min)
Start from a hypothesis, not a feature. Ask the room: "What's something you're debating shipping right now?"
Set up a draft experiment: hypothesis, primary metric (a funnel or trend), control and test variant.
Walk through how to read results. When to call it. Use a real experiment with good data.
Mention no-code web experiments for quick wins that don't need eng work.
AI Observability (10 min)
Big for any team building AI features. Clustering in particular can provide insights that are otherwise hard to come by.
Show what gets captured automatically: conversations, token usage, cost per model, latency, error rates.
Walk through a generation: input, output, tokens, cost.
Show traces for multi-step LLM workflows.
Connect it to Session Replay: "here's the replay of a user interacting with your AI feature, alongside the trace."
If they're not building AI features, skip this. Spend the time on Feature Flags and Experiments instead.
MCP
Make sure everyone who wants to use the MCP server has either set it up already or knows where to find the docs.
Ask for a volunteer to try using MCP to create a feature flag. "Create a feature flag called 'new-checkout-flow' with 20% rollout targeting users in the US." For teams already using AI coding tools, this will probably be the single biggest takeaway from the entire training.
Bonus topics if time allows
Group analytics - Account-level analysis for B2B products (setting up groups, group properties, group-based flags). This is the most important bonus topic for B2B customers – if the customer sells to businesses rather than consumers, prioritize this over the others.
Web vitals: page load performance. (Matters for SEO, matters for ad spend efficiency.)
Clarify the relationship with Product Analytics: Web Analytics is aggregate and pre-built, Product Analytics is custom and user-level. Same data, different lenses.
Advanced funnels for marketing (10 min)
Build on what they learned in Session 1, applied to marketing use cases.
Funnel from landing page visit to signup (or whatever their conversion event is).
Break down by UTM source to show which channels convert best.
Correlation analysis: what properties predict conversion?
Time-to-convert: how long from first visit to signup?
PostHog AI moment – "why are users dropping off between step 2 and 3?"
Surveys (7 min)
Create a popover survey targeting a real page or user segment.
Targeting options: URL, user properties, event triggers, device type.
Filter replays to users from a specific traffic source or landing page.
Show rage clicks and dead clicks on key conversion pages.
"Watch three replays of users who hit your pricing page but didn't sign up" is a strong closer for marketing audiences.
Workflows (3 min)
Reach out to users at the right time based on their behavior.
Show templates.
After Session 2
Follow up on any unanswered questions. Share docs to anything that piqued their interest.
Reach out to anyone that was invited but didn't join. Share some of the most interesting learning / Q&A topics.
---
Engagement tips
For the "too busy" crowd
Offer a 15-minute micro session. If someone reschedules twice, don't push. Offer to screenshare and build one thing while they watch. Low commitment, high value. Most people who do a micro session rebook the full one.
For $80k+ customers who are in-office – pitch a half-day onsite. Frame it as "we'll sit with your team and build your analytics stack together." Informal one-on-one time at someone's desk is worth 3x a scheduled Zoom.
Gather feedback with Surveys
Set up a PostHog survey targeting training participants after each session. This does two things: it collects real feedback on the training, and it shows attendees a live example of Surveys in action on themselves. Good dog-fooding moment.
Every single SaaS platform or tool you use generates data. Payments in Stripe, customers in the CRM, and app data in a production database. That data could be used to ask questions that will help you improve your product, learn more about customers.
Some questions customers might have:
| Question | Data it needs | |----------|---------------| | Which features drive revenue? | PostHog Events + Stripe | | Which accounts are ready to upsell? | PostHog Usage + Stripe plans | | What do customers do right before they cancel? | PostHog Events + Stripe/Chargebee | | Do support tickets predict churn? | PostHog Usage + Zendesk/Intercom | | Which leads deserve the sales team's time? | PostHog Usage + Hubspot/Salesforce | | Which channels bring customers that stick? | PostHog Events + Stripe + Meta Ads |
The modern data stack, at a glance
So many tools to ask a simple question:
Sources – where data is born
Ingestion – move it in to
Storage – the warehouse
Modeling – clean & shape it so it's accurate
Orchestration – keep it running
BI – analyze it
Activation – push it back out
So what's wrong with normal?
A traditional stack is six or more separate tools, each with its own bill, login, and pipelines between them all to maintain.
Product data usually lives in a completely separate world from business data.
Fragmented: Multiple vendors to buy, learn and connect.
Expensive: Per-tool pricing stacks up quickly.
Maintenance: Pipelines need to be maintained between everything
Traditionally, a different vendor for every step
| Step | Traditional tool | |------|------------------| | 1. Sources | Sources are your own, no one to replace. | | 2. Ingestion | Fivetran, Airbyte, Portable | | 3. Storage | Snowflake, Redshift, BigQuery, Databricks | | 4. Modeling | dbt, sqlmesh | | 5. Orchestration | Airflow, Dagster | | 6. BI | Looker, Hex, Tableau, Metabase | | 7. Activation | Hightouch Segment, RudderStack|
Product analytics is usually your biggest data source so most of your data is already in PostHog, if customers use our full stack you don't have to export that data anywhere.
PostHog collapses the stack
Instead of assembling multiple tools, PostHog brings the layers into one platform.
The context warehouse = your events and your business data, together and queryable under one roof.
First data tool – Connect Stripe: Revenue data, joined to product events. Having Stripe synced signals that a user has customers!
Step 2 – Ask PostHog AI: Questions about their data, joining together PostHog events and external data
Step 3 – Build a dashboard: Revenue + product in one saved view
Step 4 – Provision a warehouse: A user reaches a volume of warehouse to need a dedicated warehouse (10k+ Event rows)
Long term – Model & scale: Once you have a warehouse, it needs modeling to keep the data usable and build better dashboard
This runs from an early-stage start-up through to a more mature company with a first data hire.
What's special about a context warehouse?
Definition: A context warehouse is data storage and tooling, optimized for agents as the consumer.
What we mean by "context": We give agents the context to understand things like customers or feature flags, so they can interpret data correctly.
What we mean by "data storage and tools": Ingestion, modeling, endpoints, and the rest of the data stack are all part of your context warehouse. No data pipelines to build and maintain.
What we mean by "optimized for agents": Context warehouses feed the self-driving loop: agents interpret and act on the data.
What a context warehouse is not:
Just business and product data combined. You can already do this with any warehouse by setting up batch exports to pull your product data out of PostHog.
Just an AI tool bolted onto a warehouse for querying your data, most warehouses already have those.
How to talk about context warehouse vs data stack
Companies talk about a "data stack" like a "tech stack." We sell the whole stack, all-in-one but you can bring your own tools if you like, and we're optimized for agents.
| The traditional data stack – humans interpret & act | The context warehouse – agents interpret & act | |-----------------------------------------------------|------------------------------------------------| | Assembled from many separate tools | One all-in-one stack, bring your own tools if you want | | You build and maintain the pipelines between them | Ingestion, storage, modeling, and intelligence | | Built for humans to query, dashboard by dashboard | Agents get the context to know what a customer or feature flag is | | People read the data, then decide what to do | Query in natural language or using SQL | | Optimized for analysts | Optimized for agents as the consumer |
Who the context warehouse is for
It's our ICP, but more data focused.
Primary persona · today: Product engineers
Engineering-led startups that want to run their own data before they hire a data team.
Seed–Series B · 15–500 people · no data hire yet
Cares about
Open source, data ownership, transparency
Developer-first tools, speed to value
Self-serve over sales calls
Frustrated by
Enterprise analytics tools too expensive
Five disconnected tools and data silos
Hidden pricing and sales friction
Secondary persona · next: Data Lead
The first data hire at a growing PostHog customer will usually be a generalist who can build infrastructure and query it.
Series A–C · solo data team · already on PostHog
Cares about
SQL-first tools, no black boxes
Clean models, reproducibility, good docs
Peer validation over marketing claims
Frustrated by
Babysitting pipelines instead of analyzing
Context-switching across siloed tools
Inheriting a messy, undocumented stack
Not yet: data scientists. They're a company's second data hire. Most of our customers don't have data scientists, and our modeling tools aren't mature yet. Once we have a product that can compete with dbt, we can start targeting data scientists.
Why are we targeting these groups
Product engineers: We want to educate this user so that they adopt our products and build data foundations, including setting up warehouse sources, before hiring a dedicated data person…
Data leads: …so that when this person gets hired, the stack that already exists is PostHog, and they will give us a shot instead of churning to tools that are more established
How to talk to them
Start with treating them like a human being.
Product engineers
Primary message
"Ship features faster and understand users deeply without needing to hire a data person straight away"
Why they'll care
They can do complex data analysis that would traditionally require a data team
"It just works" - it's already there in PostHog, no additional tools, cost or setup
Lead with
Are there deeper analytics problems you would solve if you had a data team?
Would having access to additional data (ie payment data) change the way you measure product decisions?
Data leads
Primary message
"Stop maintaining the stack. Start doing the work."
Why they'll care
They can focus on providing trusted semantic layer instead of maintaining the data movement
All internal teams can report on the same data
Lead with
Do most of your data consumers know exactly what data they need to be building on - what is an order? How do we calculate revenue?
Do you have a problem with internal teams reporting similar metrics out of multiple tools? With varying values?
Acronyms, decoded
An appendix of sorts.
| Acronym | Meaning | What it is | |---------|---------|------------| | ETL | Extract, Transform, Load | Pull data out from the source, clean it, then load it into your warehouse. | | ELT | Extract, Load, Transform | Load raw to the warehouse first, clean it once it's there. The modern default. | | CDC | Change Data Capture | Live updates only the data that is new or changed to your warehouse | | OLTP | Online Transaction Processing | The database that runs your app. Fast, one row at a time. | | OLAP | Online Analytical Processing | The database built for analytics. Slower, millions of rows at once. | | SQL | Structured Query Language | The coding language you use to ask a database questions. | | BI | Business Intelligence | Dashboards and reports built on top of your data. | | CDP | Customer Data Platform | Unifies customer data and pushes it to your other tools. | | Reverse ETL | – | Send modeled warehouse data back out into apps so it's up to date and enriched in tools like Salesforce. | | DAG | Directed Acyclic Graph | A map of the order modeling tasks need to run in |
How to evaluate an account's revenue growth potential
We don't have an automated "growth score" for expansion potential, and we probably won't for a while. The signals that matter most are human-judged (depth of buy-in, roadmap fit, whether the champion actually has budget authority) and they don't live in our data. They're hard to represent even heuristically.
So instead of a model, we have a shared framework. The goal is that two people looking at the same account land in the same ballpark. Your assessment should be reproducible by a teammate, not by a query.
Answer three questions, in order. Calling your own shot matters, but the shot has to be grounded in reality rather than wishful thinking.
Is there an expansion opportunity with this account at all?
What specifically is the opportunity?
How much is it worth, and how confident are you?
---
Question 1: Is there an opportunity?
You're looking for headroom: the gap between what the account spends today and what a fully-adopted version of this account would spend. Headroom shows up in a few different places, and most accounts only have it in one or two of them.
Don't size it yet. But answering this question with a "yes" implies the opportunity is meaningful. Don't keep an account just because you like the people. (They're probably great)
Where headroom comes from
Most accounts won't have all four of these. One or two is normal.
1. Use case gaps. Map their paid products against the use case framework. Which use cases are they in? Which applicable use cases are untouched? A B2C mobile app has no Group Analytics story. A company with no AI features has no LLM analytics story. Only count use cases that plausibly map to who the company actually is externally, not everything that's technically possible. This is a big reason a heuristic model fails here, because it needs the human context to make that call.
2. Workloads. How many apps, products, environments, or business units do they have, and how many are instrumented? One workload fully instrumented at a company with a single product surface is largely saturated. Three business units globally with only one instrumented is an expansion lever. If you don't know the answer and you often can't get it from LinkedIn or enrichment data alone, that's not a "no" necessarily, it means you need more discovery.
3. Free-tier usage below the paid threshold. Someone may be experimenting with a product area, which is a warm-intent signal. Sometimes a billing spike is just someone clicking around who turned something on by accident. Sometimes they're partway through instrumenting it properly. Either way it's worth a check-in: at best it's warm intent, and even if it's accidental it's a chance to get them right-sized. Their attention is worth having regardless.
4. Commercial levers. The easiest to name and size. Credit conversions, renewals, and mapping org size and use-case fit to add-on packages.
The saturation checks
Equally important: know when there's nothing there. An account is saturated when most of the following are true. One on its own doesn't count for much.
All applicable use cases are at meaningful spend and actually leveraged by the customer
Single workload, fully instrumented, and no other workloads exist
The champion has told you directly there's no roadmap for more ("we're happy, nothing planned") This is weak on its own, so pair it with other indicators. It can also just mean you need a new champion, which is context dependent. At a small company there's no point sidestepping them, they likely know the full truth. At a medium-to-large company it's worth trying to connect with other people and create new champions
Usage has been flat or declining for 2+ quarters
The last two expansion conversations went nowhere, and not for any of the "check back later and nurture for now" reasons — timing wasn't right, no discernible reason, other blockers, external company factors, and the like
Price sensitivity is the dominant theme of every conversation
A TAM being willing to let go of an account is itself a saturation signal, since TAMs are incentivized to maximize their book outcome. But don't take that at face value either.
Saturated is not a bad thing. Quite the opposite. It's a healthy, retained customer who is bought into PostHog at an organizational level. For our purposes here it just means the account doesn't require a TAM. The worst outcome of this exercise is inventing an opportunity to justify keeping an account.
---
Question 2: What is the opportunity?
What's the growth lever? "This account can grow" is not an answer. "They're on monthly billing at $1.8k MRR and their platform team is trialing Error Tracking" is an answer. Most real opportunities group into one of these mechanisms:
| Lever | What it looks like | Where to go deeper | | --- | --- | --- | | Cross-sell (same team) | 1-2 products adopted, gaps in their current use case | Go deeper, cross-sell motions | | New team / workload | Multiple teams or apps, only one instrumented | Expand into new teams | | Event-based add-ons | High event volume, no Identified Events / Group Analytics / Pipelines | Pricing, plus the math below | | Platform package | >50 people, compliance/SSO/RBAC needs, no Boost/Scale/Enterprise | Contract rules | | Annual conversion / renewal uplift | Monthly billing >$500 MRR, or credit expiry approaching | How commission works | | Organic usage growth | Forecasted MRR > current MRR, headcount growth, recent funding | Nothing to sell, but it's incremental cash you should forecast |
Two guiding principles:
One primary lever per account per quarter. Track several if you like, but your account plan should say which one you're actually focused on right now.
The lever must attach to a person. "They should adopt Session Replay" is a product observation. "Rui's team spends hours reproducing bugs from user reports, and Rui has budget authority" is an opportunity. Opportunities don't happen without people on both sides. If you can't name who buys it and why they'd care, you're still on Question 1.
---
Question 3: How much, and how confident are you?
There's no formula. There is a small set of evidence sources you can reliably build an estimate from, plus a discipline of writing down how you got the number so someone else can challenge it.
Build every estimate from real evidence
1. Their own volumes against list pricing. When the opportunity is usage-priced against data they're already sending, this is mostly arithmetic. Event-based add-ons are straightforward and you can calculate them in QuoteHog.
2. What they've told you. Their current vendor's contract price, their company or product roadmap, their team sizes, their budget cycle. Most estimation problems are actually discovery problems: if you can't size the opportunity, the next step is getting the information that would let you. "What are you paying Sentry today?" and "how much traffic does the other product do?" are sizing questions.
3. Comparable accounts in your own book. You have direct visibility into what accounts of similar size, archetype, and vertical spend on the product you're pitching. This is never 1:1, though similar companies still differ in org structure, product surface area, and how saturated they are across PostHog.
4. Bottoms-up from their product. For a new workload or team, estimate from what you know about that workload: public traffic, app store presence, team size, and how the equivalent metric compares to the workloads they've already instrumented.
---
Grow, nurture, or release
Grow — there's a real, qualified expansion opportunity. This account gets proactive TAM work this quarter.
Nurture — a real opportunity that isn't workable yet, because it's waiting on a funding event, a champion hire, or a roadmap item. If it's already a TAM account, it's fine to keep. If it isn't, it can wait for a TAM to be assigned.
Release from TAM — healthy and retained, but no viable growth. Drop it from TAM coverage per the quarterly book planning rules. This is a good outcome: it concentrates TAM attention where it compounds.
As a Technical Account Manager, you'll spend as much time managing your existing book of business as you will closing product-led leads. Your first priority is retaining them - this is counter balanced to an upwards Land, Expand, Retain motion. We have to work twice as hard if we're trying to close new deals and make up for lost customers. You'll typically be assigned a bunch of customers who are paying monthly - this means they could turn off PostHog at any time.
Once you're confident that a customer isn't going anywhere, then you want to think about how you can expand their usage. Usually (but not always) this is after they've signed an prepaid credit contract.
In order of priority, your objectives should be following all points of "REREE":
Retention - establish multiple strong lines of communication
Expansion - cross-sell additional products
Retention - secure a discounted, credit-based commitment (maybe, but not always - hard to do on just a single product!)
Expansion - expand usage of the same product into new teams
Expansion - expand usage of the same product in the same team
The reason why we put cross-sell so high up the list is that we have seen that by _far_ the happiest and best-retained PostHog users, including from a revenue retention perspective, are those who have adopted 2+ products. It makes sense - it's relatively straightforward to replace PostHog if you're just using product analytics, but it's much tougher if you're using analytics + experiments + session replay.
Once you've established contact, you basically want to get them into the same flow as if they were a new customer (and give them the same level of attention). You will be doing a combo of discovery and commercial evaluation, as the customer will want to figure out whether a prepaid credit contract with PostHog makes sense vs. what they've already got.
Do not push for discounted, credit-based plan no matter what - consider what actually makes sense here! Some customers are very highly likely to stick with PostHog even if they are paying monthly, e.g. if they have many users regularly logging in, lots of product activity, multi-product adoption etc. Do not turn up to a new customer and the first thing they hear from you be 'would you like to pre-purchase credits?'
You'll also go through the same contracting process with them. We usually find that convincing a customer happily paying monthly to switch to prepaid credits is quite difficult, especially if they are a fast-growing startup (who tend to value flexibility over pure cost saving). This means that the discounts may not be as effective. If you're finding this is the case, you can get them on an prepaid credit plan but paying monthly or quarterly and halve the discount you offer.
Steady state retention
These are customers that are happily using PostHog long term, and are neither a churn risk nor likely to have expansion potential. Managing this group is much more automated and taken care of by CSMs, who do things like tracking usage and setting up alerts in Vitally to trigger outreach from us when a customer changes their usage behavior (either up or down).
An important part of retention here is also to ensure support issues are fixed in a timely manner. We deliberately don't want to invest a huge amount in hands-on customer success here, because that can often paper over cracks in the product experience or quality of our customer support, so staying hands-off here is an intentional strategy. In the future, we will build out this playbook a lot more.
Expansion & cross-sell
Note: AEs and CSMs also do expansion at PostHog therefore this is not a Product-Led Sales TAM only approach. This is because we all are constantly on a sales footing with customers - for the most part, we don't do steady state account management with an arbitrary 10% uplift at renewal team.
An overview of how to drive expansion with a customer can be found in the cross-selling pages.
Principles for visiting customers
If you offer to do a meeting in person with a customer, they’ll then feel obliged to introduce you to other people to make good use of your time. Trying to get them to adopt more products can be a good trigger, but generally you should be matching the cadence for in-person meetings with the size of contract (ie. more regular for Very Large, less regular for Large). If necessary you can request a budget for travel and accommodation in Brex.
Generally speaking you should be trying to regularly see customers in your book of business who are $100k+ annually, or could get there. Occasionally you can pull in James/Tim if they are traveling to SF/NY especially, or if the customer is in London.
Make sure to log notes in Vitally when customer visits take place. This can be done by creating a new note with the "On-site" category and describing any key details and takeaways.
The Expansion and Retention page lays out the REREE priority order for managing your book: retain, expand (cross-sell), retain (commit), expand (new teams), expand (same team). The cross-sell motions page tells you what to sell. The use-case-selling playbooks tell you how to frame it. This page covers the layer underneath: how you structurally grow an account.
Not every account grows the same way. A 30-person startup with one engineering team is a completely different expansion motion than a 500-person company with four business units. You need to pick the right approach for the account you're working with, and sometimes run multiple strategies in parallel.
These four strategies are not mutually exclusive. Most accounts will involve a combination over time. But being deliberate about which one you're running right now, on this account, this quarter, makes it much easier to focus your effort and measure progress.
Overview
| Strategy | Core idea | Best for | |----------|-----------|----------| | Go deeper | Layer more products onto the team already using PostHog | Accounts with 1-2 products adopted, strong engagement, same team | | Build champions | Grow usage and advocacy from individual power users up | Accounts where you lack executive access, or where adoption is engineer-driven | | Expand into new teams | Replicate PostHog usage in a different team or business unit | Larger orgs with multiple engineering teams, product lines, or workloads | | Move upward | Engage leadership to drive org-wide adoption or commitment | Accounts with strong bottom-up usage ready for credit purchase or org-wide rollout |
Strategy 1: Go deeper on the existing team
The team already uses Product Analytics. You help them adopt Session Replay, then Experiments, then Error Tracking. Same people, same workload, more products.
When to use it
Account has strong engagement but low product count (1-2 paid products)
Your champion is receptive and has the ability to try new things without heavy approvals
The team's workflows have natural gaps that other PostHog products fill
How to execute
Review their current product adoption against the use-case-selling framework. Identify which use case they're closest to completing and what product fills the next gap.
Tie the recommendation to something they've already told you. "You mentioned spending time reproducing bugs from user reports — Session Replay shows you exactly what happened" is better than "you should try Session Replay."
Offer a trial incentive if needed. 2-3 months of credited usage for a new product removes the risk for them. See trial/evaluation incentives.
Follow up with hands-on help. Don't just suggest the product — help them set it up, build their first dashboard or workflow, and show value in week one. A product training session can accelerate adoption if the team is large enough to justify it.
Signals that it's working
New product shows up in their billing within 30 days
Champion starts referencing the new product in conversations unprompted
Usage is sustained (not a one-time spike)
Common mistakes
Pitching products the team has no use for just to hit a product count target. If they don't need Surveys, don't push Surveys.
Suggesting too many products at once. Pick the one with the highest likelihood of adoption and land that first.
Not following up after the initial setup. Products adopted without guidance often get abandoned.
Each additional product above 1 adds 0.2x to the quota multiplier (from a 0.7x base). Going from 1 to 3 paid products moves the multiplier from 0.7x to 1.1x on the same ARR. This is the most direct way to improve your quota math.
Strategy 2: Build champions from the bottom up
You identify 2-3 power users inside the account who are getting serious value from PostHog, and you invest in making them successful. They become your internal advocates, and their enthusiasm pulls in more users and more products organically.
When to use it
You don't have (or can't get) executive access
The account is engineer-driven and decisions happen bottoms-up
There are individual users who are clearly engaged but haven't been given direct attention
Early-stage companies where the "champion" might be a founding engineer or product-minded CTO
How to execute
Identify power users. Check who's logging in most frequently, who's creating dashboards and insights, who's asking questions in your Slack channel. These are your champions, whether they know it yet or not. If you're struggling to make initial contact, the getting people to talk to you playbook has specific tactics.
Invest in them directly. Share tips specific to what they're building. Point them at features they haven't found yet. Help them build something impressive they can show their team. The goal is to make them look like heroes internally.
Equip them to sell internally. When your champion wants to bring in Session Replay for their team, give them the ammunition: a short summary of what it does, rough cost estimate, and how to pitch it to their manager. The cross-sell motions page has product-specific discovery questions and value stories you can adapt for this.
Ask for introductions. Once you've built trust, ask your champion to introduce you to other people in the org. "Are there other teams that might find this useful?" is a low-pressure way to open the door to multi-team expansion.
Signals that it's working
Your champion starts CC'ing or introducing colleagues
New users from the account start showing up in PostHog
Your champion brings problems to you proactively rather than waiting for you to reach out
Common mistakes
Over-relying on a single champion. If your one contact leaves, you lose the account. Always work toward having at least 2-3 relationships.
Treating champion building as a substitute for commercial conversations. Champions are great, but at some point someone needs to talk about contracts and commitments. Don't avoid that conversation forever.
Ignoring quiet power users. The person creating 20 dashboards a week but never responding to your messages is still a champion — they're just not talking to you yet.
Strategy 3: Expand into new teams
Engineering Team A uses PostHog for product analytics. You get introduced to Engineering Team B (different product line, different business unit, different workload) and replicate the adoption. Same org, net new usage.
When to use it
The org has multiple engineering teams, product lines, or business units
Your existing team's usage is mature and there's limited room to grow with them alone
You've identified (or your champion has mentioned) other teams with relevant use cases
The account is at a stage where workload expansion is the primary growth lever (typically $60k+ ARR)
How to execute
Map the org. During discovery with your existing contacts, ask: "How many products or apps does your company maintain?" and "Which teams have their own engineering org?" Each product/app is a potential new workload. Your account plan should explicitly document known workloads and which teams own them.
Get a warm introduction. Cold outreach to a new team inside an existing account almost never works. Ask your champion to introduce you, or use in-person visits (people feel obligated to introduce you to others when you're physically there).
Treat the new team like a new customer. They have different needs, different stakeholders, different technical contexts. Don't assume that what worked for Team A will work for Team B. Run fresh discovery and consider offering a training session to get the new team up to speed.
Start with the use case that fits, not the product the other team uses. Team A might use Product Analytics heavily, but Team B might need Error Tracking first. Let the use-case-selling framework guide the conversation.
Signals that it's working
New projects created in the PostHog org for the new team's workload
Event volume from new sources (different SDKs, different domains, different app identifiers)
New admin users from a different team or department
Common mistakes
Assuming the new team has the same priorities as the existing one. They probably don't.
Trying to expand into new teams when the existing team's implementation is shaky. If Team A is unhappy or poorly set up, they'll warn Team B off.
Not involving your champion in the introduction. Going around your existing contacts to reach new teams damages trust.
New team adoption is often the biggest single expansion lever in larger accounts. A new workload can mean an entirely new use case stack, which adds both ARR and product multiplier simultaneously.
Strategy 4: Move upward through stakeholders
You've built strong usage and advocacy at the IC and team lead level. Now you engage a VP Engineering, CTO, or Head of Product to drive an org-wide commitment: annual contract, standardization on PostHog, top-down mandate to adopt across teams.
The account is large enough that an org-wide deal is meaningful ($60k+ ARR potential)
You have evidence of value you can present to leadership (usage data, time saved, problems solved)
There's a commercial event on the horizon (contract renewal, budget cycle, new fiscal year)
How to execute
Build the business case before you ask for the meeting. Pull together usage data, product adoption, number of active users, and any concrete outcomes your champions have shared. Leadership doesn't care that Session Replay is cool. They care that it reduced bug reproduction time by 50% and saved 10 engineering hours a week.
Get introduced, don't cold-call. Ask your champion to set up the meeting. "Would it make sense to loop in [VP] so we can talk about how PostHog fits into the broader engineering org?" Your champion's internal credibility is what opens the door.
Frame the conversation around their priorities, not yours. Leadership cares about consolidation (fewer vendors, fewer contracts), cost predictability (annual plan vs. monthly surprises), and organizational efficiency (one platform for all teams vs. five point solutions). Lead with those.
Have a specific commercial proposal ready. Don't go in with "we should do an annual deal." Go in with "based on your current usage of $X/month across these teams, here's what an annual commitment would look like, including the discount and what that saves you." See contract rules for discount structures, and remember that even after an annual deal is signed, additional usage beyond the annual run rate still counts toward your quota.
Use the meeting to also open multi-team expansion. "Are there other teams that should be using PostHog but aren't?" is a natural question when you're talking to someone with org-wide visibility.
Signals that it's working
Leadership agrees to a meeting and brings relevant people
Conversations shift from "should we keep using PostHog" to "how do we roll this out more broadly"
Procurement or finance gets involved (this is a good sign, even if it slows things down)
Common mistakes
Going over your champion's head without their knowledge. This destroys trust and usually backfires.
Trying to go upward before you have bottom-up proof. If leadership asks "do our teams actually use this?" and the answer is weak, you've wasted the meeting and it's very hard to get a second one.
Treating the executive meeting as a product demo. Executives don't want a tour of features. They want to understand business impact and cost.
Moving upward too early in the relationship. If you're still establishing trust with the IC team, forcing an executive conversation feels pushy and premature.
Choosing the right strategy
There's no formula here, but some patterns hold:
| Account situation | Start with | |-------------------|------------| | Small team, 1-2 products, strong engagement | Go deeper | | Low executive access, engineer-driven org | Build champions | | Large org, multiple teams or products | Expand into new teams | | Strong bottom-up usage, approaching renewal or budget cycle | Move upward | | New account, first 90 days | Go deeper (always start here) |
For most accounts under $40k ARR with a single team, go deeper is the right default. You're adding products to the team that's already bought in.
For accounts over $60k ARR with multiple teams, expand into new teams is usually where the biggest growth lives. You can only go so deep with one team before you hit a ceiling.
Build champions and move upward are not standalone strategies — they're how you enable the other two. You build champions so they can pull you into new teams. You move upward so leadership can mandate adoption across the org. They're force multipliers, not end goals.
The best TAMs are running 2-3 of these in parallel on their largest accounts. One team is going deeper on products. A champion in that team is introducing you to another team. And you're building toward an executive conversation that ties it all together into an annual commitment.
Product engineers, our ICP, are very self-serve and happy to implement PostHog themselves and read the docs without ever interacting with someone unless they have support queries.
Why is it helpful for someone to talk to you?
The reasons have to be _genuinely helpful_ ones - just 'having a point of contact' is not enough. Reasons include:
You can save them money:
They've implemented PostHog in a silly way and are consuming stuff they don't need
They can pre-commit and get a discount on credit
You can help them get more out of PostHog for the same amount of money, e.g. if they're ingesting loads of events but not using features to their fullest
You can train their team on how to use PostHog, so they don't have to
You can make them aware of upcoming or new products that are specifically useful for their use case
You can be a shortcut to premium support, if they are in your book of business
If you go down the 'saving money' route, bear in mind two things:
Prepaid credit never works as an opener - 'save money by fixing implementation' >>> 'save money by committing to credit at a discount'
Buying a bunch of credits at a nice discount is much nicer to hear than 'please commit to a scary annual plan' - they can commit for a year, 6 months, whatever so long as they buy >$20k up front
How to get people to talk to you
This is usually the most difficult bit! Sometimes customers will proactively reach out to us because they see their bill rocketing, but we have many customers who have happily self-served to a very high level of spend without feeling any need to talk to us. In particular, engineers have no interest in jumping on a call with you 99% of the time.
Offer to optimize their usage/reduce their billing - if they are pointlessly tracking a bunch of junk, tell them! Otherwise they'll just find out themselves and churn anyway.
Tell them about new or upcoming features or products that they may not be aware of which you know could be a great fit for them (and let them try them out for free).
Use multiple channels - email is usually the worst way to reach our ICP. Slack, in-app Surveys or even Telegram are all usually better. But try email first anyway.
Ping everyone in the account individually (don't do group, no one will reply) - start with the most active users first. New users are also good.
Loom videos sharing your observations about their usage/account provide a personalized and human touch which can go a long way to building lasting relationships. Ask Simon for an invitation to our company account if you don't have access.
Adding the contact on LinkedIn and sending a very human video or audio message can work really well - even for technical people (use the LinkedIn mobile app).
Figure out what the non-technical people in their team need and then go out and talk to them - get someone who isn’t an engineer to talk to us given engineers don’t want to.
If they submit a support request, jump in and respond yourself to try and build a relationship.
Subscribe to your customers' newsletters, set up Google Alerts, use their products and follow their X or Reddit communities. This lets you time your outreach for when they've just shipped something - making it about them, not you. For example, if they just launched an AI feature, you can reach out the next day to the PM or engineer and congratulate them whilst they are energized and then connect it to a PostHog product they might not be using yet that helps them make their new product better.
Ask the wider team for help - we have to get creative here! You'd be surprised how often somebody knows someone...
If you're not succeeding getting through with your champions, engage with "new users" instead – colleagues recently invited into PostHog. Monitor for them via the "new user" segment in Vitally and reach out immediately with an email and Slack invite. New users often accept because they assume the Slack channel is part of their company's PostHog setup. Be helpful, send merch, and when it lands at their office, the rest of the team is much more likely to join the Slack channel (especially when the new user refers them to how helpful you've been).
Find your customer's GitHub – company open source repos or individual engineers' personal projects. Review any open bugs, issues, etc. and submit a real pull request. Extra points if you fix an open bug on their company repo. The customer will see your name somewhere other than their inbox and engage. For important customers, ask our engineering team for help with more complex fixes.
If you're reaching out to a non-English speaking team and getting no response, try writing your message in their language. Use Claude to draft it, or ideally – get a native speaker on your team to help you craft it.
Guest-list your customer to a cool event – a PostHog event, industry meetup, hackathon, etc. – where they can meet potential customers, partners, or peers in their space. You're putting them in front of people who can help their business – and that's a reason to talk to you.
Before you do any of this stuff, get to know your customer as well as you possibly can. Don't do clickbaity things or trick people into talking to you - it'll just annoy them. And definitely don't just offer a generic checkin 'to see how things are going'!
Ideally you want to get multiple people into a shared Slack channel, as we've found this enables the best communication and allows us to provide them with great support. Just adding a bunch people to the Slack channel is also a legit tactic - forgiveness, not permission.
Your first message where we've never had contact
Despite the organization using PostHog, they may not recognize you/PostHog, or may not even be the correct person to talk to about PostHog, which means your message needs to be well crafted.
When crafting a message, consider the following:
Your initial outreach isn't about you, it is about them. Lead with customer-centered comms. Avoid leading with being attached to their account or telling them how you are there to help them. Tim has some great thoughts on this subject.
Avoid fluff. "I'm just reaching out to", "I just wanted to" etc. are empty phrases that take longer to get to the point. Before you hit send, reread and see if there is anything you can cut out.
Lead with value within the first sentence. If it takes a paragraph to get there, you won't get responses.
Ask yourself, if I got this email to the sales@ email box, would I engage it? Would I even give it a second look?
Some examples of good emails that have worked:
Hello [name],
It looks like your Product Analytics usage has increased over the past month and I wanted to ensure that the increase was expected.
Here are some tools you can use to ensure you are collecting the correct events and getting valuable insights from them. We have a whole host of tutorials and guides to help you get the most out of PostHog.
If you have any questions, don't hesitate to ask.
[First],
Wanted to reach out direct since I noticed the [Company] team ramp up usage in PostHog recently.
We'll typically reach out to help with optimizing event capture and make recommendations with regards to instrumentation + querying in PostHog.
Up for a chat? Here's my calendar, feel free to grab a time that works best for you.
Cheers,
Asking for introductions
If you feel like you have done a good job with a customer, and have genuinely been helpful, it's ok to ask for a favor back. You can be specific and ask for a direct introduction to a person you want to talk to, or try go a bit more broad and ask the person if they know anyone who would benefit from some help with PostHog. Either way, a warm introduction from a colleague is always going to be better than reaching out on your own. Something like "Hey Leon, our session last week seemed to have landed well. I'm glad you found it useful. I was wondering if you could help me out. Your team is growing really quickly, and there's a bunch of new folks starting to use PostHog. I imagine not all of them are super comfortable with the platform yet and could use a helping hand. Could you introduce me to Simon, Charles and Scott?"
Just been handed an account?
Sometimes you'll get a customer in your book who was previously working with someone else on the PostHog team. A pre-existing relationship can help, but it's not guaranteed they'll want to talk to you.
We've found a message like this in Slack/email works well after the intro:
Thanks [PostHog team mate]
Hey [customer] :blob-wave: Excited to be working with you! As I take over, it would be a big help if we could schedule a quick 15–20 minutes intro call [link to your Calendly]. Just a chance for me to learn more and figure out how I can best support you going forward. Let me know if you'd be open to that.
We've found most people will respond to this.
Have you been ghosted?
If you've had a conversation with someone, there was interest on their side and then they suddenly go dark, using the John Barrows Ghosting Sequence can revivify them.
After 2 weeks of valuable follow-up and you've not heard back, reply-all to the latest email thread.
Change the subject to: "Still interested?"
And put in the body:
[Name]
Still looking at options like PostHog to solve [business problem they previously acknowledged]?
Let me know either way.
That last line is very important because it gives them a safe option to say "no". About half will respond.
If there's no response again after another week, change the subject again to "Did I lose you?"
Leave the body empty. This will pick up about 80% of people who go dark. If not, close out the opportunity 3 days after this final message.
LinkedIn Sales Nav
To get notified about new hires and other changes to the accounts you manage, you can set up lists of accounts to track in LinkedIn Sales Nav.
Search for an account you want and click on their profile.
Click the star icon on the left, and then choose a list to add them to.
Optional, tailor the notifications you get in LinkedIn
You will now be notified any time a senior hire joins your account, which will be helpful for tracking folks to reach out to and give advanced signals around potential data science hires.
The best PostHog accounts don't look like one team using Product Analytics. They look like an entire engineering organization running releases through Feature Flags, a product team measuring impact with Experiments and Session Replay, a growth team optimizing funnels with Web Analytics and Surveys, an AI team monitoring model performance with LLM Observability, and a data team piping everything into their warehouse with CDP. Multiple teams, multiple products, multiple use cases, all on one platform.
In larger orgs there are more specialized roles and teams, and you may have multiple different teams with the same exact use cases, or more variety across the entire org. In smaller teams, you have hybrid roles and many-hat-wearers, so you'll see a single team or person with multiple use cases.
Either way, the goal is for PostHog to be the platform of choice for as many of those use cases as possible, with buy-in from founders, executives, and senior leadership.
That's the gold standard. In reality, it's not a single motion or playbook but rather a cycle that you repeat as needed until full saturation is achieved.
Start with what brought them here
Every PostHog account starts because someone had a problem (or they love hedgehogs, or someone told them analytics were a must). Maybe a product engineer needed to understand why users dropped off after signup. Maybe an SRE needed error tracking that didn't cost six figures. Maybe a growth engineer wanted to run experiments without standing up a separate tool. Whatever it was, there's a use case that pulled them in. That's the Trojan Hedgehog.
Your first job is to figure out what that use case is. Not what products they're paying for (that's a billing question), but what problem they're trying to solve (that's a relationship question). Start by seeing who the users are by their role/title and then how they're specifically using PostHog. The fastest path is generally just talking to the customer directly.
The use-case selling framework gives you the language for all of this. There are seven use cases documented:
Each maps to a core buyer persona and a set of PostHog products. Each has discovery questions, expansion paths, and competitive positioning.
Look at how they're actually using PostHog. A customer who only uses Product Analytics and Session Replay is living in the Product Intelligence use case. A customer who's heavy on Feature Flags and Error Tracking is living in Release Engineering. A customer sending all their data to Snowflake via Batch Exports is living in Data Infrastructure.
Once you know the use case, you know who the buyer probably is, what they care about, what their unmet needs look like, and where the expansion paths lead. You also know what not to pitch. Trying to sell LLM Observability to a product manager who came to PostHog for funnels is a waste of everyone's time. Showing that same PM how Surveys can answer the "why" behind their funnel drop-offs is solving their actual problem.
Fix the foundation first
A lot of customers are using PostHog wrong. And that's not a them problem, generally speaking.
They self-served the implementation and then nobody reviewed it. They're calling identify() on every page load and inflating their event volume. They have autocapture turned on but haven't defined a single action, so they're paying for events they never look at. They enabled Session Replay with default settings and are recording every bot visit and sub-second bounce. They're paying for Group Analytics but never implemented it. They have no reverse proxy, so ad blockers eat 15-30% of their data.
If you try to cross-sell a customer whose implementation is broken, two things happen. First, they don't trust their data, so they don't trust your recommendations. Second, their bill is higher than it should be, which makes every pricing conversation harder.
Fix the foundation first. Run an implementation health check. Look for the common problems: unnecessary event volume from misconfigured autocapture, inflated identify/group calls, replay capturing everything, missing reverse proxy, no feature flag fallbacks. Then help them fix it.
This feels counterintuitive. You're a TAM with a growth quota, and your first move is to reduce the customer's bill. But this is the single most trust-building thing you can do. When you tell a customer "you're paying $800/month for events you don't need, here's how to fix that," they stop seeing you as a vendor trying to expand their contract and start seeing you as someone who's actually on their side.
We track these "anti-revenue" optimizations internally because we believe they lead to long-term expansion. A customer whose implementation is clean, whose data they trust, and whose bill matches their actual usage is a customer who will say yes when you suggest they try Experiments next quarter.
Nail the first use case
Once the implementation is clean, go hard on their primary use case. That first use case, the problem they came to PostHog for originally, needs to be solidified before you eagerly push a new one. You can always cross-sell in parallel to other teams, but in most cases, it is a better investment to help them absolutely nail the first thing first.
If they came for Product Intelligence, don't immediately pitch Error Tracking. Instead, help them build the dashboards that answer their most important product questions. Help them set up their first experiment. Show them how to filter Session Replay by funnel drop-off so they can see why users leave, not just where. Get their PMs self-serving with PostHog AI. Make PostHog the place where their product decisions get made, not just where data passes through.
If they came for Release Engineering, help them build a proper feature flag workflow. Help them implement gradual rollouts, percentage-based releases, and proper fallback code. Show them how Error Tracking connects to specific flag variants so they can catch regressions instantly. Make PostHog the tool their engineers reach for every time they ship.
The point is to make PostHog indispensable for the thing they already care about. A customer who uses PostHog for one use case casually is at-risk. A customer who can't ship a release without Feature Flags, can't make a product decision without their PostHog dashboards, and can't debug an issue without Session Replay is not going anywhere.
This takes time. It takes multiple conversations, check-ins, training sessions, and sometimes getting on calls with their engineers to work through implementation details. It's not a one-and-done demo. It's a process of embedding PostHog into their workflows until it becomes infrastructure.
Go deeper, then go broader
Once a customer is locked in on their primary use case, two expansion motions open up. These map directly to the expansion strategies: going deeper is Strategy 1 (go deeper on the existing team), and going broader is Strategy 3 (expand into new teams).
Going deeper
Going deeper means continuing to expand within the same use case. It's bringing in more teams and users to adopt the same use case and layering in other products and features to supplement and enhance it.
The use-case playbooks each define a primary expansion path. For Product Intelligence, it's Product Analytics → Session Replay → Surveys → Experiments → Workflows. It's not always going to be in that order, but this is generally a trend that we see and makes sense intuitively. Each step solves a natural next problem: "I can see the drop-off" becomes "I can see why users drop off" becomes "I can ask them directly" becomes "I can test a fix" becomes "I can automate the solution."
Going deeper adds products, but more importantly, each additional product within a use case makes the customer stickier. Replacing one analytics tool is easy. Replacing an analytics + replay + surveys + experiments + workflows stack that's all integrated is a migration nobody wants to do.
Going broader
Going broader means expanding to a new use case with a different team. This is where the real organizational penetration happens. The use-case playbooks all have a cross-sell pathways section that shows how one use case naturally leads to another.
The most common patterns:
Product Intelligence → Release Engineering. The product team is deep in PostHog. Their engineers are already implementing Feature Flags for experiments. Show the engineering team that the same flag infrastructure can power their entire release process. This is a different buyer (engineering manager vs. product manager) with a different problem, but the platform is already there.
Release Engineering → Observability. Engineers are using Feature Flags and Error Tracking for releases. They start noticing that Error Tracking surfaces issues they'd normally find in their logging or APM tool. The pitch writes itself: "You're already catching errors here. Want to see the logs and traces too?"
Product Intelligence → Growth and Marketing. The product team is measuring user behavior. The growth team wants to measure acquisition funnels, run landing page experiments, and track marketing attribution. Same platform, different team.
Any use case → Data Infrastructure. Once multiple teams are in PostHog, someone wants all that data in their warehouse. Data Pipelines and Data Warehouse become relevant not as standalone products but as the connective tissue that makes PostHog the source of truth for product data.
The key insight is that each expansion uses a different entry point with a different champion. The PM who loves Product Analytics is not the person who decides to adopt Feature Flags for the engineering team. You need a new champion for each use case. The existing champion can introduce you (see getting people to talk to you), but the new buyer needs to hear the pitch in their language, tied to their problem.
The expansion cycle
The cycle can be summarized as:
Identify the use case that brought them in (or the next one to pursue).
Fix the implementation for that use case. Clean up billing waste, correct tracking issues, establish data trust.
Go deep on that use case. Make PostHog indispensable for the problem they're solving. Add the natural expansion products.
Find the bridge to the next use case. Look for signals: an engineering team that's already using Feature Flags for experiments, a growth team that keeps asking for funnel data, a support team that watches Session Replays to debug customer issues.
Repeat with the new use case, starting from step 1.
Each cycle adds products, adds users, adds teams, and increases switching cost. The customer goes from "we use PostHog for analytics" to "we use PostHog for everything product and engineering related" one use case at a time.
Not every cycle works. Sometimes the bridge to the next use case doesn't exist yet. The engineering team might already have a deeply embedded feature flag provider and there's no forcing function to switch. That's fine. Work the use cases that have natural pull and don't force expansions that don't make sense for the customer. Forced cross-sells are how you lose trust.
Discount contracts as an expansion tool
Annual prepaid credit agreements (what we call "discount contracts") are not just a billing mechanism. They're one of the most effective tools for accelerating this cycle. See contract rules for discount structures and mechanics.
A customer considering a new PostHog product has two concerns. One, will this actually work for my use case? Two, what will it cost if we go all-in?
A discount contract addresses both. When a customer pre-purchases credits at a volume discount, the marginal cost of trying a new product drops to near zero. They've already committed the spend. Experimenting with LLM Observability or Surveys or Error Tracking doesn't feel like a new line item; it feels like getting more value out of something they've already paid for.
This changes the psychology of cross-selling. Without a discount contract, every new product pitch sounds like "spend more money." With one, it sounds like "use what you've already bought."
When a customer is on monthly billing and has expanded to 2-3 products, the annual contract conversation should lead with the use-case expansion angle, not the discount angle. "You're using Product Analytics and Session Replay today. With an annual commitment, you can experiment with Experiments, Surveys, and Error Tracking at no additional cost up to your credit limit. If those don't stick, you haven't paid extra. If they do, you've just consolidated three more vendors into PostHog."
For customers already on annual contracts who are approaching the credit boundary, the renewal conversation is a natural expansion moment. "You're going to exceed your current credits this quarter. Before we resize, let's look at whether there are new use cases we should plan for. If your engineering team is interested in Feature Flags for releases, we should factor that growth into the new commitment so you get the volume discount on the expanded usage."
This is where the use-case framework and the commercial motion connect. The use-case playbooks tell you what to pitch and when, while the discount contract gives the customer economic permission to try it.
Even after an annual deal is signed, additional usage ARR beyond the annual run rate still counts toward your quota.
When to go for the organizational sell
There's a point in the cycle where the motion shifts from "expand one team at a time" to "make PostHog a platform decision." This maps to Strategy 4: move upward through stakeholders in the expansion strategies page.
TAMs find this step daunting, because it can feel like if it doesn't land, the conversation is over with leadership. This isn't true.
There isn't necessarily a right or wrong time to attempt this, but it should be something on your mind with any account. Here are some conditions you can rely on to strategically time your organizational sell:
Multiple teams actively using PostHog as part of their day-to-day workflow. At minimum, this probably means two distinct teams and two distinct PostHog products.
Multiple products with meaningful spend. The quota multiplier gives you a rough proxy: if a customer is at 1.1x or above (3+ paid products above $200/month), they have enough product breadth that platform consolidation starts to make sense.
An internal advocate with a leadership title who cares about the platform story. If you don't have this and currently only have a user-champion (growth person, PM, senior engineer, etc.), your task is to find the leader who can be the sponsor. This is generally a VP of Engineering, a Head of Product, or a CTO. Someone who sees the value of having one platform for product analytics, experimentation, error tracking, and session replay instead of paying for four separate vendors with four separate contracts, four separate data models, and four separate support channels.
A commercial forcing function. A contract renewal, a budget cycle, a vendor consolidation initiative, a procurement review. Organizational decisions don't happen in a vacuum. They usually need a moment where the decision maker has a reason to evaluate. It's your job to know enough about the customer to know when these things are happening internally.
If all of the above are present, the organizational sell is straightforward: "You already have three teams on PostHog across five products. Here's what it would look like to standardize, including the cost savings from vendor consolidation and the volume discount from a larger annual commitment."
If you're missing one or more, keep working the cycle. Add another team. Add another product. Build another champion. The organizational sell usually happens pretty naturally when those things are aligned, but it is something that you have to actually go out and do.
What this looks like in practice
An idealized trajectory (each account is different, but the shape is common):
Trojan Hog phase
Identify the primary use case. Run an implementation health check. Fix billing waste and tracking issues. Build trust by saving them money and improving their data quality. Get the first use case working properly.
Depth phase
Expand within the primary use case. Add 1-2 products along the natural expansion path defined in the relevant use-case playbook. Get 5+ active users in PostHog from the first team. Identify potential champions on adjacent teams.
Breadth phase
Open a second use case with a different team. Repeat the implementation review for the new use case. The existing champion makes the introduction; you build the relationship with the new buyer. If the customer is on monthly billing, this is often where the annual contract conversation happens.
Platform phase
With two or more teams active, start the organizational sell conversation. Connect the existing champions with the executive sponsor. Frame the annual contract renewal (or first annual commitment) around the expanded platform footprint.
Shampoo phase
There's always another team, another use case, another expansion path. The cycle doesn't end. Even gold-standard accounts have adjacent teams who haven't adopted PostHog yet, new products they haven't tried, and new use cases emerging as PostHog ships new features. Rinse and repeat.
Realistic expectations
Not every account will reach the gold standard. Some customers have one team, one use case, and no appetite for expansion. Some have organizational dynamics (strong platform team, preferred vendor agreements, decentralized buying) that make the organizational sell impractical. Some are just not big enough for multi-team, multi-use-case adoption to matter.
But your task is to gather enough information to be absolutely sure that this is the case. See the account planning framework for how to systematically think through these questions.
The framework still applies at whatever scale is appropriate. A customer with one team using Product Analytics + Session Replay + Surveys well is better than a customer with three teams using PostHog poorly. Depth before breadth. Quality of adoption before quantity.
The gold standard is the north star. Every step of the cycle, from fixing an implementation issue to adding a second product to opening a second team, creates value for the customer and growth for PostHog. The organizational sell is the ultimate outcome, but each intermediate step is still a big win.
Since our system does not experience a huge variance in incoming traffic aside from the occasional instrumentation bug, it's important to give the pipeline team a heads up in advance, since we may rate limit the requests. Additionally, we need to clarify a few commercial and technical points before giving the green light.
Make sure they have their product questions answered first, ie, they are not relying on historical import data to validate their use case. It's ok for this to be a contingency of them using the product/paying us, but we should be pretty sure that they are committed so we can avoid asking pipeline team to spend (sometimes considerable) effort managing an import only to have a user decide we're not a good fit.
Customer should answer the following:
When is this scheduled for (strong preference for weekdays with the most EU-timezone overlap)
Regarding the actual request(s), what can we expect around:
batching
distinct_id variance, specifically, max events per distinct_id for the top few users (eg select count(*), distinct_id from events group by distinct_id order by count(*) desc limit 100 or similar)
event types (some require more consideration to process than others, eg $create_alias , $identify etc)
Will you have apps enabled
What will be the peak rate and total duration of calls
What will the ramp-up profile look like
If the count of events for a given distinct_id is too high, we may relax the constraint that events for a single distinct_id are always sent to the same kafka partition, which means these events might not be processed in the correct order. This can be problematic for merging events, where order of ingestion matters (eg an alias event arriving before an identify event on which it depends). This will need to be communicated to the customer.
Load testing
If a customer mentions load testing, get answers to the above and then alert the pipeline team asap, so that accommodations can be made, as this may require scaling up to handle properly. If a customer plans to send a large volume of single capture requests all at once, rather than ramp up to a peak over some time period, that is not a load test but more like a denial of service (DoS).
Discovery isn’t walking through every PostHog feature. It’s having real conversations with customers to figure out if PostHog will be a good fit for them. Learn their problems, see how they solve things today, and find the people who’ll get excited enough to bring us in.
This is meant to be a guide, not a rule-set. Each person has their own unique style. The goal here is to surface the right insights by providing a framework for how to go about _asking the right questions_ vs. a talk-track for how to run discussions with customers.
Core principles:
Curiosity over pitching - Be genuinely interested in their challenges
Find the pain - People buy solutions to problems, not features
Identify champions - Someone needs to sell internally when you're not there
Discovery isn't one-sided questioning - it's give and take. You learn something, you show something, you ask questions, repeat. The goal is understanding what customers are trying to accomplish so we can focus on relevant features rather than discussing everything PostHog can do.
Why discovery matters
PostHog is a broad product suite with common combinations depending on the use case. Discovery can help us provide customers with a better experience by understanding their specific needs so we can:
Conduct a demo that actually matters - No one wants to sit through features they'll never use
Draw connections between their problems and our products - There are 10+ products (and counting), we want to help them find the right combination
Skip the irrelevant stuff and get to the good bits - Customers' time is valuable, and generic sales calls aren't
Reduce time & effort needed for them to make a confident decision - By understanding requirements upfront, we can address concerns early and focus on what matters most to stakeholders
Timeline
We don't need to cram every question into the first call. Discovery is always happening and we have many customers who stay with us long term. Use each touchpoint to learn something new.
Other channels
Beyond the 1st call, there are other spaces where we frequently communicate with customers:
Most customers are preferential towards Slack while others like email/Zoom. Slack is central to communications at PostHog and tends to be a great place to offer real-time support and ask questions.
Before your 1st call
Prep work
Discovery includes preparation. Before speaking with any new customer interested in engaging further with PostHog, it's helpful to gather some basic knowledge to help with demoing relevant features and determining if it's a good fit.
Cross-reference Vitally, PostHog, Slack and Salesforce for any prior engagement or current activity/status
Learn more about who you're speaking with via LinkedIn/X
Visit the company's website, learn about their product, who they are marketing/selling to, language they are using. Familiarize yourself with what may be important to them
Use ChatGPT, Perplexity, Claude, etc. to help research the company, their industry, macroeconomic factors and potential use cases for PostHog
Asking questions
Discovery is about understanding the real problem through natural conversation. The goal is to be genuinely curious about their situation, not to interrogate them.
Question principles:
Use "what" and "how" to signal curiosity rather than judgment
Start questions with "tell me...", "explain to me...", or "describe to me..." to avoid yes/no answers
Focus on understanding their current state and challenges
Ask about consequences and impact naturally as the conversation flows
Understanding customer goals
Instead of asking about room for more PostHog products, ask about what the customer is trying to accomplish. Questions like "what's coming up in your roadmap over the next few months?" get better intel without feeling like an upsell and it's just generally a much more natural conversation.
When you understand their goals, you can frame PostHog around outcomes instead of features. For example, if you learn they're launching a jobs board and their GTM leans on niche SEO, you can shape the demo around using web analytics to nail that launch. You're telling a story where PostHog helps them succeed, not just showing what buttons do.
Goal-discovery questions:
"What's coming up in your product roadmap over the next few months?"
"What's the biggest thing your team is trying to accomplish this quarter?"
"What does success look like for your team right now?"
"What's keeping you up at night with work?" (only if you have genuine rapport)
When to use these:
In prep — research their roadmap, recent launches, and blog posts beforehand, then confirm on the call
During discovery — weave into the opening conversation naturally
At the end of a call — as a lightweight follow-up: "before we wrap, anything big coming up I should know about?"
In follow-up comms — as part of a warm intro or handoff (e.g. TAM introducing to the engineering team)
Important: This only works if you're genuinely curious. It's not a checklist item for every call — forced interest is gross and salesy. But when the connection is there, it's a much better place to frame what we offer from.
What makes PostHog different
The demo
Demoing PostHog is an important part of our sales process and how we first introduce PostHog to customers. It brings immediate value to a call, is consistent with other messaging and builds credibility with technical folks.
A demo can also be a great format where questions bubble naturally.
Principles:
Leverage PostHog's technical credibility by showing vs. telling
Use the demo as a conversation starter rather than a monologue
It's okay to say _"I don't know"_. The main thing here is to follow up with an answer after the call. If you try to fake it, you'll lose credibility
Demo of Product Analytics: _Showing a funnel analysis_
Questions: "Is there a conversion flow you're currently struggling to understand?"
Demo of Session Replay: _Showing user session with errors_
Questions: "How do you know if users are struggling with your product?"
Demo of Web Analytics: _Showing UTM sources breakdown_
Questions: "How are you currently attributing conversions across channels?"
Demo of Autocapture: _Showing retroactive insight creation_
Questions: "How much dev time do you currently spend on instrumentation?"
Demo of Data pipelines: _Showing how to create a destination_
Questions: "Is there anywhere you'd ideally like to send data back out to?"
Demo of Error Tracking: _Showing error dashboard_
Questions: "How are you prioritizing bugs to fix first?"
Demo of Data warehouse: _Showing available sources_
Questions: "Are there other data sources that would be valuable to query alongside PostHog data?"
Demo of Experiments: _Showing Experiment dashboard_
Questions: "How are you currently cross-referencing test results with other user-behavior data?"
Demo of LLM Observability: _Showing LLM Dashboard_
Questions: "How are you gathering data for your AI/LLM products?"
Other questions you could ask while demoing:
"Who else would find this valuable?"
"How does this compare to how you're handling this today?"
"Of what was covered, what did you find most valuable?"
Qualifying
A key component of discovery is qualifying customers to ensure they are a good fit and whether they're speaking with the right people at PostHog. You can find more about how we qualify at PostHog in the new sales qualification guide.
No engineering resources - There is some coding required for a tool like PostHog and customers will need some engineering support to be successful
Strict compliance constraints - A customer may ask for a very niche security or privacy certification that we don't have
Need self-hosted - PostHog's self-hosted open-source deployment is made for hobbyists and since we're a small team, we can only provide limited support for it
Identifying your champion
Champions aren't just customers you're friendly with - they're people who will actively sell PostHog internally. While you won't always find a champion, working with one when possible can streamline deals and provide us with valuable feedback along the way.
Examples
Questions to identify champions:
"Who else is affected by this problem?" (Look for advocacy in their response)
"How do you typically evaluate new tools at [Company]?" (Champions know the process)
"What would need to happen for this to get approved?" (Champions understand internal politics)
"Who would be most excited about solving this?" (Champions will often name themselves)
Characteristics to listen for:
Using "we" and "us" language (ownership)
Asking for detailed technical / instrumentation questions
Mentioning budget or approval processes prior to you asking
Referencing internal stakeholders by name
Expressing personal frustration with their current state
Have a vision for what future state needs to look like
Follow up questions for champions:
"What's your role in making this decision?"
"How have you handled similar evaluations in the past?"
"What concerns might others have about changing tools?"
"Besides you, who else would we need to win over?"
"What questions should I be asking that I haven't asked yet?"
"If you were me, how would you go about positioning PostHog?"
"What's the best way to position this to [insert stakeholder here]"
"How can I help you build your internal case for PostHog?"
While you can start identifying potential champions early in the process, building the relationship is an ongoing effort.
Discovery call structure
Give yourself enough time to demo - it can make all the difference!
1. Opening & understanding the situation (~5-7mins)
Goal: Get rapport, learn about their setup, and uncover any frustrations.
Potential questions to flow between:
"What prompted you to reach out to PostHog?"
"What are you using for analytics today and how's it working?"
"What's your experience with tools like PostHog?"
"Who on your team uses this data and for what?"
"What decisions are you trying to make that you can't make today?"
"How does your team typically evaluate new tools?"
"Is there anyone else who should be part of these conversations?"
2. PostHog demo (~15-20min)
Goal: Show PostHog, focus on relevant features, establish technical credibility, get feedback and ask questions.
Reference the demo section above for how you can incorporate discovery into your demo and learn more about how we do sales in the initial demo playbook.
3. Closing and next steps (~3-10min)
Goal: Establish timeline, confirm mutual fit and next steps.
If it's not a fit, that's okay! We want to ensure we're not wasting anyone's time. Get alignment from the customer and there may be an opportunity in the future
If there is a clear opportunity, offer up some actionable next steps (free trial, invite to Slack, generating a quote, help reduce spend, scheduling a call etc.)
Set expectation that you'll follow up via email or Slack
Gain an understanding of their timeline
Route the customer to the next best channel if they are better handled by a separate team (Support, Startup program etc.)
We like to keep things conversational - if you're genuinely curious about their situation, this should all come naturally!
Summary
Discovery can help with addressing gaps in your knowledge about a customer and makes efficient use of both your time and theirs. By understanding their actual needs, challenges, and decision-making process upfront, you can:
Keep conversations focused
Avoid wasting time on irrelevant features or solutions
This is a living page for how we pitch PostHog making _your_ product self-driving. It covers the concepts (so you can explain scouts, signals, and sources without tying yourself in knots), the strengths of each and which to lead with, the core pitch, how to run it, and a reverse demo format that lets the customer experience self-driving on their own data. We're still early, so treat this as a starting point and iterate on it as we practice the pitch and learn what lands.
This pitch sits on top of our brand story, so keep it consistent with how we describe PostHog everywhere else. Two things carry through from there: self-driving is the story (the narrative everything sits under), and the customer's product stays the subject – we make _your_ product self-driving, PostHog isn't "a self-driving product" itself.
This page assumes you've already done the work in discovery – it covers what to say once you know their pain, not how to find it. For the mechanics of the wider deal, see new sales and running trials.
In a hurry before a call? Skip to the cheat sheet.
What you're selling
These are the core pieces. The docs pages are more thorough, but you at least need to have these concepts engrained before you can attempt a demo.
| Part | One-line definition | |---|---| | Signal sources | Built-in pipelines that watch one data stream continuously, in real time. Error Tracking, Support, Session Replay, Replay Vision, Product Analytics, and AI Observability in PostHog, plus external tools connected through the data warehouse – GitHub Issues, GitHub CI, Zendesk, Linear, and pganalyze. You toggle them on. | | Scouts | Research agents that explore a slice of your data on a schedule, and decide what's worth surfacing. A few standard scout templates are ready to use, and you can generate custom scouts specific to your project. | | The signals pipeline | Both of the above emit signals – a finding, the evidence behind it, and a suggested action. The pipeline deduplicates and groups related signals so one real problem becomes one item, not five. | | Reports and the inbox | A grouped set of signals becomes a report in your inbox, available in the web app, PostHog Desktop, and Slack. This is the surface a human actually looks at. | | Research and PRs | From a report, a research agent connects it to the codebase and marks it actionable when a code fix is possible. From there an implementation agent can open a PR. Nothing merges without a human. |
The full pipeline: something watches (source or scout) → it emits signals → the pipeline groups them into a report → the inbox researches it → an agent can open a PR. The docs walk the same chain in order, so the self-improving loop is the page to send anyone who wants the whole thing end to end.
Which to lead with - scouts vs signals
| Lead with signal sources when… | Lead with scouts when… | |---|---| | They already have a firehose – errors, tickets, Sentry, Linear – and the problem is triage, not detection | Nobody is watching the thing they care about, or a person is watching it manually every morning | | Completeness matters: "we can't miss one" | Volume matters: "we get too many to look at" | | The stream is well-defined and they trust it | The interesting thing spans surfaces, or nobody's written down what "interesting" means yet | | They want to shorten the path from a known issue to a merged fix | They want judgement applied to data they already have but never look at | | Their pain is described in nouns: tickets, exceptions, issues | Their pain is described in questions: "are we losing anyone?", "did that launch land?" | | Fastest to demo: toggle a source, show the queue fill | Fastest to demo: point a scout at their data and run it on demand |
The core pitch
Keep it simple. Something like this:
PostHog already has all the behavioral data about how people use your product. We turn that data into signals, feed those signals to an agent running in a sandbox, and it automatically opens PRs that improve your product. The more you put into PostHog, the better the signals get.
That last line is the flywheel line. Every event, flag, and replay you capture improves the signals the agent works from, so more data in means better PRs out. In brand terms this is context – the fuel for the self-driving loop.
The flywheel is stronger than it first sounds, because it isn't limited to product analytics. A scout reads your data through the same PostHog MCP you'd connect to Claude Code, so anything you land in PostHog becomes watchable – a warehouse table, a Stripe sync, a support inbox, even a Slack channel relayed into the warehouse.
Why it works
The pitch resonates because the customer connects the dots themselves. You don't have to convince anyone that behavioral data is valuable, because they already believe it. You're just showing them the obvious next step, which is that data shouldn't sit in a dashboard waiting for a human to act on it. It should drive changes to the product directly.
When it goes well, the customer arrives at the conclusion before you finish. We've seen this play out on an on-site: as the pitch unfolded the team worked through it out loud, described the exact signals use case back to us, and then started sequencing their own rollout, ending with asking whether they should do a Fable 5 audit of all their instrumentation first to make sure they're tagging everything and getting as much as possible into PostHog.
When the customer starts planning their instrumentation rollout unprompted and immediately, you know pitch has landed!
How to run the self-driving pitch and demo
Lead with the data they already have. Start from the behavioral data they're capturing in PostHog today, not from the agent. The agent is the payoff, not the opener.
Draw the line from data to PR. Walk through it: data goes to signals, signals to an agent in a sandbox, and the agent to PRs that ship improvements. Let them follow the chain rather than asserting the conclusion.
Ask what they check manually. "What does someone on your team open every morning?" is the single best scout-discovery question. Whatever they name is a scout, and naming it back to them lands harder than any feature list.
Land the flywheel. Make sure they leave understanding that more data means better signals means better PRs. This is what turns it from a feature into a reason to instrument everything.
Let them sequence the rollout. The strongest outcome is the customer proposing their own instrumentation audit. When they get there, help them plan it, since that's the start of the flywheel.
Leave with one concrete thing, not a strategy. The commitment you want is small and specific: one source switched on for a stream they care about, or one scout pointed at one question. Either proves the concept on their own data, and it's the thing they'll show their team.
The reverse demo
A reverse demo (a term Clay recently popularized) flips the usual script: instead of you driving a polished demo environment, the customer drives their own data. It's a faster path to the aha moment because the value shows up in their product, not a sandbox account.
The catch for us is that a reverse demo only works once there's enough clean data in PostHog for the agent to act on. Clay can have someone build a lead list on the first call before they're even a customer; we can't conjure signals out of an empty project. That makes the reverse demo a great fit for existing customers who already have the data flowing (a natural play for TAMs), and a tougher one for prospects who haven't connected anything yet (TAEs will usually need to get data flowing first, see the pre-call prep below).
Pre-call prep
The whole demo depends on there being real signals to work from, so set that up before the call:
Ask them to turn on error tracking and session replays for a window of time ahead of the call, so the agent has fresh, real signals to act on by the time you meet.
Have them get PostHog Desktop downloaded and their GitHub and PostHog connected, so they can kick off a PR live.
Frame the cost honestly: offer to credit any usage on errors and replays during the demo window, since you need them on to show it at its best, and they can turn them back off after. If it wows them, they'll want to keep them on anyway, and that's the flywheel starting.
Demo flow
Let them drive the whole way. You narrate, they click.
Have them open the PostHog Desktop inbox.
Walk them through what they're seeing in the reports and PRs tabs, using their own data.
Have them pick a report to inspect and kick off a PR from it themselves.
Explain the self-driving part: they can set it up to handle bugfix and maintenance PRs automatically, while humans still drive product decisions and new features. (This is the same line as "robots do maintenance, humans do creative work" below, made concrete.)
Using their data for this makes it click and get to the "aha!" moment much more quickly.
The scout-based reverse demo (no data prep or pre-ingest needed)
The source-led version above needs data to accumulate first. The scout-led version doesn't, which makes it the better opener for an account with historical data but nothing switched on yet.
In PostHog Desktop, open the scouts page and pick the "Make a scout" suggestion. It scans their actual project and proposes custom scouts grounded in their real data – which is itself the moment, because the suggestions are specific to them.
Let them pick the one that makes them go "huh, yeah, I'd want to know that."
Run it on demand right there on the call – no waiting for a schedule, and a scout that's still disabled can be run this way.
Read what it filed together. If it's good, turn it on. If it's noisy, that's a demo too: show them the dry run and scout notes, because "I can tell it that's known noise, in English" is often what closes it.
The thing to make land here is the memory. A scout reads back what earlier runs learned so it dedupes against itself and gets smarter.
For ideas that work across verticals, and the scout patterns cookbook behind them, send them to scout examples. For a deep dive with two real scouts traced end to end and a walkthrough video, What is a scout? are good references.
How AI observability can fit in
AI products are an easy self-driving pitch: they already know their agent misbehaves, and nobody is reading every trace. Two signal types turn AI observability data into inbox reports.
Evaluations (rolled out to everyone).Ingest AIO events → create an online evaluation that scores them → turn on evaluation reports, where an agent reads a batch of results and writes up what it found. That summary is the signal.
Anomaly detection (alpha). Ingest AI observability events, then add an anomaly detection alert on an AI errors, latency, or cost insight and turn on agent investigation. When the alert fires, the agent checks whether the anomaly is real and writes up what it found in a notebook. Only true positives reach the inbox, as a report summarizing the investigation.
Objection handling
| What they say | How to handle it | |---|---| | "Will it automatically merge PRs?" | No. Agents open PRs, humans review and merge. Autonomy is from instruction, not from the engineer. Never soften this one. | | "Won't this be noisy?" | Yes, definitely. Quality of the sources and scouts matters, but not ever report or PR is a hit. Explain the three dials: dismiss or snooze a report with a note and later runs read it, leave a scout note in plain English, or slow the schedule. . | | "How is this different from alerts we already have?" | Alerts fire on thresholds. Scouts hold judgement, remember what they already said, and weigh how much something matters. Sometimes an alert is a suitable solution | | "Can it watch _X_?" (something not in PostHog) | If it can land in PostHog – warehouse table, connector, Slack relay – yes. If it can't, say so. "Get it into PostHog first" is the answer | | "What does it cost to run?" | Runs come out of a project's daily run budget, and the schedule is the main dial. Frame it honestly: a tighter cadence mostly pays to re-confirm nothing changed. Slow a chatty scout down before turning it off. See self-driving pricing for the current numbers – check it rather than quoting from memory, it's still moving. | | "Can we try it without it doing anything?" | Yes – dry run mode runs the scout and records everything it would have filed without writing to the inbox. Great for cautious or high-stakes teams. |
Cheat sheet
For the five minutes before a call.
The chain: something watches (source or scout) → signals → grouped into a report → inbox researches it → agent opens a PR → human merges.
The trade-offs between Signals and Scouts: sources give determinism and guaranteed coverage, scouts give judgement and steerability.
Lead with sources when there's significant volume to triage. Lead with scouts when everything is technically "something" and they need a filter.
Best demo move: toggle a source and watch the queue fill, or make a scout on their data and run it on demand, live.
On an AI account: eval + evaluation report ships today, anomaly detection + agent investigation is alpha. Both need AIO events flowing first.
Never promise: auto-merge, total coverage from a scout, or a PR from every report.
Have open in another tab:the FAQ for anything you get asked cold, and pricing so you never guess at a number.
Iterating on this page
We're actively refining this pitch. If you run it and learn something, whether what resonated, what fell flat, or a better way to frame the flywheel, add it here so the whole team gets sharper.
This page covers more of the operational detail of how the Technical Account Manager team generally works - for a broader overview of roles and responsibilities, visit the overview page. If you're looking for how the New Business Sales team (Technical Account Executives and BDRs) works, see their How we work page.
Roles
We have three types of roles:
Technical Account Executives - closing new business from inbound and outbound leads and expanding their usage of PostHog in the next 12 months
Technical Account Managers - expansion from existing customers, closing new business from product-led leads
Business Development Reps, aka BDRs - generating leads for new business, including via cold outbound
Technical Account Managers
Each TAM is assigned 15 existing customer accounts representing $1.5M to $2M. See TAM book balance for the full composition targets. Additionally, you will manage inbound leads as they are assigned to you in your territory. Overall, the hard cap on existing book + new leads is 25 accounts, so staying extremely focused is important.
We use the "AM Managed" Segment in Vitally to show that an account is part of somebody's book of business and therefore included in individual and team quota calculations. AMs should not assign this themselves (that's up to Simon or Ben), but can add themselves as the Account Executive in Vitally to make it easier to track things you're working on.
For Product-led leads we will only add them to your book for quota purposes if you have a solid plan in place for conversion to prepaid credit or cross-product adoption. Account Owners can use the "Leads" Segment in Vitally to separately track these from the main managed book.
At the end of each quarter we will review your accounts and look to hand off some to bring your focus account list back down to 10. Simon and Ben will also review everyone's accounts each month proactively to make sure that the balance of accounts across the team makes sense.
TAM At-Risk Accounts review meeting
In addition to the weekly sprint planning meeting on a Monday, we do a weekly territory review standup on Wednesday. A Technical AM is picked at random and runs through the following for each customer in their book of business in Vitally:
Rate your relationship with them (no connection yet/made contact/answering their questions in Slack/trusted advisor)
What's your next step with that customer (annual plan, cross-sell etc).
Are they a churn risk and why?
The objective of the meeting is to hold each other to account, provide direct feedback, and also support each other. It is a great place to ask for help from the team with thorny problems - you should not let your teammates fail.
Coming off an account
The CSM stays on every $20k+ account, so there's no handoff when a TAM's work is done. The account just moves to CSM-only coverage. When and how to come off, and what context needs to land with the CSM first, is covered in Removing a TAM from an account. Use the saturation checks to make the case, and talk it through with your team lead.
A customer being negative/difficult to work with isn't a reason to come off an account. It's your job to turn them around to being a happy customer (AKA be their favorite).
How commission works - Technical Account Managers
General principles
We want to align incentives - TAMs get paid when PostHog gets paid
100% quota attainment leads to a 50/50 of OTE and Commission split
TAMs cover 5x their OTE with their quota
This plan, including the OTE to quota ratio, is likely to change as we scale up the size and complexity of our sales machine! For example, the rate plan will be reviewed when median book cash exceeds 5x OTE. This is completely normal - we will ensure everyone is treated fairly. For now we are generally trying to optimize for something straightforward here so it’s easy for PostHog (and you) to calculate commission.
How we calculate
Quota is calculated annually, and is paid out quarterly
A deal counts toward quota in the quarter of its effective date. For annual deals, the effective date is the contract start date or the signature date, whichever is later. For monthly accounts, each payment counts toward the quarter it falls in.
Because the signature date sets the floor, a deal can never be credited to a quarter that has already closed, even if its contract start was backdated to align with the customer's current billing period.
The Commission rate is 10% flat and uncapped, regardless of whether it is monthly or annual
There is an additional 6.7% incentive on net-new annual contracts
There is also an additional 6.7% incentive on growth in annual renewals
There is no additional incentive on monthly payments
An account counts toward your quota only from the date it is added to your book (when the AM Managed segment is applied). Cash paid before that date does not count toward commission, even if it lands in the current quarter. We don't pay retroactively on an account that wasn't yet in your book.
Examples Ator, the TAM has a book account that pays month to month. In the quarter, that account makes 3 payments of $2,200, $2,100, and $2,500 totaling $6,800. The quota realized and paid out to Ator on this account is 10% of the total for that quarter, $680.
Ator has another book account that he lands on an annual credit purchase that quarter. The first month of the quarter, they paid $8,000 and then they signed an annual credit purchase for $142,857.15 in credits. After discount, they paid PostHog $100,000. Ator realizes:
$10,000 in quota from the 10% on the cash paid
$6,700 in quota from the 6.7% incentive to balance out the annual discount
$800 from their single monthly payment that quarter
Ator is paid a total of $17,500 for that account that quarter.
Ator has (yet) another book account coming up for renewal. Last year, that account spent $100,000 with PostHog. This year, they are increasing their annual credit purchase to $171,428.57. After discount, they pay PostHog $120,000. Ator realizes:
$12,000 in quota from the 10% on the cash paid
$1,340 in quota from the 6.7% incentive on the increase over last year
Ator is paid a total of $13,340 for this account.
Effective date example A customer's billing period runs June 23 to July 23. The TAM signs the annual deal on July 20 and the contract start is set to June 23. The effective date is July 20, the later of the two, so the deal counts toward Q3 rather than the already-closed Q2.
Situations where PostHog credits a customer due to circumstances outside of the TAM's control will be handled on a case by case basis.
During ramp
For your first three months you carry a full quota, not a reduced ramp quota. You are guaranteed 100% of your OTE as a floor, so a slow start won't cost you. In each ramp period you are paid the higher of that floor or the commission you earn on net new business you personally close. You do not get the floor and commission on top of it.
Deals a previous owner signed (including ones with a future-dated start that lands in your ramp quarter) do not count toward ramp commission. The floor already covers you while you build. See the new hire FAQ for how the floor is prorated by start date.
TAM book of business rules
Only accounts with the AM Managed segment in Vitally will be counted towards your quota. Simon adds this manually after reviewing with you and your team lead.
All accounts in the AM Managed segment need an account plan in Vitally, which is updated and reviewed with your manager regularly.
If you are assigned an account with no previous owner, you have up to 3 months to figure out whether they should be in your book or not. Don't ask for the AM Managed segment to be added until you're happy that there is growth potential there.
If you are assigned an account with a previous owner, work with them on the handover process. If the customer isn't in a healthy state usage and engagement-wise, feel free to push back and ask for the previous owner's help in getting them to a good state before taking ownership. If you really can't resolve this, then talk first to your team lead. If you can't resolve it, Simon will be the tie breaker. It may be that we need you to work on the account regardless but will treat it as a lead with the same rules as point 3 above.
Accounts which you've previously been paid quota on need to stay in your AM Managed book until they are handed over as per 3 above, or until they churn/fall below $20K ARR. In this case, we will keep them in the AM Managed segment for quota calculation purposes and then remove them after the quarterly calculations are complete.
Nominally, you should have around 15 accounts/around $1.5m to $2m ARR in your AM Managed book. There is some wiggle room here, but if you find yourself with 25+ accounts, it's unlikely that you'll be able to give them the level of focus we expect from a TAM, so be prepared to rebalance with your team lead. (see TAM book balance).
You can have accounts added to your book at any time, if you are comfortable that there is growth potential there. Removal of accounts should only happen at the end of the quarter so that quota can be calculated.
If you actively work to reduce a customer's spend with us by optimizing their usage, we may exclude that usage drop from quota calculation. We will review this on a case by case basis but at the very minimum you'll need documented evidence of the work you did to optimize their usage before it dropped. This should first be reviewed with your team lead who will then ask for approval from Simon. To make the process easier, drop the details of your optimizations as a note on the customer record in Vitally.
We want you to ensure the customer has paid, and we don't want AMs to throw invoice chasing to a finance person. This means you should make friends with the finance person on the customer's side, and ensure all payment paperwork is in order to allow for the customer to pay. You should make the failed/late payment process clear to your customer, especially in the case of a severely delayed payment.
We have a bunch of accounts where they are declining for reasons that have nothing to do with a TAM’s actions. We also have a bunch where they are growing in the same way. These even each other out in the bigger picture of hundreds of accounts, if anything in favor of the latter. If they fit the criteria for having a TAM assigned, you should be prepared to continue to manage both types of customers in your book, as churn prevention is a key part of the TAM role too.
Team lead quota
From your first full quarter as a team lead in Sales, you will move to a 60% base 40% commission split in reflection of your new player/coach role. This will be based on your team's quota attainment although you will still have your own individual quota target.
Your individual quota will be lower than others in the team as you'll be spending more time on managing the team, but we still want you to demonstrate the sales individual contributor skills to your team. You should aim for 80% team management, 20% IC work, and the quota will reflect that.
To calculate the team quota, we combine the quota of all team members with proration applied if they are still ramping:
For fully ramped team members we add 100% of their quota to the team quota.
For team members who begin the quarter still in their first three months in the role we add 50% of their quota to the team quota.
Example: With a flat quota of $250,000 and 3 fully ramped people, and 1 ramping, the team quota would be $875,000 (($250,000 * 3) + $125,000)
If someone leaves the team, we may recalculate the team quota depending on how their accounts and opportunities are reallocated to others in the team. If someone joins the team, we don't change the team target, and don't count their contribution towards the existing target, to keep it simple.
Travel to see customers
You are likely to need to travel a lot more than the typical PostHog team member in order to meet customers. Please make sure that you follow our company travel policy and act in PostHog's best interests. We trust you to do the right thing here and won't pre-approve your travel plans, but we do keep track of what people are spending and the Ops team will follow up with you if it looks like you are wasting money here. We are not a giant company that pays for fancy flights, accommodation, and meals so please be sensible.
As a TAM, we want you to get in front of customers in person on a regular cadence. As a baseline:
Visit local customers (those near you) once a quarter. If a customer is within easy travelling distance, it's a great opportunity to see them regularly. Even if they aren't directly your customer, showing up with donuts helps develop strong relationships.
Visit your big customers twice a year. Your largest accounts warrant more face time, so plan to see them at least twice a year even if they aren't local to you.
Visit your closest tech hub (SF, London, etc.) once a year. A lot of customers and prospects cluster around major tech hubs, so make a point of getting to the one nearest you at least annually and stacking up meetings while you're there.
These are guidelines, not limits — if it makes sense to see a customer more often, do it. Use your judgement, be sensible with spend, and prioritize the trips that will have the biggest impact on retention and expansion. As a general rule, larger customers justify more regular visits.
Working with engineering teams
We hire Technical AEs. This means you are responsible for dealing with the vast majority of product queries from your customers. However, we still work closely with engineering teams!
Product requests from large customers
Sometimes an existing or potential customer may ask us to fix an issue or build new features. These can vary hugely in size and complexity. A few things to bear in mind:
Engineers at PostHog talk to customers. It's much better to bring engineers onto calls to speak to a large customer to talk to them directly than just do the call yourself and copy and paste notes back and forth. This is especially useful if a) the team was already considering building the feature at some point, b) it's an interesting new use case, or c) the customer is really unhappy for valid reasons and could churn.
Provide as much internal context as you can. If a customer sends a one-liner in Slack, don't just copy and paste into a product team's channel - find out as much as you reasonably can first, ask clarifying questions up front etc. Otherwise the relevant team will just ask you to do this anyway.
We already have principles for how we build for big customers - if you have a big customer with a niche use case that isn't applicable to anyone else, you should assume we won't build for them (don't be mad!)
Finally, if you are bringing engineers onto a call, brief them first - what is the call about, who will be there. And then afterwards, summarize what you talked about. This goes a long way to ensuring sales <\> engineering happiness.
Complicated technical questions
You will run into questions that you don't know the answer to from time to time - this is ok! Some principles here:
Try to solve your own problems. Deep dive the docs, ask PostHog AI, ask the rest of the sales team first - a bit of digging is a valuable opportunity for you to learn.
Similar to the above, don't just copy and paste questions from Slack with no context. Add some commentary - 'they have asked X, their use case is generally Y, I think the answer might be Z - is that right?'. Do some of the lifting here, rather than putting all the mental load on an engineering team.
If you open a ticket in PostHog Support and know which team the ticket needs to go to, assign the ticket to that team so that it bypasses support and goes straight to them.
Working with customers in Slack
Most of our customers use Slack, and it's a great way for us to be responsive to them. Qualifying customers and prospects can get a shared Slack channel, and you should set one up as early as it makes sense in your relationship with them.
We share channels via Slack Connect and add SupportHog so that both PostHog and the customer can raise support tickets directly from a Slack thread — react with the :ticket: emoji or mention @SupportHog. This syncs the conversation into PostHog Support so our Support and Engineering teams can work on customer issues in a familiar context.
See Shared Slack channels with customers for the full setup steps, including channel naming, who to invite, and how to support customers who use MS Teams instead.
It's your job to ensure your customer issues are resolved, make sure you follow up with Support and Engineering if you feel like the issue isn't getting the right level of attention.
Generally speaking, companies already using PostHog and spending money will be routed to the product-led sales team. Leads where the customer is earlier in their lifecycle with us, e.g. using PostHog but not spending money, will go to the new business sales team.
We frequently tweak these rules and experiment with different signals to see which work best. Generally you should be aiming for a 20% conversion rate from these types of leads.
They follow the normal territory assignment rules in Salesforce, and are routed either to Technical Account Executives or Technical Account Managers depending on the type.
Product-led sales team
Customers with MRR between $500-1,667, employee count > 50, user count > 7, based in ICP country, and has been paying for at least 3 months
Customers who have high ICP score and subscribe to the Scale plan
Customers with MRR >$1K and >50% forecasted spend increase this month
New business sales team
Completed the book a demo form (organic inbound, paid ads campaign, or outbound)
Engineering Managers (VPs, Directors, Heads of) who follow us on LinkedIn but are not (yet!) customers
Job Switchers v4
Competitor takeouts
Companies with recent fundraising activity
Revenue-fit and Growth-fit lookalikes
Backlog:
Filled contact sales but then went silent, never talked to an AE (next: AE Campaign to warm back up)
Future Event attendees
Closed lost opportunities (new biz _and_ renewals) 5+ months old where reason was 'unresponsive'
Tried PostHog but did not convert - signed up but went inactive, never paid, never talked to an AE in DW (next: more filtering on this list)
Automated (Abhischek):
Requests for Trust Center access that require an NDA
Paused - Warmbound - $100-499 MRR at some point in the account's history (need to filter more)
Anyone at PostHog can also manually flag an account as a high potential lead. This includes new or low spend accounts with strong net new potential or existing paying customers with credible expansion potential. To create a lead, go to the customer's Vitally record and add a Segment for AM referral (product-led sales) or AE referral (new business).
Demo booking
Customers that want to book a demo and show strong ICP fit signals are automatically get shown a booking link for a demo with a TAE. Those <20 are for the TAE to manually review and schedule. Default is our contact form submission routing system for managing this.
We have an AI qualifier step to classify submissions as sales/support/spam. If 'support' or 'spam', it'll skip round robin - 'support' will auto create Zendesk tickets, 'spam' are dropped.
Accounts also have to match 2/3 requirements for revenue, title, and/or industry to see the instant scheduler.
If an account has had a lead disqualified within the last month, we no longer show the scheduler.
Lead scoring
We calculate lead scores in Salesforce to help us prioritize our inbound book of business. Put simply, the higher the score the higher value a potential contract with a customer should be. The current ICP fit score is described here
This page covers more of the operational detail of how the New Business Sales team (Technical Account Executives and BDRs) generally works - for a broader overview of roles and responsibilities, visit the overview page. If you're looking for how the Technical Account Manager team works, see their How we work page.
Roles
We have three types of roles:
Technical Account Executives - closing new business from inbound and outbound leads and expanding their usage of PostHog in the next 12 months
Technical Account Managers - expansion from existing customers, closing new business from product-led leads
Business Development Reps, aka BDRs - generating leads for new business, including via cold outbound
Technical Account Executives
TAEs work with:
People who email sales@ directly
People who book a demo via contact sales
Other triggers we see in product, supplemented by data from Clay
Cold outbound leads generated by our BDRs are routed to TAEs to work with too. Customers move off of a TAE to a TAM or CSM 3 months after closing on a prepaid contract (usually annual) - you have to ensure they are well set up, not just contract signed!
TAE Territory Review
In addition to the weekly sprint planning meeting on a Monday, we do a weekly territory review standup on Wednesday. A Technical AE is picked at random, and we spend 30min going through:
Brief, mid-week announcements (if any)
For one random Technical AE as chosen by the wheel of names - SFDC Hygiene check — is the deal value, stage, and close date accurate? Are the next steps up to date? No story time here, just data.
Biweekly, we review all larger ($50k+) opportunities across all Technical AE. For each opportunity, the person reports and discusses:
Opportunity value and close date - why this value? when do we think it will close?
Progress towards exit criteria of the current stage
Concerns and questions about the opportunity
On alternate weeks from the larger deal review, we run wheel of names again (excluding the Technical AE selected for the hygiene check), and the selected Technical AE reports and discusses the opportunities in their pipeline, including:
Starting with later stage opportunities, discuss opportunity value and close date - is the value solid? and what confidence do we have in the close?
Progress towards exit criteria of the current stage
Concerns and questions about the opportunity
The objective of the meeting is to hold each other to account, provide direct feedback, and also support each other. It is a great place to ask for help from the team with thorny problems - you should not let your teammates fail.
How commission works - Technical Account Executives
General principles
When thinking about commission, we want to particularly incentivize:
Landing new customers
Quickly expanding them into new products using the relationship you've developed in onboarding them as customers.
We aim for a 50/50 split between base/commission when calculating OTE by default.
This plan will almost certainly change as we scale up the size and complexity of our sales machine! This is completely normal - we will ensure everyone is always treated fairly, but you need to be comfortable with this. For now we are generally trying to optimize for something straightforward here so it’s easy for PostHog (and you) to calculate commission. Fraser runs this process, so if you have any questions, ask him in the first instance.
Variables
Your quota is set for the year and then divided by 4 - this means you don't have to cram deals into the end of a quarter.
Commission is _uncapped_ and paid out on a sliding scale based on the % of your quota you hit. Hit 100% quota, get 100% of commission. 0% for 0%. And 200% for 200%.
Quota is based on $ amount sold, not credits/product usage, so you can't in theory sell a $500k deal with an 80% discount and claim the full $500k to your quota, for example. Ways to hit quota:
The invoice payment amount for any pre-purchased credit deals in the first 12 months after they become a paying customer.
If the purchase is a renewal of an earlier credit purchase (i.e. at the end of the first year) then you'll get recognised on the difference between the initial purchase and renewal purchase.
ARR from monthly customers for the first _12 months_ after you sign them up as a monthly customer as long as you are the primary account owner.
For multiyear contracts, we will true the quota ARR up to the year 1 equivalent amount as you'll have given a deeper discount but there is more committed revenue for PostHog which is a good thing.
The way we work this out is by taking the annual credit purchased by the customer and applying the standard 1 year discount to it.
Your quota will depend on your OTE
A deal counts toward quota in the quarter of its effective date. For annual deals, the effective date is the contract start date or the signature date, whichever is later. For monthly accounts, each payment counts toward the quarter it falls in.
Commission is paid out quarterly, and is subject to clawbacks if the invoices remain unpaid.
We want you to secure upfront payment - which helps PostHog and helps you.
If you close an annual contract with monthly payments, you will still get recognized for the full commission amount, but the actual payout of your commission will be quarterly.
We want you to ensure the customer has paid, and we don't want AEs to throw invoice chasing to a finance person
This means you should make friends with the finance person on the customer's side, and ensure all payment paperwork is in order to allow for the customer to pay.
For monthly customers, commission is only paid after all 3 invoices have been paid
Commission is still paid out quarterly even if the customer pays monthly
Overdue invoices from the current quarter will be excluded from commission payouts, with the cutoff being the 14th of the calendar month following the quarter (January, April, July, and October)
Invoices that are issued in the final period of the current quarter, but are due at a date beyond the 14th of the calendar month following the quarter (January, April, July, and October), will be paid on the good faith assumption that the customer will pay on time and you will assist in securing timely payment. If the invoice becomes overdue in a future quarter, it will be subject to a clawback in that quarter.
If we have to give a customer a big refund, we’ll deal with your commission on a case by case basis or via clawback.
Commission payments are made at the end of January, April, July, and October. Fraser will send you an email that breaks down your commission and explains how you did.
In your first 3 months, you'll be paid 100% OTE fixed. You can find more info on how quotas work in your ramp period in the new hire FAQ
Performance expectations for Technical Account Executives
There are cultural and role-based expectations for TAEs at PostHog. We also now have enough data to define minimum performance exceptions for TAEs relative to the annual commmission targets.
After your ramp period, you should expect to have a performance conversation with your lead and Ben if:
You are under 80% of your annual quota, _and_
You have finished two consecutive quarters under 70% of your quarterly target
These standards are likely to change as the TAE role evolves. Any changes will be reflected in the handbook. We will always consider any relevant context when having these conversations with you - quota does not exist in a vacuum!
How commission works - BDRs
General principles
When thinking about commission, we want to particularly incentivize:
Generating high quality leads
Getting people in who fit our ICP, ie. are easier for us to sell to
We aim for a 70/30 split between base/commission when calculating OTE by default.
This plan will almost certainly change as we scale up the size and complexity of our sales machine! This is completely normal - we will ensure everyone is always treated fairly, but you need to be comfortable with this. For now we are generally trying to optimize for something straightforward here so it’s easy for PostHog (and you) to calculate commission. Fraser runs this process, so if you have any questions, ask him in the first instance.
Variables
Quota is based on the number of sales qualified opportunities you generate - basically when an account is moved into the initial Opportunity stage in SFDC.
In your first 3 months, you'll be paid 100% OTE fixed. You can find more info on how quotas work in your ramp period in the new hire FAQ
After your ramp period, the 30% commission portion of your OTE will be based on 9 sales-qualified opportunities per quarter per representative, which breaks down to 3 sales-qualified opportunities per month per representative.
Your quota is set for the year and then divided by 4 - this means you don't have to cram meetings into the end of a quarter.
Commission is _uncapped_ and paid out on a sliding scale based on the % of your quota you hit. Hit 100% quota, get 100% of commission. 0% for 0%. And 200% for 200%.
Commission is paid out quarterly.
Team lead quota
From your first full quarter as a team lead in Sales, you will move to a 60% base 40% commission split in reflection of your new player/coach role. This will be based on your team's quota attainment although you will still have your own individual quota target.
Your individual quota will be lower than others in the team as you'll be spending more time on managing the team, but we still want you to demonstrate the sales individual contributor skills to your team. You should aim for 80% team management, 20% IC work, and the quota will reflect that.
To calculate the team quota, we combine the quota of all team members with proration applied if they are still ramping:
For fully ramped team members we add 100% of their quota to the team quota.
For team members who begin the quarter still in their first three months in the role we add 50% of their quota to the team quota.
Example: With a flat quota of $250,000 and 3 fully ramped people, and 1 ramping, the team quota would be $875,000 (($250,000 * 3) + $125,000)
If someone leaves the team, we may recalculate the team quota depending on how their accounts and opportunities are reallocated to others in the team. If someone joins the team, we don't change the team target, and don't count their contribution towards the existing target, to keep it simple.
Travel to see customers
You are likely to need to travel a lot more than the typical PostHog team member in order to meet customers. Please make sure that you follow our company travel policy and act in PostHog's best interests. We trust you to do the right thing here and won't pre-approve your travel plans, but we do keep track of what people are spending and the Ops team will follow up with you if it looks like you are wasting money here. We are not a giant company that pays for fancy flights, accommodation, and meals so please be sensible.
Working with engineering teams
We hire Technical AEs. This means you are responsible for dealing with the vast majority of product queries from your customers. However, we still work closely with engineering teams!
Product requests from large customers
Sometimes an existing or potential customer may ask us to fix an issue or build new features. These can vary hugely in size and complexity. A few things to bear in mind:
Engineers at PostHog talk to customers. It's much better to bring engineers onto calls to speak to a large customer to talk to them directly than just do the call yourself and copy and paste notes back and forth. This is especially useful if a) the team was already considering building the feature at some point, b) it's an interesting new use case, or c) the customer is really unhappy for valid reasons and could churn.
Provide as much internal context as you can. If a customer sends a one-liner in Slack, don't just copy and paste into a product team's channel - find out as much as you reasonably can first, ask clarifying questions up front etc. Otherwise the relevant team will just ask you to do this anyway.
We already have principles for how we build for big customers - if you have a big customer with a niche use case that isn't applicable to anyone else, you should assume we won't build for them (don't be mad!)
Finally, if you are bringing engineers onto a call, brief them first - what is the call about, who will be there. And then afterwards, summarize what you talked about. This goes a long way to ensuring sales <\> engineering happiness.
Complicated technical questions
You will run into questions that you don't know the answer to from time to time - this is ok! Some principles here:
Try to solve your own problems. Deep dive the docs, ask PostHog AI, ask the rest of the sales team first - a bit of digging is a valuable opportunity for you to learn.
Similar to the above, don't just copy and paste questions from Slack with no context. Add some commentary - 'they have asked X, their use case is generally Y, I think the answer might be Z - is that right?'. Do some of the lifting here, rather than putting all the mental load on an engineering team.
If you open a ticket in PostHog Support and know which team the ticket needs to go to, assign the ticket to that team so that it bypasses support and go straight to that team.
Working with customers in Slack
Most of our customers use Slack, and it's a great way for us to be responsive to them. Qualifying customers and prospects can get a shared Slack channel, and you should set one up as early as it makes sense in your relationship with them.
We share channels via Slack Connect and add SupportHog so that both PostHog and the customer can raise support tickets directly from a Slack thread — react with the :ticket: emoji or mention @SupportHog. This syncs the conversation into PostHog Support so our Support and Engineering teams can work on customer issues in a familiar context.
See Shared Slack channels with customers for the full setup steps, including channel naming, who to invite, and how to support customers who use MS Teams instead.
It's your job to ensure your customer issues are resolved, make sure you follow up with Support and Engineering if you feel like the issue isn't getting the right level of attention.
Welcome to the PostHog Sales team! We only hire about 1 in 400 applicants, so you've done well to make it here! Unlike a lot of companies, we don't have a super-long onboarding process and would prefer you to be up and running with your customer base as quickly as possible. Here are the things you should focus on in your first few weeks at PostHog to help you achieve that.
Ramping up is mostly self serve - we won't sit you down in a room for training for 2 weeks. If you're not sure who is supposed to make something below happen, the person responsible is almost certainly you!
How to fail
But first...
Sales at PostHog isn't like most other software companies! These are some of the things that you _shouldn't_ do:
Wait til you're ready to talk to customers. Jump in sooner than you feel comfortable - it is by far the fastest way to learn. A great, low-risk way to practise is chat to inbound leads who you think aren't going to be high paying customers - the cost of doing badly is very low!
Lazily forward customer questions to engineering teams without any context. That's super annoying. Instead:
Try to solve the problem yourself, read the Docs etc.
Try asking in #ask-max Slack channel
Ask the rest of the Sales team
_Then_ forward to the relevant engineering team _and add context_ - are they a huge oppo, evaluating or already paying, technical/non-technical etc.? Help them help you
Bonus points for: 'I think [this] is the answer, am I on the right track?'
Execute your previous company's playbook. We're trying to do things differently from 90% of the industry. But please do tell us what has _and_ hasn't worked at previous places.
Keep information to yourself - share openly and frequently the things you are learning, what you've got right or wrong. We don't do lone wolfing here. PostHog is a huge product, so it's ok to ask dumb questions - so long as you've tried to figure it out yourself first!
Use sales BS language - if you don't know the answer that's fine! Don't promise features. Don't use vague, non-specific language. Talk to our customers like real human beings, not 'prospects'. And don't be discouraged if they say 'can we talk to someone more technical'!
Being slow to reply to customers - even if it's just to acknowledge their message. Make sure you have notifications turned on for _all_ messages in your customer Slack channels (not just for mentions).
Technical Account Executive ramp
Day 1
Meet with Ben who will run through this plan and answer any questions you may have. In addition, come equipped to talk about any nuances around how you prefer to work (e.g. schedules, family time etc.).
If you start on a Monday, join your first PostHog All Hands (at 4.30pm UK/8.30am PT) and be prepared to have a strong opinion on whether pineapple belongs on pizza.
If you start on a Monday, join your first Sales standup.
We fill in a GitHub issue every week before this meeting so we are prepared for the discussion topics. Simon will add your GitHub handle to the template.
Rest of week 1
Ask team members in your region to be invited to some customer calls so you can gain an understanding of how we work with customers.
Check out some Buildbetter calls and add yourself to a bunch of Slack channels - get immersed in what our customers are saying.
PostHog integration exercise - by the end of week 1:
Find/build a blank app which doesn’t yet have PostHog integrated. You should be able to vibe code something simple with React using Cursor or Lovable.dev
Once you’ve got your app up and running get PostHog deployed and capturing events and replays. Default config is fine.
Implement a custom event
Implement user identification
Record a loom showing what you’ve done and share it in our team channel
Week 2
During your first week, Ben will go through the sales process with you and answer any questions you may have about the playbook.
Shadow more live calls and listen to more Buildbetter recordings
Towards the end of the week, schedule a demo and feedback session with Ben. We might need to do a couple of iterations over the next few weeks as you take on board feedback, don't worry if that's the case!
Get comfortable with the PostHog Docs around our main products.
We'll start routing new Salesforce Leads to you at the end of week 1. Start to review these and reach out, using a shared booking link with someone else from your region so they can back you up in the first few weeks. This is a great option to practise and fail.
Make sure you're comfortable with the Shared Processes section of the Handbook
Once you start getting leads / accounts, ping Simon to be added to the TAM quota tracker.
In-person onboarding
Ideally, this will happen in Week 3 or 4, and will be with a few existing team members (depending on where we do it) and will be 3-4 days covering:
Demo practice session with the team.
The data we track on customers in PostHog and some hands-on exercises to get you comfortable using PostHog itself.
Deep dive on Vitally tracking.
No stupid questions session.
Weeks 3-4
Focus on taking more and more ownership on calls so that team members are just there as a safety net.
Continue to meet with customers and reaching out to new leads.
Add your Calendly link to your Slack profile so customers can book in with you directly (this works!)
How do I know if I'm on track?
By the end of month 1:
Be leading customer calls and demos on your own
Have evaluations in flight (with support from the team if needed)
Have closed your first prepaid credit deal of any size
By the end of month 2:
Be leading evaluations on your own
Seeing strong conversion from your outreach to new leads
Have closed multiple contracts by this point through the whole process
By the end of month 3:
You've built out a strong pipeline and plan, looking 1-2 quarters ahead
On track to hit 100% quota by the end of month 6
Technical Account Manager ramp
Day 1
Meet with Landon or Tyler who will run through this plan and answer any questions you may have. In addition, come equipped to talk about any nuances around how you prefer to work (e.g. schedules, family time etc.).
If you start on a Monday, join your first PostHog All Hands (at 4.30pm UK/8.30am PT) and be prepared to have a strong opinion on whether pineapple belongs on pizza.
If you start on a Monday, join your first Sales standup.
We fill in a GitHub issue every week before this meeting so we are prepared for the discussion topics. Landon or Tyler will add your GitHub handle to the template.
Rest of week 1
Ask team members in your region to be invited to some customer calls so you can gain an understanding of how we work with customers.
Check out some Buildbetter calls and add yourself to a bunch of Slack channels - get immersed in what our customers are saying.
PostHog integration exercise - by the end of week 1:
Find/build a blank app which doesn’t yet have PostHog integrated. You should be able to vibe code something simple with React using Cursor or Lovable.dev
Once you’ve got your app up and running get PostHog deployed and capturing events and replays. Default config is fine.
Implement a custom event
Implement user identification
Record a loom showing what you’ve done and share it in our team channel
Week 2
During your first week, Landon or Tyler will figure out your initial book of business (10 accounts). We will review these at the start of your second week, and make sure you understand how your targets are set.
Shadow more live calls and listen to more Buildbetter recordings.
Towards the end of the week, schedule a demo and feedback session with Landon. We might need to do a couple of iterations over the next few weeks as you take on board feedback, don't worry if that's the case!
Prioritize your current book of customers, and start reaching out!
Get comfortable with the PostHog Docs around our main products.
We'll start routing new Salesforce Leads to you at the end of week 1. Start to review these and reach out, using a shared booking link with someone else from your region so they can back you up in the first few weeks. This is a great option to practice and fail.
In-person onboarding
Ideally, this will happen in Week 3 or 4, and will be with a few existing team members (depending on where we do it) and will be 3-4 days covering:
Demo practice session with the team.
The data we track on customers in PostHog and some hands-on exercises to get you comfortable using PostHog itself.
Deep dive on Vitally tracking.
No stupid questions session.
Weeks 3-4
Focus on taking more and more ownership on calls so that team members are just there as a safety net.
Continue to meet with your book of customers and inbound leads.
Add your Calendly link to your Slack profile so customers can book in with you directly (this works!)
How do I know if I'm on track?
By the end of month 1:
Be leading customer calls and demos on your own
Have evaluations in flight (with support from the team if needed)
Successfully made contact with _everyone_ in your book of business
By the end of month 2:
Have closed your first prepaid credit deal of any size (net new or conversion to)
Be leading evaluations on your own
Have identified some opportunities to add to your book from self-serve signups who aren't paying yet
By the end of month 3:
Have closed multiple contracts by this point (either new or expansion/renewal) through the whole process
Be driving multiple opportunities for cross sell through your accounts, ie. at least one customer is actively using a product they weren't before you started (at any scale)
By the end of month 4:
On track to hit 100% quota by the end of month 6
Getting your equipment setup right
In addition to following the guidance in the spending money section of the Handbook, there are a few things you should do to make sure you're set up to give high quality demos that look professional:
Buy a webcam. These are cheap, but significantly better than those built into your Macbook. Logitech is perfectly fine here. This should cost up to $100.
Buy a microphone. The mic on your Airpods will not do it. Rode do good quality, affordable mics - nice thing about these is that you can plug in wired headphones so you can still hear yourself talk. Again, up to $100 should be fine.
If you prefer to use headphones with a built-in boom mic instead, that's also ok.
Take calls at your desk. Don't dial in from your garden because it's a nice day and then spend the call apologizing for the lousy WiFi.
You don't have to go all ring light, but think about your background a bit. You don't have to construct some elaborate bookshelf situation behind you, but consider using one of our nice wallpapers.
Alerting setup (for team leads)
We have certain automations in Vitally that your team lead needs to add you to. Please ask your team lead to add you.
Vitally name trait playbook: create a new branch that matches assigned AE to new team member. In this branch, add action to update account trait AE name to name of the new team member. This is used to populate account owner info in tickets created by customers we own, so support knows who to reach out to.
New hire frequently asked questions
How does my quota work during my ramp period?
Your first three months of commission are paid at 100% fixed OTE. This will be calculated based on the date you start. If you start before the 15th of a month, you will get 100% fixed OTE for that month and two of the subsequent months. For example, if you start on Jan 13th, you will get 100% fixed OTE for Jan, Feb & Mar. If you start _on_ Jan 17th, you would get two months of 100% fixed OTE for Q1 and one month of 100% fixed OTE for Q2 in addition to two months of your quota'ed commission.
Generally, you're expected to be able to be the first line of support for customers at PostHog. You should be able to answer _most_ yourself - that's why we hire _Technical_ AEs and AMs after all! #ask-max in Slack can often help too.
Visit the /admin/ endpoint on the cloud they are on. You can then search for them via email and log in. Be careful clicking around here as you can accidentally delete a person/organization! You need to get their permission first unless it's an emergency, i.e. to resolve an incident.
We build PostHog for product engineers. While many non-technical folks use PostHog successfully every day, our sales process is built with technical folks in mind. Once implemented, a customer may use PostHog for all manner of things (and we hope they do!).
Three other general principles to bear in mind:
Aim to drive the sales process as much as possible. Most of our customers in our core segment don't regularly buy software like PostHog, so you will need to guide them through the process - for fast growing startups, this may be their first time. Even for much larger customers, this still may be the case. Remember that we've sold software hundreds of times - it's ok to guide the customer here. Inbound leads =/= the customer wants to drive.
Discovery is an ongoing process - you want to be finding out useful information at each stage, not just going through a checklist at the beginning. Asking 'why' can be a really powerful tool, and you should be curious throughout, not just selling.
At the end of each conversation with a customer, you should aim to be really specific and prescriptive about next steps. If you haven't identified a next step, the opportunity is Closed - Lost. Waiting for a customer to come back to you is not a valid next step - instead you should be saying things like "at this point, usually the next best step is for us to do X".
Maximizing your chance of success
Selling software, especially to larger companies, can be a complex process with lots of stakeholders involved. When moving your deal along you should aim to know as much about the following as possible given where you are in the process (inspired by MEDDPICC):
Pain - Do they have a problem?
Is it painful enough right now that they are willing to adopt a new solution to solve it?
Will PostHog solve this problem for them?
Timeline - When do they want to have a contract signed/solution in place?
Pricing - We should know the rough size of the opportunity, and that is in line with expectations and budget of the customer.
Champion - Are you working with a champion who is going to sell internally?
Are they the buyer (see below) or do they know who the buyer is?
Decision - How are they evaluating us?
Is it competitive? Who?
What is their criteria for success?
Economic Buyer - Sometimes your Champion has to convince upper management to spend money.
Is that person aware of PostHog and on board with signing a contract if an evaluation is successful?
Paper process - After a successful evaluation what happens next?
Do they need a Custom DPA/BAA/MSA?
Is there a security review needed?
Who signs the Order Form?
These are presented in the most likely order that you will be able to discover them, although that is not a hard and fast rule.
They are also available as Opportunity fields in Salesforce and as such you should keep them up to date when you learn more.
This is an overview for what you should actually be doing with a customer at each stage of the sales process. For details on how to manage this in our CRM, visit our Salesforce docs. The steps are:
You get a lead
You qualify
First call (30 minutes) - Discovery & initial demo
Second call (60 minutes) - Technical deep dive (if needed)
Product evaluation
Security & legal review (only if asked - skip otherwise)
Commercial evaluation
Closed - Won or Lost
1. You get a lead
We're constantly experimenting with the best lead types, documented in lead scoring. Info on _how_ leads are assigned can be found here.
2. You qualify
Once you have been assigned a lead, you'll want to qualify them before scheduling a call. Things to consider:
Which products are they looking to use? What's their use case?
How large is their company? Revenue? Have they raised funding? (ie. will they pay >$20k for PostHog?)
What is the role of the person who filled out the form?
Are engineers already involved in the sales process, or will they need to be brought in?
Most companies add friction here by making customers jump on a call first to qualify them. We don't do this when we are confident that product engineers are, or will become, involved in the sale. We may ask for a 2nd call with the engineers involved if we're confident that PostHog can help and want to make sure they agree.
It's also totally fine to ask a customer questions over email in advance of the demo to make sure you're making the best use of their time - just be specific. A few clarifying questions is fine, a 30 question survey is not.
Examples of good discovery questions
- What is the problem? What is this problem affecting?
- What metric is impacted as a result of this? What metric would be improved as a result of PostHog?
- How important is this problem to the wider team?
- What attempts have been made to fix this so far? Why has no attempt been made to fix this?
- Why fix this now? Why fix this ahead of the other important things happening at your company?
- Are you looking at {product} as a point solution that would slot into the rest of your stack, or are you looking to consolidate multiple tools and have a single source of truth?
- What does the rest of your stack look like? What other tools or data would you want PostHog data to connect to?
- Who owns that data stack? Do you have a data team or data engineers?
- Who will be the consumers of PostHog data? How are they currently answering their questions, and how easy is it for them to do so with existing tooling?
If you're pretty sure that they should be qualified out of our sales process, you should still be helpful over email - some customers just use the form to get in touch and don't want to actually have a demo (e.g. they have a billing question or are asking about compliance things like HIPAA.) There is a Claude skill that can help draft genuinely helpful responses to folks like these - it will put together helpful resources from our docs and blog posts that can help customers get started, even if they don't qualify for a call with a salesperson.
Requests for Proposals (RFPs)
There are two types of RFPs:
We have context on what they're trying to accomplish and where we have qualified their specific needs ahead of time. These are solicited RFPs, and we generally reply to these.
We just get an RFP randomly without any context. These are unsolicited RFPs, and we generally don't reply to these.
If it's an unsolicited RFP where we haven't had any prior contact or usage from the company then it is highly likely that you will burn a lot of time for nothing and you are free to decline. If you find the unsolicited RFP otherwise compelling and want to proceed, the suggested approach here is to see if anyone from the company has recently signed up to PostHog. If so, then make contact with them to see if they are aware of the RFP and can provide more information on PostHog's inclusion.
If you can't identify anyone who has recently signed up to PostHog, then ask the person who sent you the RFP for a call to gather more context before making a decision on whether to fill it in. If they aren't willing to get on a call then it's likely that we are not their vendor of choice, and they are using us to make up the numbers in a tender process. As such, we shouldn't spend time on this kind of activity. If you choose to spend time with these, timebox your effort to ensure you are not devoting a week to a 500 question RFP where we have very slim chances of success. Your time is your most valuable asset.
If it's a solicited RFP, you're free to proceed so long as the opportunity is qualified as a whole and you carefully balance the level of effort required in the RFP against the opportunity for you & PostHog. Again, a 500 question RFP may not be worth it if they plan on spending <$20k for PostHog (a 50 question RFP may not even be worth it in this instance)! Use your best judgement, and it is generally still wise to timebox your effort.
Bigger Opportunities at Bigger Companies
When you're working a deal north of $100k at a larger company, the playbook shifts. Generally, expect to challenge their stated evaluation criteria early, as well as sell to multiple people and functions within the organization. You need to dig past the surface-level requirements they may list and get to the real decision drivers. Question the "why" and "how" behind their stated criteria, because committee-driven procurement processes can hide the actual priorities behind "just so" rubrics that can obscure the real reasons they will buy (or disqualify).
On the relationship side, you need a strategy for engaging their leadership and developing champions at multiple levels within the account. If a key leadership stakeholder goes dark, escalate to PostHog leadership to help re-engage. If needed, don't be afraid to translate PostHog titles to something they would understand (e.g. Generic Exec Person = COO). For deals this size, on-site presence can also matter — you should attempt to build relationships in person, not just over Zoom.
Lastly, take a prescriptive and consultative approach to their evaluation process. The larger the opportunity, the more proactive you need to be about controlling the process. Ask for help from your lead, your team, and in Slack. These opportunities take a team effort.
Startups
If they're eligible for the Startup Plan, route them to the application form and disqualify them as it's not an immediate opportunity (but we sincerely hope they grow into loyal PostHog customers). If their usage will burn through their credits quickly, you should feel free to switch their lead status to Nurture and keep close tabs on them. Per our usual approach to sales, we want to make sure they're successful in this "high-use" scenario and are building with us for the long-term.
You can also redirect them to use the In-app support modal if they have a product-related question - this will then be routed to the right team, as well as showing them CTAs to upgrade for high priority support.
Leads below the sales assist threshold (less than $20K ARR)
We often get requests for demos from leads or existing customers who are below our sales assist threshold, and who don't have a defined use case for PostHog. It usually comes in the form of "show me all the features" or "I need someone to demo to me." These can be large time sinks because they are non-technical, don't have a clear idea of what they want, and are unlikely to ever grow into a sales-assist level customer.
We also want to be helpful to our current or potential customers, regardless of spend. Time permitting, we can offer a demo if they are willing to give us the information we need to put something together:
What tech stack are you on?
What features / products are you interested in?
What questions do you have?
This makes the demo actually valuable and can be an opportunity for you to learn more and get some demo practice. You'll also find that 90% of these requesters never respond because they are either unable or unwilling to engage with the questions, which allows you to avoid the biggest time sinks.
If you realize that they will be too small (<$20k) to go through our sales-led process and you are unable to get this information from them, you should route to self-serve.
3. First call (30 minutes) - Discovery & initial demo
Your goals on this call depend on who shows up. You should know who's coming ahead of time and be prepared to change your approach based on the actual attendees.
The ideal outcome is getting engineers to be hands-on with PostHog as quickly as possible.
Path A: Engineers are present on the first call
When you have engineers on the call from a qualified company (ICP fit or otherwise highly qualified), your goal is to get them using PostHog immediately.
Structure:
Intro & Qualification (5-10 min)
Friendly banter
Focused discovery on their use case
Articulate PostHog's vision and how it relates to their needs
Show PostHog in a technical demo as soon as possible
Technical Demo (15 min)
Highly tailored to their use case
Light on pitching, heavy on showing docs and GitHub
Start with their biggest problem first, stay there until they're happy
Call Close (5-10 min)
Part 1: Confirm they agree PostHog solves their problem; scope what success looks like for their trial; answer questions, particularly around pricing: Secure BANT
Part 2: Ask for trial signup or PostHog org conversion; confirm next steps on the call; ensure that any "give" by PostHog receives a "get" from the customer (typically feedback on the trial at this phase)
Answer questions and objections
Success looks like:
They commit to using PostHog in a reasonable timeframe
You have a plan to get their feedback on the product as soon as they use it
When engineers aren't on the call, your goal is to earn a second call with their engineering team, while also being helpful to the non-technical stakeholders in discussing PostHog.
Structure:
Intro (5 min)
Friendly banter
Get BANT info upfront (Budget, Authority, Need, Timeline)
Articulate PostHog's vision
Scope their use case
Qualify or Disqualify (10 min) - we do this politely and constructively. The customer's time is valuable and we know best who succeeds with PostHog, so we're driving the sale.
Qualify if: They have technical capability to succeed, engineers will be involved in the sales process, and there's product/solution fit
Disqualify if: They're non-technical with no engineer involvement, or there's no product/solution fit
Demo (10 min)
If qualifying: Show enough to validate required functionality and earn the next call with engineers
If disqualifying: Show what's needed to validate the lack of fit
Call Close (5 min)
If qualifying: Schedule the next call, ensure engineer attendance, set initial scope for technical demo
If disqualifying: Direct them to better resources, politely thank them for their time, ask them to reach back out when engineers are involved
Success looks like:
If qualifying: You have a call with their engineers on the calendar (Step 5 below) and they understand why it will be helpful
If disqualifying: They understand why PostHog isn't a fit right now and appreciate your helpful transparency
Important: If you can't get a second call scheduled, be skeptical of the opportunity. Keep the task in nurture status until it's on the calendar - only convert to an opportunity after the call is confirmed.
General demo tips
We have various slide templates - ask someone on the Sales team for an invite to our Pitch account. Use the deck as scaffolding, pulling out relevant slides. Do not spend the demo presenting a deck with an engineering team - most people at PostHog spend 90% of the demo call actually in product or talking to the customer about their needs. But sometimes, there is a legitimate need for a deck.
Before you demo, make sure there is enough data to properly showcase our features. If needed, you can use Hogbot to generate more synthetic data. This is built by the sales team for the sales team, so if you see anything you want to improve, don't hesitate to submit a PR!
You should give a relevant and pointed demo - don't just throw everything in, as the customer will get overwhelmed. If you don't show what's important first, people on the call will become distracted.
For example, a customer may say "we need to see how our customers are using our platform". In this case, a good approach is to go straight to Session Replay, then tie Replay into Analytics, then go from there.
Start with what their biggest problem/request is, stay there until they are happy, then move on to point two. We don't want to fall into the trap of doing the same demo for each customer regardless of what they say at the beginning.
Make sure you cover:
Who is there and what their roles are - in particular, are they the decision-makers?
Why do they _need_ PostHog?
Demo specific product features according to what they asked for
Don't promise things we can't/don't want to deliver
How pricing works with an indication of their potential spend if you have enough information
Next steps - this is really important, don't just end the demo with no clear follow-up action
4. Second call - Path B (60 minutes) - Technical deep dive
This call happens when engineers weren't on the first call. Your goal is to qualify the opportunity through the engineers and get them hands-on with PostHog.
Structure:
Intro (5 min)
Friendly banter
Confirm everyone's roles and responsibilities
Set context from the previous call
Reiterate PostHog's vision
Discovery (15 min)
Confirm use case(s) relative to the engineer's understanding
Dig into the engineer's role in shipping and their workflow
Confirm BANT, particularly timeline as it relates to the PostHog implementation
Understand their technical stack and how PostHog fits in
Technical Demo (30 min)
Given the likely mixed audience, you can take a broader view of PostHog and how it supports technical and non-technical users alike.
Even so, cater to the engineer's role in the project and the power of PostHog for product/engineering teams
Show relevant documentation and GitHub integrations
Check for engagement from the buyer persona - note any disengagement
Start with what their biggest problem is, stay there until they're happy, then move on
Call Close (10 min)
Ask for trial signup or PostHog org conversion - be specific in asking for clarity here.
Ensure that any "give" by PostHog receives a "get" from the customer
Answer questions and objections as they arise, particularly around pricing.
Be specific about next steps
Success looks like:
You've met the engineers and understand their role
You've qualified the customer's use case and involvement in the project
You know when the engineers hands will be on keyboards trying PostHog
You know how/when the opportunity will convert
BANT
By the end of either the 1st or 2nd call with a customer, you should have a defined idea about:
Budget - Calculate and share a rough ballpark figure based on which products they'll use and their expected usage. Articulate the process by which a sales-led trial will help them refine the estimate.
Need - Is PostHog a good fit? Be politely honest if we're not, to avoid wasting everyone's time.
Authority - Who will make the decision at the customer organization? Who holds the budget?
Timeline - When does the trial start? When are they looking to make a decision/have a contract in place?
It's really easy to convince yourself that you've got a well-qualified opportunity after a demo goes well. Everybody has been laughing and having fun so they must love PostHog right? You need to be more objective than that - ask the AI in the call recording to rate you on BANT qualification to see whether you actually got all of the information you need to confirm that a real opportunity exists here. If you are missing any qualification information, don't be afraid to go back and ask your champion for additional context here. It'll save you wasting a whole bunch of time helping a customer in an evaluation where they aren't serious about buying PostHog, and the inevitable Closed - Lost which comes as a result of that.
5. Product evaluation
Once qualified, and if you think they are a good prospect for our sales-led process, your first priority is to try and get them into trial of PostHog with a shared Slack channel as quickly as possible. If you close them, a shared Slack channel will also be their primary channel for support. Invite SupportHog to the channel so tickets can be created from Slack. React with a 🎫 to customer messages or mention @SupportHog to create a ticket in a thread. Generally it's better to seek forgiveness than ask permission for adding people to a Slack channel - use your judgement.
Some customers may wish to use MS Teams rather than Slack - SupportHog works in Teams too. See Using MS Teams on the shared Slack channels page for how to get set up. Before adding the customer into the channel, remember to test it to ensure ticket creation is working correctly.
You should then follow up with a standard email/Slack message that:
Summarizes what they’re after and how Posthog is a great/bad fit
Lays out next steps on both sides
Shares a proposed timetable for the evaluation and onboarding process
Includes any useful links (e.g. Docs page, competitor comparisons, relevant case studies)
Probably as a separate message, you should set out the criteria for the product evaluation to be considered a success - the evaluation will almost certainly fail if you just leave the customer to noodle around trying PostHog.
If the customer isn't super clear on how to articulate the success criteria then use the following as inspiration:
Product/web analytics + session replay: get tracking set up, turn on replay, privacy controls, figure out user ID, get set up insights/dashboards.
Feature flags + experiments: snippet, FF in the code, person ID and properties for targeting, deploy flag, run the experiment.
Surveys: deploy a survey, view and analyze the results
Data warehouse: set up the warehouse, sync at least 1 data source or pull additional person data in to enrich an insight
Don't be over-reliant on support during the evaluation. As the AE, you should be highly focused on customers during their evaluation to maximize your chance of success. We deliberately hire people we know customers will love working with, so now is your time to shine.
Guide them on how to set up tracking depending on their app paying attention to common points of friction such as:
Things we know companies often want to track (e.g. the AARRR framework).
Once you have a week's worth of data in, calculate pricing based on their actual usage and proactively share this.
A week before the trial period ends have a wrap-up call to ensure that they have seen everything they need to see, and identify any last remaining areas you can help them with, and next steps after the trial ends.
In an ideal world this involves multiple calls per week during the trial period so that you can build a trusted relationship with the customer, but don't force that if they prefer to use Slack/Email.
If non-technical people such as Product Managers, Marketing, etc. are involved we know from prior experience that the PostHog UI, while powerful, can be overwhelming, especially if they have used similar tools in the past. You should be prepared to run multiple remote or in-person sessions with these people to ensure that they get what they need out of the evaluation.
We usually set up the following trials depending on likely contract size:
$20-60k - 2 weeks
$60k+ - 4 weeks
5. Security & legal review
Most customers don't need this beyond sharing our existing documentation. This step often occurs in parallel with product evaluation. Usually only bigger companies ask for this.
You do not need an NDA to share PostHog internal policies - by default most of these should be publicly available in the Handbook anyway, though some are only stored in Drata. If a customer asks you to sign their NDA, you can sign, but have our counsel review it first. As a starting point it must be governed by US law, and mutual.
If the customer requires a vendor questionnaire or security questionnaire then it's best for the AE involved to try and fill it out. If a company reaches out initially with this request, it's often best to try and understand if the customer has an intention to pay or at least grow into a paying customer before investing a lot of time filling it out. If there are any questions that are unclear post the specific question in #team-people-and-ops channel. It is easy to get driven into filling out security questionnaires for accounts that would come in below the sales assist threshold. If the lead is pushing security review without having had any commercial discussions, be transparent up front and let them know that we only do security review for accounts at $20k annual spend or greater. We are happy to work with them to understand their usage, and at that point, further entertain security discussions or point them towards a self serve path.
Some customers may need payment details up front as part of their vendor onboarding process. Stripe allows you to generate these ahead of them signing the contract — you can see how to do it in the billing guide for applying credits.
If you need help with anything data privacy or MSA-related, ping Fraser for help.
6. Commercial evaluation
The Contracts page has full guidance on the nuts and bolts of how to put together a commercial proposal - we use PandaDoc.
Don't be the AE who gets to this point and suddenly realizes you have no idea who the buyer is! You should already know this, their budget, their purchasing process etc. already as part of your discovery - if you're finding out now, hopefully it's not too late...
By this point, you may have run into some additional objections. These are the most common, and how to handle:
Gap in the product - introduce the customer to the relevant product engineer to build together (but first agree with product team if it’s a reasonable ask). We have found this approach works exceptionally well for our newer products.
Pricing issue - understand their budget; our discounts section had the different levers you can pull to get a customer to the right price point. You can also help them tune their usage to lower costs. We don't buy customers out of existing contracts, and we don't do deals where year 1 is super cheap then we ratchet up the price in year 2.
Performance (e.g. slow dashboards) - for very large customers, usually get Tim involved, or he can loop in the right engineer to help.
Confidence in PostHog - often this Handbook page is enough. For Very Large companies who need to be sold a bit more on the company vision, you can get James H involved.
Unsure how much credit they need - suggesting the customer pay monthly for one or two months can help here, especially when there is not a technical driver that can do the mental math to figure out volumes. It's also a good expectation to set at the end of the trial that they will roll onto monthly, which can be pitched as a way to de-risk for the customer if there are still loose ends or a deal is dragging.
Ahead of the contract being signed, you'll also need to understand the customer's invoicing process. Companies will typically have a Finance or AP team who should be the billing contact in Stripe. Make sure you are also aware of any special invoicing requirements (e.g. a Purchase Order number) well ahead of the invoice being generated. Follow our contract rules here - e.g. no payment by check, ever.
7. Closed - won
Hooray! This is defined as when the contract is signed by _everyone_. 'They're about to sign' - NOT CLOSED. 'I've sent a DocuSign' - NOT CLOSED EITHER.
If an opp moves forward with PostHog on a month-to-month basis, but is below $20k annual spend, change the type to "Monthly Contract" and mark it as closed - won in Salesforce.
Once the contract is signed, it lives in PandaDoc. Next step - get them set up with billing.
Now it's time to set up an onboarding plan. We will templatize this, but for now you should send them something in the first week that includes:
How to manage billing/credits
Set up regular calls/checkins
$60k+ - every 1-2 weeks for the first 6 months, then every month
$20-60k - every month for the first 3 months, then quarterly
Schedule training for the champion and/or additional people as needed - the more people you get successfully using PostHog, the more likely they are to retain
Here is minimum checklist of things that we find customers should know how to do:
Simon and Ben review accounts every month to see if/when it makes sense to reassign accounts once they've closed.
7. Closed - lost
Oh no! It's ok - the most important thing here is that we learn. You should capture the reason in the Salesforce opportunity - this could be:
Product/feature gap
Performance concerns
Security/privacy concerns
Pricing
They chose to stick with current setup
Champion left
Business restructured/disappeared
Don’t know (disappeared)
Add detailed comments as well, including what, if anything, we could have done differently (even if not realistic - e.g. build an entirely new product).
For certain categories, you should create followup tasks:
If they went with a competitor, create a reminder to check in with them in 9 months’ time.
If it was a feature gap, contact them when that thing is built using the sub-categories above.
If it was a security/privacy concern, contact them when we get the relevant certification etc.
If they chose to stick with current, check in again every 6 months.
Share info about closed-lost people internally where it will help us learn - this may be with the sales team, relevant product team, or the company as a whole in Slack. The important thing is not to blame each other for losses, it's to find opportunities to do better next time!
We are not doing this to 'go enterprise' - for now we're trying to reach more of our ICP.
Our investors did not ask us to do this - we came up with it ourselves.
_So why are we doing it now? I thought our inbound pipeline was good?_
Outbound sales is a thing we will need to get really good at as we continue to scale PostHog, as 100% inbound eventually dries up. We are not going to be the first company in history to build a huge Saas business with zero outbound, and most companies like us start thinking about outbound around our ARR. Even the largest, most beloved devtool products of all time do this - they just do it in a smart way.
We want to start doing outbound now because, if we wait til inbound slows down, we’ll panic and make bad decisions, trash the brand, and copy and paste what other boring companies have done in a short-sighted way that doesn't work for our audience.
Outbound is helpful because it is a good way to generate more leads in a semi-predictable way - and there are lots of cool ways to do it in 2025 using GTM engineering, agents etc. We should view outbound as a type of hyper-focused _marketing_ that generates sales opportunities.
Let's get on the same page - what _is_ outbound?
‘Outbound’ means a few different things. This is how we think about it in relation to customers:
Using PostHog and spending a lot of money
Using PostHog and spending a little money
Using PostHog with good engagement/high ICP, but not spending any money
Person signed up at some point, but not really using, usually just kicking the tires
Not signed up, but has heard of PostHog
Not signed up, never heard of PostHog
None of these people are currently talking to us - that's why they are under the umbrella of 'outbound'.
We’ll call 1-3 ‘warm’ outbound and 4-6 ‘cold’ outbound.
What we're doing today
Our model is:
TAMs do warm outbound to group 1-2, and BDRs are experimenting with group 1 as requested.
BDRs (Lorena Viana, Andreas Ford, and Melad Khajepour) do warmish outbound to groups 3-6
TAEs do cold outbound to a top 10 list in groups 5-6
Our focus today is on inbound leads, getting much better at warm outbound (we have a huge number of leads that we could be converting better), and experimenting with colder outbound. Lorena Viana is leading our experiments today with the .
Check out the leads page for more detail on lead types, where they go, and the specific outbound campaigns we're running. These are changing very frequently as we figure out what does and doesn't work.
If they’re interested, we’ll show them how to try PostHog and help them along the way; if they’re not a fit, we’ll say so honestly. We need to earn the right for each step and not assume their interest.
So, what does that mean for a first conversation? We:
Do research & get context
We are human & transparent when we meet them
Explore their role & current state/stack
Qualify or disqualify
With explicit permission, give a brief PostHog pitch
Ask the hard question
Provide a relevant next step & schedule it on the call
Action the task
Rinse, lather, and repeat
Goal: help them decide if PostHog solves a real problem, not close in one call.
In order:
1. We do research & get context
Do basic account research:
Prompt your LLM of choice for facts (especially with MCP access). Ask:
What's their tech stack? (Job postings, BuiltWith/Wappalyzer, 1Password)
Recent company news (funding, launches, hiring)
Their role + tenure (LinkedIn, their website)
Why did they agree to this meeting? (Read the sourcing BDR’s notes in the New Business Slack)
What problem or pain did the BDR flag?
Use this to form a call hypothesis.
2. We are human & transparent when we meet them
We contacted them. This call only makes sense if we can solve a real problem for them. Start with:
"Hey [name], thanks for making the time. I know this was a cold outreach from our team, so I really appreciate you giving me 30 minutes."
"Before we dive in, I'm curious - what made you decide to take this call?
Often this is enough. If they’re vague or skeptical, get specific with your pre-prepared hypothesis:
"[Our BDR mentioned/I saw] that [specific trigger - e.g. you're growing team/launching new product/scaling analytics]. We work with companies at your stage who struggle with [specific pain - e.g. fragmented analytics tools/poor data quality/lack of actionable insights]. I wanted to understand if that's actually a problem you're facing."
"If it is, I can share how other companies like yours have solved it. If it's not a problem, I'll tell you honestly (or you can tell me) and we'll keep this short. Will that work for you?"
If they answer clearly, set a simple agenda:
"Got it. Here's what I was thinking for today: I'd love to understand how you're handling [your role/the use case behind the trigger] now, what's working and what's not, and then share how other companies like yours have approached it. If it seems relevant, we can go deeper. If not, I'll tell you honestly and we'll keep this short. Sound fair?"
3. Explore their role & current state/stack - find the pain
As Charles Cook says, companies don’t buy software; humans do. Start with their role/team.
"Tell me more about your role and team."
Then move to the trigger/use-case:
“How are you thinking about [use-case/trigger] in that role/team? What do you need to understand about your product/users/customers?"
Other prompts:
"What are you using for [use-case/trigger] today? And how'd you end up with that setup?”
"What do you love about it? What drives you crazy?"
You’re digging for pain, urgency, and priority in this part of the conversation. Drill in as needed:
What's the pain and is it urgent/quantified? - "You mentioned [pain]. Help me understand the impact. What's that costing you - in staff time, in missed opportunities, in money?"
Is it a priority, and do they have a sense of timeline? - "How much is [frustration] actually getting in the way? Is it blocking you or just annoying?""Is there a timeline or trigger that makes solving this more urgent?"
What does the decision process look like? - "Hypothetically, if you did decide to switch tools, how does that work at [company]? Who gets involved?""Who controls the budget for this kind of thing?""Have you ever bought a tool like this before at [company]? What was that process like?"
4. Qualify or disqualify
Run a quick mental evaluation of their answers on the call. Assess four factors:
Specific pain identified
Line of sight to impact (time/money)
Timeline (next 6 months)
Authority or direct line to buyer
If unclear, ask directly, e.g. timeline:
Why is this a problem you're trying to solve this / next quarter?
Their answer tells you if this is a priority.
If you have fewer than four, disqualify politely.
"Based on our conversation, and being completely honest, I don't think we're the right fit because [reason]. My recommendation: [alternative]. If [use-case/trigger] changes, do please reach out."
If you have all four, ask permission to pitch.
Disqualify outbound tasks that won’t convert.
Bonus: end early if they’re disqualified or disinterested. If highly qualified and eager, skip the pitch and go straight to a next step.
5. With explicit permission, give a brief PostHog pitch
Open with what you heard and ask for permission to pitch:
"Based on what you shared - [their pain] - let me tell you how PostHog works and you tell me if it's relevant. Does that work for you?"
Pivot to a tailored elevator pitch (below is generic):
"PostHog makes dev tools that help product engineers build successful products. These include many discrete tools that help with user behavior and analytics, product engineering, communication and data - all in one platform.”
"Companies switch for three reasons: (1) tired of fragmented tools, (2) want engineers and product teams to have direct access to data, (3) our transparent, usage-based pricing."
6. Ask the hard question
Ask:
"Does that sound like it solves the problem you described?"
If they’re uncertain, emphasize the free trial:
"Knowing that we offer folks like you a free trial period to evaluate PostHog for yourself, does it sound like PostHog solves the problem you described?"
Wait. Embrace the pause. And, get their answer. If we don't solve a problem for them, this isn't worth continuing.
7. Provide a relevant next step & schedule it on the call
If qualified and interested, propose a next step and book it on the call:
"What makes sense as a next step? Demo? Trial? Talk to your team?""Okay, I'll [take action]. Let's reconnect on [book specific date/time now]."
If hesitant or marginal, ask:
"Here's what I'm hearing: [summary]. Not sure if we're a fit yet. What would help you figure that out?"
If they disqualify themselves post-pitch, disqualify:
"Based on our conversation, and being completely honest, I don't think we're the right fit because [reason]. My recommendation: [alternative]. If [use-case/trigger] changes, do please reach out."
8. Action the task in PostHog's Salesforce
This is internal hygiene. Track tasks to reflect the opportunity:
If qualified + next step, create an opportunity in Problem Agreement and use stage exit criteria
If marginal/no next step, switch task from In progress to Nurturing and progress them toward an opportunity
If not qualified, disqualify with reason and share feedback with the sourcing BDR in Slack
9. Rinse, lather, and repeat
You should always aim to get them into a shared Slack channel or establish a regular communication cadence with them (call/email). Nothing will happen if we aren't talking.
Where else you take a qualified outbound sales opportunity is dependent on the specifics of your conversation.
Ask for an introduction to the best contact at the company
Record a Loom of specific features to show how PostHog works
Ship them documentation and a code sample to demonstrate how PostHog can be configured
#domoreweird in a delightful way
Schedule a kickoff to get their trial started
Ship them merch
What won’t change: qualify each step, solve a real problem, and don’t assume interest just because a task became an opportunity. Stay focused on their pain and you’ll earn the right to keep moving.
How TAEs accept and work BDR opportunities
Whether a BDR-sourced meeting becomes an opportunity is dependent on a set of fixed criteria to ensure the consistent and smooth handoff of qualified pipeline vs. simply converting oops based on vibes.
When a BDR meeting becomes an opp
Create an opportunity in Problem Agreement only when all of the following are true:
The meeting was held - No-shows are not qualified. If rescheduled, fantastic - the meeting must happen before opportunity creation.
ICP fit is confirmed — the account matches who we build for or the "fit" for PostHog is otherwise undeniable.
A specific pain is identified — there is a concrete problem PostHog addresses.
The prospect agrees the problem is worth exploring -- as we're reaching out to these folks, they need to tell us it's a big enough problem to solve.
There's a known timeline — they intend to do something about it inside a defined window (roughly the next two quarters).
You have access to authority — you're talking to, or have a confirmed path to, whoever decides or could champion PostHog internally.
A mutually-agreed next step is on the calendar — demo, trial kickoff, technical eval, with a date. Ideally, we secure a verbal commitment on the call, and this is an emphasis point for TAEs. No committed next step, no opp.
How our outbound data pipelines work
So far we run three automated pipelines that enrich accounts, surface timely signals, and qualify targets. Abhischek Thottakara manages these.
Salesforce enrichment (weekly)
Every week, we pull all Salesforce Accounts and enrich them via the Harmonic API with company info like funding history, headcount, and traction metrics. Our SSoT of Accounts (Single Source of Truth) is the Salesforce Accounts table.
Before enriching, we filter out personal email domains (Gmail, Yahoo, etc.) and normalize website domains so matching is consistent.
Job switchers → Clay (daily)
A daily query (Clickhouse + Customer.io) detects job-change signals — someone who was at a company using PostHog just moved to a new role. Only changed or new records are sent to a Clay webhook so we stay within Clay's submission limits.
Why this matters: when someone who already knows PostHog changes jobs, that's a timely outreach moment. They're evaluating tools at their new company and already have context on what we do.
Product-led outbound → Clay (daily)
First, a daily Warmbound query pulls a base set of target accounts filtered by revenue band (MRR $100–$499), company size (50+ employees), and company type.
Then a second qualification step filters those accounts against product signals. Only accounts that pass both steps and have changed since the last sync are sent to Clay.
An account passes the second step if it shows buying intent through signals like:
Using two or more PostHog products
High event volume
Two or more new team members in the last 30 days
Adopting new products they weren't using before
This focuses outbound on accounts that are already engaged with the product (i.e warmbound), not just random companies that match a firmographic profile.
Our primary focus is on making our paying customers successful, not forcing sales through. This mostly means an inbound sales model, but we are also running some outbound sales experiments.
While this means working with a smaller number of users than typical B2B SaaS companies, we know that the people we talk to are mostly already pre-qualified and genuinely interested in potentially using PostHog.
Our teams act as genuine partners with our users. We should feel as motivated to help and delight users as if we were on their team. In practical terms, this means:
No BS sales-y talk - we are direct, open and honest with customers. We share as much as possible publicly, rather than hiding it behind a mandatory demo call. We are honest when we don't know the answer, or if we're not sure that PostHog is the right solution for a customer.
Speed - we are weirdly responsive. If a customer is in a rush, we do our best to work at their pace. We are clear about expectations, and do not promise what we cannot deliver to close a deal.
Engineers helping engineers - there is nothing more frustrating than talking to a salesperson who can't give you all the answers. We keep 'let me find out from the team' to an absolute minimum.
Being power users of PostHog is a must - otherwise we won't be credible. PostHog is a big and growing platform, so this is a challenge to stay on top of!
We prioritize getting people set up on multiple products as early as is feasible, as this makes PostHog far more valuable to them and increases our chances of retaining them.
We don't do margin negative deals in order to win - this doesn't set us up for a successful long term relationship with a paying customer if we're ultimately losing money to land them. Yes, this includes fancy companies whose logos would make us look good.
Our teams
We're not one big Sales team. We're several small teams, each owning a different part of the customer journey:
New Business Sales – our Technical Account Executives (TAEs) own initial inbound contact and make it easy for users to become paying customers. Our business development representatives (BDRs) sit here too, running warm outbound and handing qualified leads to the TAEs.
Product-led Sales – our Technical Account Managers (TAMs) grow and retain a book of existing customers. We run this as two regional teams, East and West, to cover both time zones.
Customer Success – our Customer Success Managers (CSMs) focus on retaining customers, split across Europe and North America.
Onboarding – our Onboarding Specialists support hundreds of newer customers at scale, getting them set up and on track for long-term success.
Not on one of these teams but need to reach the humans who look after a customer? Post in #group-cs-sales-support. It's the cross-team channel for everyone who owns customers, so someone will pick it up or point you to the right person.
Our vision
Things we want to be great at
Technically capable: We deliver genuinely useful insights about things those customers care about (can be purely PostHog-related, but also general advice). Our ICP are ‘self-servers', so ideally we teach them how to do something, rather than doing it for them. A great support experience is part of this.
Speed: We want to be highly reactive, low process, and reliant on other teams as little as possible to ship things. We want to get stuff wrong quickly, then iterate.
Cross sell: PostHog gets much more powerful as customers adopt multiple products that all share the underlying data. And they stick around longer. It's a win win.
Warm outbound to product leads: We get hundreds of ICP signups to PostHog every week, and we want to make sure we're laser focused on ensuring they have the best possible experience with PostHog by proactively reaching out to them based on certain triggers. Some people call this 'warm outbound'.
Things we're interested in trying out
Cold outbound: Most companies do this really badly. We're interested in seeing how we could do this the PostHog way.
Things we don't want to spend time on
Events: These _may_ be a good way for us to reach more of our ICP in future, done in the right way, e.g. by giving talks. However events are not a scalable/automatable channel, and are slightly in the zone of 'outbound sales'.
Winning the deal at all costs: We have overall ARR targets at PostHog, but these are not exclusively achieved by the Sales, CS & Onboarding teams - the vast majority of our paying customers come in without ever talking to us. This means that revenue isn't these teams' responsibility alone, so we don't have to close deals where we get a short term bump to revenue in exchange for long term pain/churn (e.g. forcing a non-ICP deal to close with extremely discounted pricing).
How to work with different types of customer
We look after customers who are paying or could pay $20k+/yr. This means sometimes we will work with existing smaller accounts if we see potential to grow them into larger ones.
We've written an internal playbook for how to manage different types of customers - this goes into a lot more detail about company style, how they work, likely PostHog adopters, how to communicate etc.
'Enterprise' customers
As we get bigger, we're getting more inbound demand from larger organizations which have a very different buying process from our smaller customers. If we want to reach our ambitious revenue goals, we'll need to get good at selling to this segment of customer. However, we need to do this without compromising our focus on building a great product for our ICP.
To prevent us going down the wrong path with deals like these, we follow 4 simple principles:
We don't contract deliverables. Otherwise a single customer could have too much of an impact on team morale and priorities.
We will build things for a big customer, as long as we are confident they won’t be the only user of that thing.
Customers need to try PostHog before they ask us to change things. We love feedback from customers. We don't love big requirement documents from people that haven't used our product before.
We don’t care about losing deals. If we have to walk away from a deal because we'd have to compromise on these principles, we will. We can do this because we have a really strong growth engine with our ICP customers.
We'd typically define a deal as a large deal if it has most of the following:
The customer puts us through a lengthy procurement process (3+ months)
The customer wants us to build new features
There are multiple stakeholders on the customer side, some or all of whom are not engineers
The deal is larger than $250k/year
Who we are
Our people are spread across the teams above, each with its own small team page. In addition to people who share PostHog's culture, we also value:
People who have very high empathy with product teams and their needs
People who are happy to choose their own objectives if it meets a business goal
Low ego, and a willingness to turn around even the most disgruntled and unreasonable customer
Hands-on people not motivated by managing a team
We would want to buy PostHog from them - this is more important than cool logos
Staying current with what we ship
Being a power user of PostHog means knowing what just shipped. The #changelog Slack channel makes this easy, and we recommend everyone on the Sales, CS & Onboarding teams joins it. It's owned by the Wizard & Docs team and updated constantly as PRs merge.
The channel is populated by agentic workflows that scan merged PRs and feature flag changes and summarize them into it. Authors can also opt in or out using the Publish to changelog? checkbox on the posthog/posthog PR template, or via the @posthog Slack app. See how to publish changelog.
PostHog has a broad and growing set of products, and folks in GTM roles need to develop and maintain deep product knowledge for each individually, as well as understand how they work together. This deep understanding helps us drive initial adoption of PostHog as well as cross-sell and expansion. Without a structured enablement process, we face several challenges:
Onboarding gaps: New joiners lack a clear path to learn our products systematically
Keeping current: With continuous product development, it's difficult for team members to stay up to date on changes and new features
Uneven expertise: Knowledge levels vary across the team, leading to inconsistent customer experiences
Missed opportunities: Without comprehensive product knowledge, we may miss adoption and expansion opportunities with customers
Rather than hiring an external sales enablement person (who would need significant time to ramp up on PostHog and wouldn't speak with customers regularly enough), we're leveraging internal expertise to build and maintain our enablement program.
How it works
Subject-Matter Experts (SMEs)
Each product area has a designated SME from the Sales, CS, or Onboarding teams. The SME is responsible for:
Coordinating content creation for their product area (not necessarily creating everything themselves)
Keeping content current as products evolve
Facilitating knowledge sharing through regular updates
Being a bridge between GTM and Product to ensure a two-way feedback loop exists
Important: SMEs are enablers, not gatekeepers. The goal is to level up the entire team, not to create dependencies on specific individuals.
Content areas
For each product, SMEs should develop and maintain content covering:
Sales messaging for customers not currently using the product
Demo best practices showing how to effectively demonstrate their product
AI features how to use PostHog AI for maximum effect within their product
Implementation considerations to help customers avoid common issues
Real-world use cases demonstrating practical applications
Competitive positioning relative to alternative solutions
Content should be primarily recorded (Loom, Gong) or visual (Pitch) to support our async, distributed team.
New hire onboarding
New joiners to Sales, CS, and Onboarding teams go through PostHog GTM Academy, which incorporates product training content from SMEs in a structured learning path. This ensures consistent foundational knowledge across the team.
Staying current
It's on the SME to schedule a regular (nominally monthly, but this may vary by product - use your judgement here) update call with the GTM team and someone from their product team to cover:
Share recent developments and new features
Demonstrate new capabilities
Hold a "no stupid questions" session for team members to ask anything about the product
We're a global team. Try to schedule the meeting to get as many folks live as possible (8-10 AM Pacific time is an ideal slot here), but also ensure it is recorded.
Content storage
Handbook: This page lists SMEs and links to training materials
Video content: Stored in Loom
Written/visual content: Stored in Pitch or Google Drive
Last updated dates: Displayed alongside each product area's materials
All content should include a "last updated" date so team members know they're working with current information.
As we develop content, we can link directly to it from this page.
Product areas and SMEs
| Product Area | SME | Last Content Update | |--------------|------------|---------------------| | Product analytics | Ben Smith | - | | Customer analytics | Christophe | - | | Session replay | Dana | - | | Feature flags | Sachin, Seb Muriel | - | | Experiments | Sachin, Seb Muriel | - | | Error tracking | Sean M | - | | Enterprise & Platform | Leon | - | | Data pipelines (batch and realtime) | Ryan | - | | Data warehouse | Ryan | - | | AI Observability | Leo | - | | Workflows | Phil | - | | PostHog Desktop | Landon | - | | Logs | Sean | - |
For SMEs
Getting started as an SME
If you've volunteered to be an SME for a product area:
First of all, thank you!
Connect with the product team - Consider joining sprint planning calls to stay informed
Audit existing content - Review what training materials already exist
Identify gaps - Determine what content needs to be created or updated
Recruit help - Enlist others (team members, product team, etc.) to help create content
Establish a cadence - Plan regular content reviews and updates
Best practices
Don't work alone: Work with product teams and other GTM team members to develop comprehensive materials
Stay connected: Join product team sprint planning calls if helpful and time zones allow
Gather feedback: Channel top feature requests to product teams (but don't act as a gatekeeper)
Keep it fresh: Review and update content at least quarterly
What this is NOT
This enablement program is not:
A replacement for individual expertise: Everyone should use SME content to develop their own product knowledge
An expert escalation path: SMEs aren't brought into customer conversations as specialists; the goal is to enable everyone to be effective independently
A one-person show: SMEs coordinate content creation but shouldn't develop everything themselves
Cross-sell playbooks: That's a separate initiative
Customer-facing content: This is internal enablement; customer-specific demos should be created by account owners as needed
New products
When a new product is approaching customer availability:
Identify an SME early in the development process (bonus points if you self identify with a handbook PR)
SME coordinates with the product team to understand capabilities and use cases
SME develops initial training content before general availability
SME delivers a new product training session to the wider GTM team
Product area is added to the table above
Switching SMEs
If you don't want to be an SME for a product area anymore, or want to switch with someone else to stay fresh, first identify someone else who is willing to step in and make the change as a PR to this page.
Most product-led leads land in your queue because they crossed an automated threshold (MRR, ICP score, employee count), a manual referral from Onboarding, Engineering, or elsewhere, or some other qualification. Once it lands in your lead task queue, your job is to decide whether this account meets the criteria for TAM ownership.
This covers the things TAMs look at to make an informed decision. Note: Disqualification can happen really quickly, but often it takes a bit more time to decide if it's qualified. Some accounts will have immediate opportunities and be ready to engage, and some may require more nurturing.
A note on existing resources: Several handbook pages cover the diagnostic tools you'll use during qualification. The Metabase account analysis playbook walks through event composition, billing breakdowns, and project mapping. Checking the health of a customer's deployment covers $identify/$groupidentify patterns, autocapture noise, and implementation quality. Those pages answer "how healthy is this account's implementation?" This page answers a different question: "given what I see, should I invest my time here?"
What you're actually deciding
TAMs have a soft cap of 15 managed accounts. Every lead you take on means less time for the rest of your book. You're asking one question: does this account have a realistic path to $20k+ ARR and meaningful expansion potential across multiple products?
If the answer is no, simply mark the task as "disqualified" with your reasoning. If the answer is "not yet," change status to "nurturing" and come back. If the answer is yes, change status to "in progress" and move fast.
Step 1: Size the opportunity
Open the account in Vitally. You need three things:
Current MRR and trajectory. Check current MRR, forecasted MRR, and the delta between them. A $600 MRR account growing 30% month over month is more interesting than a flat $1,200 account. Look at the last 3 months of invoices, not just the current snapshot.
Revenue composition. Go to Metabase and look at the per-product spend breakdown (see the Metabase playbook for how to navigate this). You're looking at whether revenue is concentrated in one product (fragile) or spread across multiple (sticky), and whether the spend comes from intentional usage or a misconfiguration.
Credit and contract status. Are they on startup credits? How much remains and when do they expire? Monthly plan and growing? That's an annual conversion opportunity. See startup plan roll off for how to handle those accounts specifically.
Quick filters to deprioritize:
MRR under $500 with no growth trend
All spend from a single product under $200
Startup credits with 12+ months remaining and low burn
Already has a TAM or active sales engagement in Vitally (always check before reaching out. If they have an Onboarding Specialist assigned, coordinate with them to ensure no double reach-out is happening)
Step 2: Evaluate the company
Engineer count and company size. Check Harmonic/Clearbit data in Vitally (employee count, headcount growth). Companies with 50+ employees and a meaningful engineering org are more likely to expand. A 10-person startup spending $800/mo might get to $20k ARR eventually, but the timeline is long.
Growth trajectory. Recent funding (harmonic_last_funding_date), aggressive hiring (compare harmonic_headcount vs harmonic_headcount_180d), and early-stage companies with significant capital can qualify even if current spend is below threshold. The new business team learned this the hard way: their inbound lead skill was incorrectly disqualifying well-funded, engineer-heavy companies because it relied too heavily on stated MAU. They added a growth trajectory override for exactly this reason.
Business type and use case fit. The company type tells you which expansion path to lead with. The cross-sell motions page lists the profile of accounts where cross-sell works best: smaller/startup-size without existing tooling, engineer-heavy with direct technical contacts, heavily engaged users pushing the limits of PostHog. The use-case selling guide helps you map teams/roles to the problems they are trying to solve with PostHog.
ICP score. Use it as one signal among many. ICP score is rigid and data completion is always an issue. A -5 ICP score on a well-funded, engineer-heavy company should not stop you.
Step 3: Check the implementation
The Metabase account analysis playbook and deployment health checks cover the mechanics of each diagnostic in detail. Here, the question is different: you're reading these signals to decide whether to invest your time, not to diagnose a support issue. If the high spend is a result of a poor configuration with too much unnecessary volume, you're likely to invest time where there isn't future growth. Helping customers is never a bad thing, but it won't be a high ROI activity for you as a TAM. Though, there are potential opportunities to offer them FDE services (for a cost).
Event composition. High autocapture percentage with zero Actions means they haven't invested in instrumentation. That's both a risk (they might not be getting value) and an opportunity (optimization advice is the strongest opening message you can send). High custom event percentage often means they are more serious, and more importantly, have engineering resources available to invest into PostHog.
Products activated vs. products paying. Check paidProducts in Vitally. Single-product users with obvious cross-sell fit are prime targets. Also check if they've turned on products they're not yet paying for. Experimentation with products, even if in the free tier, shows intent.
Billing limits and conservatism. Fewer billing limits means less friction to growth. Limits set very close to current usage means they're cost-conscious, which gives the annual discount conversation a natural hook. It's also an opportunity to reach out to let them know they are close to possibly losing valuable data.
Data destinations. Data flowing out to a competitor (Amplitude, Mixpanel) is a risk signal. Data flowing to a warehouse (Snowflake, BigQuery) or an ad platform is a stickiness signal.
Project count and workloads. Multiple active projects mean multiple workloads, which means a bigger expansion surface area.
Step 4: Check for existing engagement
Before you reach out, confirm nobody else is already working this account:
Vitally: Check segments (TAM/CSM Candidate, Annual Plan, Active Trial), Key Roles, active conversations, and recent notes
Slack: Look for a channel following the #posthog-[company] convention
Salesforce: Check for an existing lead task or opportunity
Product-led leads can overlap with onboarding referrals, TAE pipeline, and CSM accounts. The sales handover page documents how the onboarding team evaluates these same accounts from their side. If someone is already engaged, coordinate before reaching out.
Step 5: Is it qualified?
Qualify and start working when:
Realistic path to $20k+ ARR based on current spend trajectory
Multi-product expansion opportunity is clear (not speculative)
Company profile suggests they can grow with PostHog (funding, headcount, business type)
You have a plausible first message that leads with specific value
Qualifying a lead means you're investing time in it. It does not mean adding it to your managed book yet. Add yourself as the Account Executive in Vitally and use the "Leads" segment to track it separately. You have up to 3 months to figure out whether a new lead belongs in your book.
Add to your managed book when you have traction:
You've established contact and have an active relationship
There's a concrete plan for prepaid credit conversion or cross-product adoption
Spend trajectory and engagement back up the expansion thesis you started with
You're confident enough to put an account plan in front of your lead and Simon
The AM Managed segment is what triggers quota tracking. Adding an account too early, before you have real traction, locks you into carrying it against your 15-account cap without a clear path to quota credit. Simon reviews and approves AM Managed additions, so come with evidence, not just potential.
Track as a "nurture" but don't add yet when:
Spend is growing but still under $1,000 MRR
Implementation is too early (mostly autocapture, few custom events)
Company has potential but no urgency signal
Set a Vitally task to revisit in 30-60 days
Pass or disqualify when:
Spend is flat or declining with no expansion lever
Company is too small to realistically hit $20k ARR
Usage looks like a misconfiguration, not intentional adoption
Already being worked by someone else
For accounts you qualify, see getting recognized on the deal and getting people to talk to you for next steps. You need to demonstrate concrete sales activity to get the account added to your book. Sending a couple of emails and one call is not enough.
What makes a strong opening message
When you qualify a lead, the signals you found during qualification are your conversation starters:
Optimization opportunities: High autocapture percentage, $identify over-calling, session replay without minimum duration. Leading with "I noticed something that could reduce your bill" builds trust fast.
Missing products that fit their use case: B2B without Group Analytics, mobile app without Mobile Replay, AI product without AI Observability, engineering team with flags but no experiments.
Growth anomalies: A product that just spiked in usage (new product activated, event volume doubling). Screenshot it and include it in your outreach.
Billing page visits: In the org event stream, filter for path name contains 'billing'. Recent billing page views mean they're thinking about cost, which is a natural opening for an annual plan conversation.
A large proportion of our paying customer base sign up to a paid plan without ever talking to the Sales team. We don't want to force these customers through a sales process if they don't need it, but we also know that having a human to help them through the process on hand is likely to maximize the chances of retaining them as a paying customer long term. Longer term, we know that customers who have worked with a member of the PostHog sales team retain better, and are much more likely to expand their usage through cross-sell.
Product-led lead generation
Product-led leads can be generated in different ways - see this page for more info.
Some product-led leads might have already chatted with someone on our team. Before reaching out, take a quick look in Vitally to see if there’s any prior activity, and check in with the AE or team member who was involved to get the full picture if needed. Every lead has a "Vitally account URL" field in Salesforce which links directly to their Vitally profile for easy review.
Working with the customer
Just as with the inbound sales process, it's on you to decide how you qualify the lead. If you think they have potential to end up paying more than $20k a year then you should reach out to introduce yourself and offer help. As they have likely done a lot of research themselves, they may not need a demo so a 30-minute discovery is probably more appropriate here.
Getting people already happily using PostHog to talk to you can be challenging - here are a few things you might want to try.
If it's a viable opportunity then you should convert the lead to an opportunity and then follow the New sales process. Bear in mind that you can join it at any point depending on where the customer is at in their buying journey (e.g. you might skip product evaluation if they are ready to buy). If they are eligible for a shared Slack channel and they do not already have one, set one up.
Even if after speaking with them you think they may not end up at $20k+, you should educate them on how to get help, as well as the value of adding our Scale, Boost, and Enterprise plans.
Startup plan roll off
Customers who are rolling off the startup plan present a unique opportunity, as they are already using PostHog and may well be spending >$20k annually. Just like any other customer, we want to help them reduce spend and get the most out of their existing usage, while also educating them on the savings involved with an discounted, credit-based plan.
For customers that may have started implementation late, or ran into issues during their startup period, at our discretion, we can extend the life of their credits by 3 months. To do so, visit that customer's billing admin page (linked in Vitally), scroll to the bottom, and click the extend startup plan button.
Getting recognized on the deal
As they have already shown intent by signing up/subscribing, you will need to demonstrate that you have actively worked on the opportunity to include it in your book of business. We will use a common sense approach here but sending a couple of emails and 1 call won't be classed as 'actively working'. We want to ensure there is concrete sales activity going on with this customer. Simon will make the call here, escalating if needed.
Some potential customers either expect to pay for professional services to help them get set up. There are others who don't ask for this, but where we can tell it would be helpful for them.
For now this is only a service we offer to potential customers by default, so this will mainly be of interest to the .
Who we can offer professional services to
A good candidate for this probably has some combination of the following:
ARR in the $100k+ region, either today or in the next 12 months (actual spend, not credit)
Large-ish company with complex needs
Have explicitly asked about paid implementation services and training
The team adopting PostHog work in person at a single location
They are not set up with PostHog yet, ie. we would be helping them implement PostHog in their codebase
They are able and willing to give our team access to their codebase
We are helping them get set up with session replay, feature flags, AI Observability, and/or error tracking
If you are working with someone where this might be applicable, ping Ben and Simon first, as we can offer to send a forward deployed engineer to work with them to help get set up. Please don't just offer this to anyone without checking in, as we don't have unlimited capacity.
For ongoing training, this is something that we are solving for separately, but is not within the scope of professional services at the moment.
What work is included
Typically, we will send a forward deployed engineer to work with a customer for a week in person. What we charge depends heavily on the nature and scope of the implementation, but in any case starting at $10k. Simon will work with you to figure out the relevant scope of work and contractual terms.
We don't offer this for free, because it is a valuable service that customers expect to pay for. We also don't offer it as a freebie negotiation tactic, because that devalues it for all other customers.
The specific checklist of what will be implemented depends on the customer, but the following sections detail the broad topics we can cover.
Implementation scoping
This should be conducted ahead of time to ensure that we deliver services according to the customer's needs. We will document a plan for:
PostHog SDK implementation.
User identification.
Privacy controls.
Sampling.
Autocapture tuning.
Custom event instrumentation.
Identifying key insights/dashboards to be created.
At the end of this session we should have a good plan and understanding of any onsite work which needs to take place, as well as who in the customer our engineer will be working with, and what level of access to customer systems they require.
Technical implementation
Here we make sure that PostHog is correctly integrated into the codebase using one or more of our SDKs. We should also:
Implement any user identification or privacy controls that are required.
Ensure they are only tracking the events which they need to (including implementing custom events where necessary).
Integrate the first set of feature flags into their application.
Set up the relevant dashboards and insights as documented in the scoping phase.
Ensure that everything is set up according to our best practice guidance.
Getting started training
Once data is integrated, we should provide an intro to PostHog session to the customer to teach them the basics of how to use PostHog. This will be tailored to their needs but should provide a baseline understanding of how to navigate the UI, where to find events, create insights, filter replays, etc.
Whilst Sales and CS folks also provide ongoing training to customers in their book of business, it's important to ensure they have a basic understanding of PostHog, especially if they are brand new.
Migration
Whilst it's crucial to get live data flowing in to PostHog, the customer may also want to bring over historic data to PostHog from their previous tools. This will normally be product analytics data, and we have both managed and manual processes for this depending on the incumbent tool.
Longer term it's expected that forward deployed engineers will own the managed migration tools and also build out that capability.
Once data is migrated, we may also need to implement dashboards and insights from the previous tool. There's no automated way to do this currently, so we will need a login to the previous tool to understand and recreate the visualizations they need to move over.
If the customer is replacing a feature flagging tool and has existing feature flags in place, we will need to migrate the flags in the codebase and ensure that the flags and targeting are set up correctly in PostHog.
Data connectivity
This will normally involve the setup of realtime and batch export destinations for other tools in the customer's stack. We'll need API keys for the relevant tools as well as an agreed criteria for choosing which events will go to which destination.
This may also involve getting data into PostHog without using our SDKs, for example, by using the Webhooks or Data Warehouse sources.
SQL Query implementation
Some customers aren't able to write SQL themselves and don't want to rely on PostHog AI. We can scope and write the SQL queries that they need, as well as creating the relevant views and person joins so that all of their data is connected.
Statement of work
Before any onsite work we will need to document a Statement of Work (SOW) which outlines the scope of work and the agreed terms of service. We should incorporate what we learn in the scoping phase into this to ensure we have all the customer's needs covered and allocate the right amount of time to the project.
We know things happen and sometimes you might need to issue a refund. Here’s how we handle common scenarios:
Learning curve
Just got off of the startup plan/new client accidentally used us a lot.
We issue refunds or credits in this category if this is the first bill >$1 and/or they meet eligibility criteria as explained below.
Unexpected stardom
Side project sudden volume spike
We issue refunds or credits in this category if this is the first bill >$1 and/or usage spiked by >200% compared to their average usage over the past three months, and the company doesn't have any revenue, or is a hobby project.
Under attack
Bot spike/abusive user drove traffic which in turn increased PostHog usage
We flag accounts with unusual activity spikes for review, and refund or issue credits to cover the overage amount once the issue has been resolved. The issued amount covers any amount exceeding the average usage of the three months preceding the spike.
Wrong setup
New feature trial with incorrect configuration
We issue refunds or credits in this category if the customer was charged for features they didn't intend to use due to default settings or configuration errors, and this is the first occurrence of unintended usage charges.
Eligibility criteria
Customer must meet the following criteria to get a refund:
The request is made within 30 days of the billing date.
The customer provides a reasonable explanation for the request, fitting into one of the scenarios.
The account does not show signs of fraudulent activity or abuse of PostHog services.
In cases of volume spikes, the unusual usage has ceased and there is evidence that the customer has taken measures (like implementing a billing limit or managing event volume).
Repeat incidents
For first incident response, we follow standard policy above and provide guidance for preventing future incidents (e.g. ask them to implement billing limits)
Subsequent incidents:
First, check if the customer has acted on PostHog’s earlier recommendations.
If they have not yet fixed the issue, refunds are conditional. Give them a window to implement the fix, and offer a partial refund (up to 50%) while they address it.
If they have made good faith fixes but the issue still occurred, then we issue a full or partial refund depending on severity.
Always warn that repeated incidents may not be refunded again.
For third incident and beyond, refunds may be declined unless there are extraordinary circumstances (e.g. a PostHog bug).
Request channels and processing
Refund requests can come through different channels:
In-app ticket
Support team reviews the request, issues refund or credits based on the eligibility and criteria outlined above, and responds to customer.
Contact sales form or email to sales@posthog.com Account Executives can direct these to the Support team using the ticket emoji in the #website-contact-sales Slack channel to auto-create a support ticket
Large account requests
For large accounts managed by an AE, AE may lead the customer conversation and can loop in Support or RevOps team as needed to process credits or refund in Stripe.
Processing credits or refunds
How to calculate overage amount
Review customer usage
Before doing a refund, review customer's usage. Some useful sources:
If you have access to Vitally, find the customer's Metabase dashboard link under the 'Usage Dashboard Link' trait. The 'Event counts by type last X days' insight is particularly useful here - you can change the lookback period to see a longer time range.
This dashboard for an overview with usage reports and invoice history.
This dashboard to help identify issues for customers with many projects
You can also make a copy of this PostHog insight and use organization id to review account usage. Note that the org usage report can run 2-3 times per day, so numbers may be duplicated/inflated.
What's "normal" vs "weird" usage:
Normal: Gradual increase, weekly patterns
Suspicious: Sudden 10x jumps, severe spikes
Bot attack: Lots of similar events
Identify baseline usage
Calculate the average usage over the past three months to establish a baseline.
Cross check the amount calculated with the last two invoices paid by this client to make sure they're consistent.
Calculate overage
Subtract the baseline usage from the spike amount to find the total overage. Example: If average monthly usage was 1 million events per month and a spike resulted in 3 million events, the overage amount would be 2 million events.
For event-specific overages (optional):
If you want more precision when a single event type is inflated, use the 'Event counts by type last X days' insight in the Metabase dashboard:
Change the lookback days to find the baseline period before the spike
Identify the inflated event type and compare its spike volume to the baseline
The difference is your overage amount for that event type
Calculate the amount to refund/credit
Use the pricing calculator to calculate the total price for baseline and overage volumes. The difference between the two will be the refund amount.
Alternatively, you can use QuoteHog - go to the usage history tab, build a price option from a specific month's usage, and subtract the inflated volume to see what the bill would have been without the spike.
Don't just put in the overage amount in the calculator - doing this would give you the wrong amount because of our tiered pricing structure. Calculating the difference between regular usage and usage with overage is the accurate way to calculate actual amount.
Add a private note on the support ticket with a breakdown of calculations, the baseline average, and the overage. This transparency can be helpful if the customer has questions.
Refund or credit?
Issue credits if the customer's period hasn't ended yet and the invoice isn't finalized. It is much easier and better for users and us to avoid payment if we can!
If invoice is finalized and this is a first time request, issue a refund via a credit note (do not use the refund button, this is important for correct revenue attribution).
If the customer has overdue invoices and needs changes on that, we need to apply credit notes. Escalate such cases to RevOps.
In the 'Customer' field, use the drop-down menu to find your customer
In the 'Amount' field, set an amount of credits you wish to issue for this customer
In the 'Reason' field, select a reason which best describes why you're issuing the credits
Add an optional note in the 'Notes' field
Include an optional link in the 'Reference link' field, e.g. support ticket, Slack message link, etc.
Click 'Save and view'
After saving, you'll land on the customer view in Billing Admin — confirm the credit now appears on the customer's balance there. You don't need to check Stripe.
Issuing a refund
Refunds are now initiated through Billing Admin and finalized in Stripe via a credit note.
There are two ways to reach the Add Refund screen.
Option A:
Navigate to Billing Admin → Customers.
Find the right Customer (search by organization ID or customer ID).
Once in the Customer view, scroll down to _Related invoices_ section. Find the right one (you can identify it by its id, dates or amount).
Click on "Start refund"
Option B:
Navigate to Billing Admin → Invoices.
Find the right invoice (search by invoice ID, organization ID, etc).
Click and open the invoice view.
Once in the view, click on the top right button "Start refund"
Once you do that (through any of the two options), you'll land on the "Add refund" screen. From there, you can continue with the refund:
Allocate refund amounts per product. Refunds must be issued per product. Enter the refund amount for each affected product. You may need to do more math here: for an event spike refund may span Product Analytics, Person Profiles, and Group Analytics. Billing Admin does not automatically split refunds across products, you must do the math and allocate amounts manually. As you enter per product amounts, the total refund amount updates automatically.
Select refund reasons: Choose a Stripe refund reason (required) and select an internal reason (used for internal reporting and analysis)
Add any relevant notes or context (e.g. support ticket, Slack link, short explanation)
Once you review everything and all looks good save the refund in Billing Admin. This will issue a Stripe credit note, which is processed as a refund to the customer’s default payment method. Stripe automatically sends a notification email to the customer.
Fixed fee product refunds
For fixed-fee subscriptions (e.g. Boost plan), Stripe’s default proration behavior can cause double crediting.
Example: A customer subscribes to a fixed fee add on by accident and requests a refund. After we issue a credit note, they cancel their subscription. When this happens, Stripe automatically creates a prorated “unused time” line item on the next upcoming invoice. This results in the customer being credited twice:
once via the manual credit note
again via the prorated unused time credit
To prevent overcrediting, we need to manually delete the pending invoice item that Stripe creates after the subscription cancellation.
Steps:
Find customer profile in Stripe (you can search by organization id)
Locate the proration adjustment under Pending Invoice Items.
Manually delete the line item.
Add a private note on the support ticket documenting that the proration line was removed to avoid double crediting.
Spotting suspicious stuff - watch out for:
Multiple accounts that seem connected - easiest way to spot this is to look up user profile in Vitally and check connected accounts. If one email is connected to multiple accounts it is good to check previous requests and refunds on all related accounts as well.
High refunds notice in Stripe (This will appear as a yellow box notification next to the customer's name on the customer page in Stripe)
Usage that doesn't make sense for customer size, or business details don't add up
When to escalate to RevOps
Something seems off
They've asked for multiple refunds lately
The case doesn't match the simple cases above
It's a big customer (spending $1,667+ monthly)
Need to create or modify an invoice for the correction. Support team should not create or modify invoices. Invoicing responsibilities will be handled by RevOps to maintain accuracy.
Message Mine Kansu in Slack with what you checked, what you think we should do, and any other relevant context, and attach a private note to the ticket linking to the conversation. RevOps will review usage trends and customer lifecycle (e.g. new client, high-value account) to figure out next steps.
Our approach
We'd rather fix unexpected usage issues than have customers pay one massive invoice and then reduce spending or leave us. The goal is to maintain a fair, transparent relationship that works for everyone in the long term.
Trial periods and usage spikes
We're generous with trial periods for actively engaged new ICP customers
Tag accounts as "trial" in the billing system. If they're already paying when actively testing the product, inform Mine/RevOps for proper tagging and revenue recognition
If you spot accidental usage spikes, proactively reach out and work with customers to reduce their spend to fit their budget and needs
When you're unsure about handling a specific case, ping Mine/RevOps directly for review
If you're actively thinking about churn prevention in response to a customer churn threat or major red flag, it's already way too late.
Churn prevention is best done from early, and often, risk mitigation practices.
We should default to flagging "at risk" accounts by adding the "Churn Risk" tag in PostHog Customer Analytics well before the customer has told you they are exploring alternatives. If you have the slightest inkling that something may look off or something has you feeling a bit uncomfortable, flag it. This could be anything from not taking action on a recommendation you gave them for too long, down-trending volume with no apparent seasonality cause, only one or two core users of the platform, or no Slack activity for an extended period. To name a few.
There are a few risk-mitigation strategies you'll want to incorporate that serve as early detection and proactive mitigation, as well as a process for what to do when an account is actively at risk.
---
Risk mitigation (proactive)
Risk mitigation is about building habits that surface problems before they become emergencies. If you're doing this well, you'll rarely need the reactive playbook below.
Quarterly account planning
Every managed account should have an Account Plan note created in PostHog Customer Analytics, on the account's profile, once per quarter. You should also review this regularly with your manager and update it as needed. This forces you to step back and evaluate the account holistically rather than just reacting to whatever's in front of you.
The plan can be broken into two parts: the quarterly plan and ongoing updates.
Quarterly plan
Title format:Q[X] Account Plan - [Company Name]
Add the plan as an account note in PostHog Customer Analytics on the account's profile. For each account, work through these seven questions:
What type of opportunities (opps) are there this quarter? Name each one – conversion (moving a pay-as-you-go plan onto a discounted credit plan), renewal (securing an existing contract for another term), or cross-sell (getting them onto a product they aren't using yet) – so you're clear on what you're actually driving toward.
What are the customer's business objectives? Capture what they're trying to achieve with PostHog and how it connects to their broader goals so it's clear what they are – and if you don't know, say so, so the gap is visible.
What's the desired outcome for the account by the end of the quarter? State the concrete result you want (renewal signed, in with a new team, Error Tracking adopted) so success is measurable rather than vague.
Does the customer know about this plan? Note whether you've aligned with them, because a plan they haven't bought into is just a guess.
Is it blocked on anything right now, and are there any other risks? Call out current blockers and any other risks so you can get ahead of them before they derail the outcome.
Link to the SFDC opp. Drop in the Salesforce opportunity link so anyone reviewing can jump straight to the deal.
Who are the key players? List the stakeholders – champions, budget holders, technical evaluators, and end-users – and where you stand with each.
Ongoing updates
What did you do with them last week.
Any risks to flag or opportunities you are working
Who are you talking to
What are you working on with them this week
This can largely mirror what goes in our sprint planning, and shouldn't be duplicate work.
Early warning signals
These aren't emergencies yet, but they should make you pay closer attention. Many of these are also tracked automatically as risk indicators in Vitally.
| Signal | Why it matters | |--------|----------------| | Recommendation not actioned for 2+ weeks | They're not engaging with your guidance | | Down-trending event volume (no seasonality) | Usage decline is a leading indicator of churn | | Only 1-2 active users | Single point of failure, low organizational buy-in | | No Slack activity for 14+ days | Relationship is going cold | | Billing page visits without context | They're evaluating costs, possibly shopping around | | Champion changed roles or left | Your internal advocate is gone | | Support tickets spiking | Something is broken or frustrating | | Single product usage | Low switching cost, easy to replace | | Data exported to external warehouse only | PostHog becomes a pipe, not a destination |
When you notice any of these, don't wait. Reach out, dig in, and address it before it compounds.
Drive adoption of behavioral products
Not all PostHog products carry the same switching cost. Customers who primarily use PostHog as a data pipe to an external warehouse are structurally riskier. If their analysts query Snowflake or BigQuery, PostHog becomes invisible and replaceable.
Behavioral products create stickiness because they're used directly in PostHog's UI and embed into day-to-day workflows:
| Product | Why it's sticky | |---------|-----------------| | Surveys | Active feedback collection tied to user segments. Hard to replicate externally. | | Cohorts | Saved user segments used across insights, feature flags, and experiments. Accumulated investment. | | Workflows | Automated actions triggered by product events. Operational dependency. | | Feature flags & experiments | Engineering teams build release processes around them. Deep integration. | | Session replay | Qualitative context that doesn't exist in a data warehouse. Unique value. |
When you see a customer heavily reliant on data pipelines and external analytics, proactively introduce behavioral products. Frame it as expanding what they can do, not replacing their warehouse workflow. The goal is to make PostHog the place where decisions get made, not just where data passes through.
Practical moves:
Show them how cohorts can power targeted surveys or experiments
Demo how session replay answers "why" questions that SQL can't
Introduce workflows for automated follow-ups based on product events
Help them build dashboards they actually use inside PostHog
If they're doing all their analysis in Looker or Mode, ask why. Sometimes it's habit, sometimes it's a gap we can fill. See communication templates for new feature adoption for outreach examples.
Implementation health
A lot of customers self-serve without ever talking to a PostHog human. This means they can implement PostHog in ways that cause problems down the road: inflated bills, inaccurate data, or features that don't work as expected. Left unchecked, these issues lead to avoidable churn.
Proactively check for common implementation issues, especially for newer accounts or accounts that haven't had a technical review. See checking the health of a customer's deployment for the full checklist.
When a customer wants to cut costs
If a customer expresses interest in reducing their PostHog spend, view it as an opportunity to act in their interest, help them optimize, and stabilize the relationship. The fact that they're telling you is a signal of trust. Deepen that trust by helping them save money (which is a totally reasonable goal to support).
Tag the account cost optimizing in PostHog Customer Analytics while you work on it – see cost optimization for what the tag is for and how we share these with the team.
First, help them do what they asked, fast. At this point, the customer already decided that they need to cut costs, so don't lead with discovery questions that may suggest an effort to talk them out of that decision. Take action on their request first. Gather context along the way or after.
Give them actionable ways to reduce spend. This is where your product expertise comes into play - what are the concrete levers they can pull to reduce spend? Customer health check is a good starting point to identify opportunities to reduce billing waste.
Be transparent about trade-offs, but frame them as information, not as warnings. The goal is to help them make an informed decision, not to reopen the question. For example, if they don't want to pay for Product Analytics, let them know we'll stop ingesting events past the free tier. Frame this as "here's what to expect" rather than "are you sure?" Proactively flag non-obvious dependencies between products too; if you’re not sure, do some digging - use #ask-max, PostHog AI, ask the rest of the sales team, or ask the relevant product team in Slack (and add some commentary so they can better assist you).
Consider proposing a target spend. Once you've acted on their initial request, consider aligning on a target monthly spend. You can then work backwards from that goal to improve their implementation and shape how you support them going forward.
Pause any cross-selling or expansion work until they're at their target monthly spend. You make the call on when the relationship is stable enough to recommend increased adoption of our products, but it's a safe bet to pause on this while they're in the process of lowering their spend.
Billing waste:
Group Analytics enabled but not implemented. We have a Vitally risk indicator for this. If they're B2B and could benefit, help them implement it. If not, tell them to remove the add-on.
Autocapture noise. If >50% of events are autocapture and they haven't defined any autocapture actions, they're likely paying for events they don't use. Help them tune or disable it.
Session replay capturing everything. Default settings capture all sessions. At minimum, recommend setting minimum duration to 2+ seconds to filter out low-value recordings.
Tracking issues that erode trust:
Calling identify() on every page. Inflates event volume dramatically. They only need to call it once per session.
Calling group() on every page. Same problem. Once per group per session is enough, or when the group changes.
Calling posthog.reset() before identify. Creates unlinked anonymous users. Common culprit when web-to-app tracking seems broken. See guidance in the JavaScript Web SDK usage guide.
No reverse proxy. Best practice is to use PostHog's managed reverse proxy or configure their own. Events from their own domain improve reliability and ad-blocker resistance.
Feature flag resilience:
No fallback code. If flags fail to load, the app should still work. Check that they're falling back to working code when flags return unexpected values.
No local evaluation (server-side).Server-side local evaluation ensures flags work regardless of network status. Important for reliability.
When you find implementation issues, don't just tell them what's wrong. Help them fix it. A customer who had a billing problem you solved is more loyal than one who never had a problem at all.
De-risking common churn scenarios
Most churn follows predictable patterns. See common churn reasons for the full list. Here's how to de-risk the scenarios we have some control over:
| Churn scenario | De-risking strategy | |----------------|---------------------| | Champion leaves | Multi-thread relationships across teams. The more users actively in PostHog, the less one departure matters. | | Champion isn't the decision maker | Identify and build relationships with actual decision makers. Your champion can help with introductions. | | Customer builds internally or switches to competitor | Drive multi-product adoption. Harder to replace five products than one. | | Poor customer experience | Stay on top of open issues proactively. Circle back before they have to follow up. Rebuild trust through responsiveness. | | Customer can't extract value | Offer workshops, training, or hands-on help building specific insights. Don't wait for them to ask. | | Missing critical feature | Loop in the relevant PM and engineering team. Be transparent about what we can and can't do. Make sure the request is also tracked in Vitally | | PostHog isn't trusted as source of truth | Dig into data discrepancies. Often an implementation issue. If they're exporting everything to another tool, they're one step from leaving. | | Privacy/compliance concerns | Help them understand data controls, masking, privacy controls, cookieless tracking, and data deletion options. Often they assume they can't use features when they actually can. |
For scenarios outside our control (acquisition, company shuts down, not ICP fit), document what happened and share learnings with the team. There's usually something we can learn even when we couldn't have changed the outcome.
---
Churn prevention (reactive)
When an account is actively at risk (they've told you they're evaluating alternatives, usage has cratered, or you've lost a champion) you need to move fast and follow a clear process.
When to flag an account as at risk
Add the Churn Risk tag to the account in PostHog Customer Analytics if any of the following are true:
Customer explicitly mentions evaluating alternatives or considering churning
Usage has dropped 30%+ with no seasonal explanation
Key champion has left and no replacement relationship exists
Payment has failed and they're unresponsive
They've asked for a full data export
Health score has been "Poor" for 4+ consecutive weeks
Contract is up for renewal in <90 days with negative engagement signals
They're not using PostHog as source of truth (all analysis happens externally)
When in doubt, flag it. It's easier to remove a flag than to explain why we didn't see a churn coming.
Internal process
1. Add the Churn Risk tag in PostHog Customer Analytics
When you flag an account as at risk, add the Churn Risk tag to the account in PostHog Customer Analytics, and add a note on the account with:
Account name and ARR
What triggered the risk flag
What you know about the situation
What help you need (if any)
What you are doing to mitigate the churn
Adding the tag triggers a PostHog workflow that automatically posts to the #customer-churn Slack channel. This keeps the team informed and surfaces accounts that might need additional support or visibility.
2. Weekly at-risk account review
We hold a weekly team meeting to review all accounts tagged Churn Risk in PostHog Customer Analytics. Come prepared to:
Give a 60-second status update on each at-risk account you own
Share what you've tried and what's working or not
Ask for help or ideas from the team
The objective is accountability and support. If an account has been at-risk for 4+ weeks with no improvement, we need to either escalate for additional support or accept the loss and document learnings.
3. Escalation
Escalation means getting support at a higher level, not handing off the account. You remain the owner and primary contact. Use your best judgment on when to pull in additional resources:
Engineering involvement: If there's a technical issue, bug, or feature gap that's driving the churn risk, loop in the relevant engineering team directly. Tag them in Slack, share context, and ask for their help.
Product involvement: If the customer needs a feature we don't have or is struggling with product limitations, bring in the relevant PM. They may want to join a call to understand the use case.
Leadership involvement: For strategic accounts or situations that need executive attention (pricing negotiations, product commitments, relationship rescue at the exec level), loop in your team lead. For accounts >$50k ARR at serious risk, involve Ben or Simon to get their perspective and support.
The goal of escalation is to get the right people involved to help you save the account, not to pass the problem to someone else. You're still driving the relationship and the recovery plan.
Recovery playbook
Once flagged, your job is to diagnose and act:
Diagnose the root cause. Is this price, product, relationship, implementation, or business change? You can't fix what you don't understand. Use the churn scenarios above as a checklist.
Get on a call. Don't try to save accounts over email. Get face-to-face (or video) time to have a real conversation.
Listen more than pitch. Understand their perspective fully before proposing solutions.
Be honest about gaps. If we can't do something they need, say so. Credibility matters more than closing a save. This aligns with our sales principles: we don't care about losing deals if we'd have to compromise on our principles.
Create a recovery plan. Document specific actions with dates and owners. Share it with the customer so they know you're taking this seriously.
Follow up relentlessly. A save isn't done until the risk is resolved and usage is stable. Check in weekly until you're confident.
When churn happens
Not every at-risk account can be saved. When a customer churns, write a retro and share it in #customer-churn as soon as possible while the details are fresh. See learn from churn for the template and guidance.
---
Summary
| Activity | Cadence | |----------|---------| | Account Plan note in PostHog Customer Analytics | Quarterly | | Implementation health check | At onboarding + annually | | Early warning signal monitoring | Ongoing | | Behavioral product adoption push | Ongoing (especially for warehouse-heavy accounts) | | #customer-churn posts | As needed when flagging risk | | At-risk account review meeting | Weekly | | Recovery calls with at-risk accounts | Within 48 hours of flagging | | Churn retros in #customer-churn | Within 1 week of churn |
The best churn prevention is never needing to prevent churn. Build the habits, check implementation health, drive behavioral product adoption, and catch problems early.
A trial creates space for you and the customer to validate technical fit, agree on success criteria, and close the deal. This guide covers when to offer trials and how to run them effectively.
When to offer Trials
Offer a trial when:
Qualified for sales-assist (>$20K ARR potential)
Clear decision makers and timeline identified
Customer wants technical validation
Customer is ready to invest time in an evaluation of PostHog
Skip the trial when:
Below sales-assist threshold (route to self-serve)
No clear timeline or decision process
They are price shopping with no technical criteria
They are already committed to buying
Trial length: 2 or 4 Weeks?
We default to 2 weeks ($20-$60K ARR) unless there's a compelling reason for 4 weeks.
Extend to 4 weeks when:
Deal value >$60K ARR
Customer has a complex technical environment requiring extended implementation
Multiple stakeholder validation required
They are evaluating PostHog alongside other products
Trial "must-haves" and "should-haves"
Every trial _must_ include:
SDK installed and events firing - Can't trial without data. This is a non-negotiable, and should occur as a "Day 0" item requiring completion before proceeding to any of the recommended timeline steps below.
Documented success criteria - Define what "winning" looks like for them. What do they need to see for the trial to be considered a success. Leaving them to their own devices and hoping they envision their success with PostHog in the way that we do is not likely to work.
Documented timeline - Define the "when" for each of the success criteria in #2.
Every trial _should_ include:
Kickoff call - Use this time to align on the "must-haves": success criteria, timeline. An understanding of "how" they will evaluate is just as critical as what you can be doing throughout the trial to help check off the success criteria. Using this time to collaboratively build the success criteria ensures alignment and mutual understanding.
Shared Slack channel - Set up before kickoff if possible, so that there's a more "live" way to communicate that comes with better and more accessible support. See Shared Slack Channels with Customers for additional guidance.
Onboarding success plan - Use the 30-day onboarding success plan template as a starting point, then iterate where appropriate. Adapt for trial length, and share with the customer as a Slack canvas in the shared Slack channel.
AI products in a trial
A trial gives unlimited usage on most products. Four AI products are different: Replay Vision, Desktop, PostHog AI, and Inbox. These products have a spend cap during a trial, because each use costs us model tokens.
Many prospects in a sales-led trial do not have a subscription. For these prospects, the cap is 2x the free tier. This is low for a real evaluation. For example, the PostHog AI cap is 1,000 credits ($10). When the prospect gets to the cap, the product stops.
If AI products are part of the evaluation, add the organization to the billing-trial-expanded-free-allocation feature flag. Do this when you create the trial, before the kickoff call. The flag changes the cap to 10x the free tier. For example, the PostHog AI cap changes to 5,000 credits.
Add the organization to the release conditions. The organization name must match exactly.
Click Save.
The new cap does not apply immediately. It can take up to 30 minutes. If the prospect is already at the cap, the product starts again after the new cap applies.
If the prospect will need more than 10x the free tier, talk to the Billing team before the prospect gets to the cap.
Suggested timeline
Note: Per above, the trial shouldn't progress past this point until the SDK is installed and event data is being sent to PostHog.
Days 1-3: Kickoff & Review
30-min kickoff with key stakeholders
Review settings and configuration aligned with trial goals (Identified events, Session Replay controls, Group analytics etc.)
Custom events (real KPIs) and properties instrumented (not just pageviews)
This is crucial. We want to be able to tie back event data in PostHog to actionable business insights stakeholders care about.
Build initial dashboards together with customers
Days 4-7: Initial validation
Additional insights created (trends, funnels, paths)
Complimentary products introduced (session replay, error tracking, AI Observability, data warehouse etc.)
Start to gather initial feedback from test group
Start to validate success criteria
Business process happens in parallel
As customers are technically validating PostHog, you should also start to work with them on initiating procurement, reviewing legal requirements and aligning on price.
Ask: "What does the procurement process look like?"
Validate: Build and agree on a quote together in QuoteHog based on expected volumes. Does pricing make sense and work within their budget?
Identify: Who approves? What legal/security requirements exist?
Timeline: Confirm we're still on track to close by trial end. "How long does procurement typically take?"
Days 7-14: Close
Feedback session with stakeholders
Confirm their success criteria has been met
Address any remaining concerns
Validate procurement is in motion
Mutually aim to get an order form signed by trial end
Support approach
Different customers may need and/or request different levels of support during their trial. We should match the customer's energy accordingly:
Hands-on (larger deals, less technical teams):
Weekly check-ins
Proactive dashboard building
Regular training sessions
Frequent Slack engagement
Self-serve (technical teams, smaller deals):
We're available when needed
Very quick response times
Async support via Slack
Most trials fall somewhere in-between. It's up to us to read the room and adapt.
Monitoring engagement
It's important to have visibility into a customer's usage and engagement in order to validate whether or not they will be successful with PostHog.
These signals are not guaranteed to always indicate success. Some teams are chattier than others, some teams like to keep comms over email, others enjoy regular Zoom meetings - see above for notes on Hands-on vs. Self-serve approaches.
Pro tip: You can always use session replay to also check their activity and learn how they are using PostHog! Leverage PostHog AI to help you analyze multiple user sessions. Look for things like:
How well users are onboarding
Points of friction, confusion, or frustration
Product usage & discovery - are they doing the things they said they wanted to?
High engagement signals:
Active Slack channel (questions, wins, feedback)
High insight creation volume
Extensive event instrumentation
Regular meetings scheduled
Low engagement signals:
Quiet Slack channel
Limited insight creation
No logins for 3-5+ days
If engagement drops, be proactive:
Build dashboards tied to their KPIs and share with stakeholders
Send Loom videos showing interesting insights from their data or record your own demos
Ask directly: "Is this still a priority?"
Your time is valuable. If timing isn't right, it's okay to pause the trial and reconnect with them at a later date.
Extensions
It's common that a customer needs more time to validate PostHog. People get sick, take vacations, priorities change. There are a number of reasons why a customer may need an extension and we're happy to be amenable to them while getting a good understanding of the path to trial end, win or lose.
When considering granting extra time (7-30 days), we should ask for something in return. Examples include:
Introduction to key stakeholders
Commitment to start procurement process in parallel
Verbal confirmation they're moving forward
Weekly check-in calls until trial end
Always understand: Why do they need more time? What specifically needs to be accomplished?
Wrapping up the trial
Whether it's a 14 or 30-day trial, you should already be getting clear signals that the customer will choose PostHog halfway through. Schedule a feedback session to confirm the technical win and understand what else needs to happen before we make things official.
In your feedback session, be sure to:
Confirm they've achieved what they need to in order to buy PostHog
Address any remaining concerns
Discuss next steps and validate timeline
Confirm that procurement is in motion
Don't wait for the trial to end to start closing conversations. If success criteria are met early, no need to wait. You can always start moving towards the required closing steps (order form, amount, where to send invoices, etc.) at the customer's pace.
Here are the common tools the Sales, CS, and Onboarding teams use daily.
Our canonical call stack
For customer and sales calls, we've standardized on three tools. Use these by default – keeping to one stack means every recording, transcript, and meeting link stays consistent and searchable for the whole team.
Zoom for meetings – every customer and sales call runs on Zoom.
Gong for meeting recordings – records and stores every call in a shared, searchable library the whole team can review.
Granola for transcripts – AI-generated notes and transcripts, created on your laptop while you're in the call.
BuildBetter is where we store historical demos and meetings, and some teams still use it day-to-day. For new calls, Gong is the default.
Connecting them together
The three tools layer on top of each other: Zoom hosts the call, Gong records it to our shared library, and Granola gives you your own transcript and notes. Set them up in this order:
Zoom – Run every customer and sales call on Zoom. You'll also need a Zoom Pro account for Gong recording to work – request one via /zluri if you don't have it. If you happen to use Calendly for scheduling, you can set Zoom as its default location so booked calls land on Zoom automatically, but that's optional.
Gong – Request access via /zluri, then connect it to your calls:
Download the Gong Meeting Manager extension, which triggers a user consent page when you join calls.
Once connected, Gong automatically joins and records your Zoom calls into the shared library.
Granola – Install the Granola app and connect it to your calendar. It runs on your laptop and transcribes whatever call you're in (including your Zoom calls), so you get notes and a transcript without adding another bot to the meeting.
AI investigation tools
The fastest way to dig into an account is an AI agent wired into our tools. Not mandated, but many of us lean on it daily, and setting it up early will speed things up.
PostHog Desktop – PostHog's agent workspace. Runs coding agents on top of product data with PostHog skills built in.
Claude Code – a terminal agent you point at customer data, tickets, and repos. Install the PostHog plugin with claude plugin install posthog@claude-plugins-official.
MCPs – connect the following MCPs to your AI agent:
Note: Add yourself to group emails sent to sales@posthog.com or cs@posthog.com by joining the corresponding Google Group (sales@ or cs@). It's important you don't mark these emails as spam as Google will unsubscribe you from these group emails.
Tools requiring approval
You can self-serve access requests to the following tools using Zluri through Slack (type /zluri in any channel to start the request)
Gong - our canonical meeting recorder. You'll need a Zoom Pro account too. See connecting them together for setup.
Unless otherwise indicated, you can self-serve access requests to the following tools using Zluri through Slack (type /zluri in any channel to start the request)
BuildBetter for storing historical demos and meetings – some teams still use it
Wappalyzer for identifying tech stack on customer sites (also as a Chrome/Firefox extension). Credentials in 1Password
Alfred / Raycast for automated workflows. - Just download and install.
An IDE, like VS Code, Zed, or Cursor. It will come in handy for coding and development tasks.
Your next favorite tool!
Useful Slack channels
#team-customer-success - the Customer Success team.
#team-new-business-sales - the New Business sales team.
#team-product-led-sales - the Product-led sales team.
#team-onboarding - the Onboarding team.
#group-cs-sales-support - cross-team discussion for everyone who owns customers.
#sales - for general sales topics.
#incidents - for notifications of incidents which may impact customers. Make sure you set this to alert you for every message so that you know when something is up.
#sales-alerts - automated notifications from Vitally.
#sales-leads - automated notifications for new sales leads.
#legal - for requests from our legal folks.
#closed-won - yay!
#closed-lost - boo!
#customer-churn - discussion of potential and actual customer churn.
#changelog - product launches.
#today-i-learned - where we share our learnings.
#ask-max - bot focused on internal processes and questions.
#demo-posthog-anything - show off something cool or see how others are demoing things.
Internal tools
Why should engineers have all the fun? We routinely build our own internal tooling.
DemoHog - sample data for demo calls.
HogFlix - demo app.
Hedgeground - LLM-focused demo app.
Wheel of Names - randomly pick a person.
Academy - training platform.
QuoteHog - create quotes for customers.
HogSpy - Chrome extension for extra debugging info about PostHog usage.
Learn - prompts for PostHog Code on how to use PostHog effectively.
Yet Another Hog Spy - Chrome extension to identify SDKs used on a website.
WatchTower - alerts for your accounts.
Blake Bot - Slack bot to retrieve customer data.
Vitally MCP Server - expose Vitally data over MCP (public version also available).
Claude Skills - miscellaneous skills for retrieving data.
Stakeholder Mapping - visualise accounts from Vitally data.
This page outlines how we manage customers, differentiating those who make contact via booking a meeting with us (hands-on) versus those who sign up and get going themselves (self-serve).
If you are looking for guidance on how to manage customers in HubSpot specifically, visit our CRM page.
Hands-on Process
Customer will either:
Fill in the contact form on the contact page, which captures what they are interested in as well as metrics such as MAUs, event count etc.
Email us directly at sales@
We'll do some ICP scoring and either route them to self-serve or email them introducing ourselves and answering any questions they've shared as well as offering up a call/demo to discuss their needs further.
On the initial call we'll spend some time understanding what they want and then optionally give a demo if that's what they are there for.
Ensure call notes go into HubSpot against the contact/company/deal so that they are shared amongst the wider team
If they are ready to get started with PostHog, we should either:
For lower volume customers we should send them a getting started templated email which providers pointers on how to get set up as well as where to get help if they get stuck.
For higher volume customers we can create a Slack Connect channel in our Company Slack, this allows us to provide more focused support to ensure that they are successful.
As a priority we should get them sending data in from production (even just a small part of their app) so that they can see the value of PostHog quickly (decreasing time to revenue) see how we do this in the Onboarding section below.
Self-serve Process
For customers that sign up themselves, and begin using the product, we provide a number of self-serve resources, including:
Additionally, all users can contact us for support/bugs/feedback using the support panel in the PostHog app (bottom-left More menu → Support). This is routed to the appropriate team in PostHog Support.
Ensuring customers see value quickly
Most potential customers will show up because they want to replace an existing analytics product, or start doing product analytics from scratch. In either case, we should show them the power of PostHog as quickly as possible. To that end, getting live production data through our pipeline and available for analysis should be our top priority.
Help them get set up with tracking their production site/app using one of our client or server libraries.
JavaScript / Autocapture is the easiest - also make sure to turn on Session Replay.
If people aren't sure what they want to track, AARRR is a great framework to use and will give people a good taster on the types on insight they can see. We have a number of supporting resources:
A blog post on getting started with the framework.
A sample AARRR tracking plan which we can give to customers to fill in. It shows how we do things at PostHog and may help inspire people who don't know how to get started.
Encourage them to create dashboards for them to show off PostHog in the wider organization.
Keep on top of any support requests / blockers they may have.
Free trials?
Generally speaking we don't need to do anything around free trials as our free tier has a generous 1m events, 1m feature flag calls, and 5k sessions. If a customer is going to go over this limit pretty quickly then we can agree to give them 2 weeks of free usage - this can be done in the billing service. See the billing page for more info (and the latest on this).
Figuring out the best solution for a customer
Assuming PostHog is the best solution for a customer, you should look at their level of scale and if they have any specific security needs to determine the most appropriate plan for them.
In general, PostHog Cloud is the best option for customers. It is much more scalable than self-hosted instances, doesn't require devops time to configure, monitor, and run, and is also the only way to use all of PostHog's paid features. In certain cases, the open source / free product may be the best choice, if customers are very technical, and also have a strong data control requirement.
What about Open Source?
Open Source will be appealing to customers who want to self-host, but are happy with 1 project only and community-based support.
By contrast, paid has premium features around collaboration - such as user permissions so people can't delete everything, multiple projects to keep data tidy, basically functionality to keep things running smoothly when you have lots of logins.
Okay, they're using PostHog. Now what?
Congratulations, this is the best part! Now we focus on making customers successful at unlocking insights into their product.
We typically use two top-level metrics when looking at revenue: MRR (monthly recurring revenue) and NRR (net revenue retention).
The easiest way to see these is on the go/revenue dashboard. These queries were built by Tim
FAQs
_Can I give a customer a discount?_
Again, no need - we already have usage-based pricing which is _heavily_ discounted at higher volumes, and we only bill month-to-month, so customers don't need to feel locked in to a longer term contract. If it's high volume (B2C) we can do this on an ad-hoc basis.
_How do I work with a customer who wants to sign an MSA?_
This occasionally happens when we are dealing with very large companies, who may prefer to sign an MSA due to their internal procurement processes or to have the security of a locked-in contract from a pricing perspective. We have a contract version of our standard terms and conditions that we can use for this - ask Ben.
We'd only really look to do this with people spending $20k+ per year - we don't do it below this value because of the legal effort required.
_How do I find out a customer's usage?_
The tool we use for this currently is Pocus, which combines revenue, PostHog, HubSpot data all in one place. You can search for the org/user/domain using cmd + k and the popover should give a deep dive into usage across products, revenue, engagement, etc.
_Can a customer transfer from self-hosted (e.g. Open Source) to Cloud?_
_What if the customer knows their user volumes but has no idea about number of events?_
A good approach is to point them to our Downsampler app and set it to say only capture 1% of users. If they then go to their billing page, they can see the events count. Multiplying this by 100 will indicate their actual likely volume, without creating a ton of risk that they spend too much money.
We also did a study on PostHog Cloud and most companies were within the range of 50-100 per user per month.
_What privacy features does PostHog offer?_
Self-hosting so no data needs to go to a 3rd party
You can block Auto Capture on certain elements
You can use PostHog without cookies
You can mask IPs
We make it trivial to delete a user's data if requested to do so
_What apps are available?_
We have the full list here. We also accept apps built by the community, which we audit first before adding to the list.
DemoHog is an internal tool for spinning up a PostHog project filled with realistic, made-up event data. Describe an app in plain English, and it generates events, dashboards, insights, cohorts, Surveys, Feature Flags, Experiments, and (optionally) a hosted demo site wired for Session Replay.
When to use it
Two reasons to reach for DemoHog:
Tailored demos. A dashboard showing the prospect's funnel, personas, and events lands harder than a generic ecommerce demo. Describe their product, generate the data, walk into the call with a project that already tells the story.
Take-home sandboxes for prospects. Sometimes a prospect wants to click around before they instrument anything. DemoHog hands them a populated project to explore Product Analytics, Session Replay, Feature Flags, and Experiments with zero setup.
Sandboxes are a fallback, not the goal. Read the next section before you hand one out.
Sandboxes carry real risk
First prize is always getting prospects to send their own data. Two things break when they don't:
Lower commitment. Installing the SDK is the moment a prospect actually invests in PostHog. Skip it and they're one click from walking. Instrumented prospects convert at much higher rates than sandbox-only ones.
It doesn't feel like the real product. The data is plausible but it isn't theirs. Numbers won't match anything they recognize, edge cases in their funnel are missing, and the "aha" moment from spotting something real in their traffic never happens.
Push for real instrumentation first. Offer to pair on the SDK install. Send them the relevant installation guide. Only fall back to a sandbox when they genuinely can't instrument yet (pre-launch products, procurement gates, locked engineering time).
If you do hand one over, frame it as a tour, not a trial.
The four-step wizard
Open DemoHog and click Start wizard (/wizard). The home page also lists past demos under Scheduled and Sandboxes so you can resume or extend a run.
1. Describe your app
Write a paragraph covering:
What the product does
1 or 2 personas
The main journey (sign up, do thing, convert)
Any specific events, Surveys, or Experiments you want to show off
Your prompt can be as simple as:
A prediction market site with a theme related to buying or selling predictions based on what hedgehogs will or won't do.
You can add significantly more detail if you want a more deterministic output:
A prediction market site with a theme related to buying or selling predictions based on what hedgehogs will or won't do. Below is an example of the events and event properties that should be instrumented for capture and imported.
**Basic**
- `signup`, `buy_trade`, and `sell_trade`. Add relevant properties based on below information.
**Discovery & Education**
- `market_viewed`: `category`, `market_id`, `source` (browse, search, deeplink, push notification, email), `time_to_close`, `total_volume`, `is_trending`
- `search_performed`: `query_text`, `results_count`, `result_clicked` (bool)
- `market_shared`: `share_method` (link copy, twitter, embed), `market_id`
- `education_tooltip_viewed` / `explainer_opened`: `user_tenure_days`
**Pre-Trade Deliberation**
- `order_book_viewed`: `depth_viewed`, `time_spent_ms`
- `position_calculator_used`
- `price_chart_interacted`: `timeframe_selected`, `zoomed`, `hovered_on_event_marker`
- `order_started_but_abandoned`: `amount_entered`, `price_entered`, `abandon_reason` (navigated away, changed mind, insufficient balance)
- `contract_details_expanded`
**Portfolio & Position Management**
- `portfolio_viewed`: `total_positions`, `unrealized_pnl`, `frequency_per_day`
- `position_closed_early`: `pnl_at_close`, `time_held`, `market_time_remaining`
- `limit_order_placed` vs. `market_order_placed`
- `deposit_initiated` / `deposit_completed` / `deposit_failed`: `method`, `amount`, `is_first_deposit`, `time_since_signup`
- `withdrawal_requested`: `amount`, `remaining_balance`, `trigger_event`
**Engagement & Return Triggers**
- `notification_received` / `notification_opened`: `notification_type` (price alert, market resolution, new market in category), `time_to_open`
- `watchlist_added` / `watchlist_removed`: `market_category`, `current_price`
- `market_resolved_viewed`: `user_had_position` (bool), `pnl_on_resolution`, `next_action_within_5min`
- `referral_link_generated` / `referral_converted`: `referrer_lifetime_volume`
**Trust & Friction Signals**
- `kyc_step_completed` / `kyc_step_abandoned`: `step_number`, `time_on_step`, `document_type`
- `support_ticket_opened`: `category`, `user_tenure`, `recent_trade_count`
- `terms_or_rules_page_viewed`: `from_context` (during trade, during dispute, idle browsing)
You'll also be asked to fill in:
Customer name (required). Labels the saved config (e.g. prospect name).
Date range. How far back (and forward) synthetic history should span. Defaults to roughly 3 months back through 1 month ahead.
Click Analyze my app. DemoHog uses an LLM to infer pages, events (with property specs), objects, personas, funnels, key events (signup, revenue, churn), audience (B2B vs B2C), a dashboard spec, trend/funnel/retention insights, and dynamic cohorts.
2. Review inferred data
Check the inferred cards (pages, events, funnels, key events, audience) and fix anything that's off. For full control, open Edit inferred JSON to edit dashboard, insight, and cohort definitions directly in the model.
Set:
Number of users. Synthetic users in the dataset (default 100).
Events per session. Custom events per session (default 5).
Keep custom event names in snake_case so they match PostHog conventions. Click through to save the config.
3. Connect PostHog and generate
Enter:
| Field | Where to find it | | --- | --- | | Host | Ingest host, e.g. https://us.i.posthog.com or EU (https://eu.i.posthog.com) | | Project ID | PostHog → Project settings | | Project token (phc_…) | PostHog → Project settings → Project token (needed for upload; add it here or on Results) | | Personal API key (phx_…) | PostHog → Personal API keys |
The personal key needs these scopes:
dashboard:write
insight:write
cohort:write
survey:write
feature_flag:write
experiment:write
Click Generate demo data. DemoHog will:
Create (or reuse) a survey, feature flag, and experiment in the project via the PostHog app API.
Produce JSONL for the date range, validate it, and auto-repair (up to 5 attempts) if validation fails.
Generation doesn't upload events yet. If the end date is still in the future, a daily job gets scheduled automatically (see Optional extras).
4. Results
On Results:
Download JSONL (optional) to inspect the file.
Upload to PostHog. Sends events to /batch using the project token. Needs the phc_… token if you didn't set it earlier.
Create dashboard, insights & cohorts. Available after upload. The UI waits ~30 seconds for ingest, then creates the inferred dashboard plus trend, funnel, and retention insights and dynamic cohorts.
Session Replay demo site (optional). Provisions a generated Next.js app on a Fly.io Sprite with posthog-js and session recording enabled, wired to your host and project token. Provisioning takes a few minutes. Click around the live URL for at least 10 seconds and move between pages so replays land in PostHog (and confirm Session Replay is enabled in the target project).
Done. You've got a populated project with analytics resources; replays show up once someone (or automation) uses the demo site.
What gets generated
Beyond pageviews and custom events, synthetic data can include:
Groups (B2B-style organizations)
Feature flag / experiment exposure ($feature_flag_called) aligned with the created flag and experiment
Survey responses tied to the created survey
Revenue and subscription-style events
LLM-style usage events
Error events at a low baseline rate
State carries over between runs so scheduled generation stays coherent (same synthetic users and groups over time).
Optional extras
Daily scheduled generation
If the config end date is after today, DemoHog schedules a daily job when you generate (default 03:00 in the job timezone). Production runs this on Vercel cron.
First scheduled run: backfills from the range start through today (or the range end, whichever is sooner).
Later runs: 1 new day of events per run until the range end.
Each day gets validated, repaired if needed, queued, and uploaded in the same cron run.
The home page Scheduled tab shows active jobs and lets you extend the end date to keep a sandbox alive for prospects who come back over a week or two.
Hosted demo site (Sprites)
Provisioning kicks off from the wizard Results step. It needs a Sprites API token on the DemoHog server (SPRITE_TOKEN or SPRITES_TOKEN in the deployment env, not something you paste per demo). If provisioning fails with a missing-token error, ping whoever maintains DemoHog.
The generated site mirrors your inferred pages and events and is built to produce real PostHog Session Replay in the same project you connected.
Automated browser sessions (Browserbase)
If the DemoHog deployment has BROWSERBASE_API_KEY set, the server fires 5 headless Stagehand sessions against the demo URL after Sprite provisioning, and again after scheduled runs that generated new data (when a sandbox URL exists). Those sessions drive the instrumented demo site so PostHog gets events and replays without you clicking manually. Replays also show up in the Browserbase dashboard for debugging.
Optional infrastructure on the shared DemoHog instance, not a per-user setting in the wizard.
Picking the right project
For tailored demos, generate into a fresh project so the data doesn't pollute anything else. Don't reuse a project from a previous prospect.
For prospect sandboxes, create the project in an org the prospect can be invited to, and set realistic timezone and currency so the data feels right.
Getting help
DemoHog is maintained as an internal tool. Code lives in the demohog repo.
PostHog is now available on AWS Marketplace for SaaS products. The way we've chosen to list our product is that it is not available as a public offering and instead is "listed" but only available via AWS "Private Offers", which means we create custom order forms for each customer through AWS that they accept via their portal.
AWS Marketplace lets vendors use their own terms and MSA. For now, PostHog team members set the price as a lump sum credit purchase for annual pre-payment only. Down the road, if we change our listing to public on the marketplace, we could set up usage-based billing through AWS (but that's future state).
Default to Stripe
Stripe is our default billing method. Only use AWS Marketplace when the customer specifically asks for it.
Stripe charges a flat fee per bank transfer regardless of deal size, and the cash lands with us straight away. AWS Marketplace takes a percentage cut on new contracts and disburses on its own schedule, so we get paid less and later, with more admin along the way.
That said, we don't want to block customers from buying the way that's easiest for them. If procuring through their existing AWS spend is what unblocks the deal, use AWS Marketplace — it's available, we're just not promoting it. Don't offer it unprompted.
Why this matters
Our ICP lives in AWS - Product engineers already have AWS access and budget. Adding PostHog to their AWS bill just makes sense since we're part of their product infrastructure stack
Procurement bypass - Organizations have bigger, more flexible AWS bills. Way easier to add a line item there than set up a whole new vendor
Customer kickbacks - Buyers get ~3% of purchase price back as AWS credits (sweet deal for them)
TAM incentives - AWS TAMs get SPIF'd for marketplace sales (we should apply to ISV Accelerate to fully capitalize on this)
Current requirements
For now, we're keeping it simple:
Annual contracts only (upfront payment)
No minimum deal size beyond our usual sales-assist threshold – there's no extra overhead in selling this way, so if a customer wants to procure via AWS Marketplace, go ahead
Using Clazar for private offers
Since AWS Marketplace can be a pain to navigate, we're using Clazar to manage this. Clazar ties private offers directly to Salesforce (something AWS doesn't do natively). Future state: would be nice if QuoteHog could create these directly too!
Initial setup
Before you start:
Make sure you have access to Clazar
Have signed order form from customer with "AWS Marketplace" selected as the billing method
Have the customer's AWS account ID ready
Creating a private offer via Clazar
Option 1: Direct from Salesforce (recommended)
Open the opportunity in Salesforce
Navigate to the AWS Private Offers widget (should be on the opportunity page)
Click "Create Private Offer" - Clazar pre-fills most fields from the opportunity
Fill in the required fields:
Buyer AWS Account ID (critical - double check this and it should be their management/root account ID)
Offer Name - Something clear like "PostHog Annual - [Company Name] - MM/YYYY"
Contract Duration - 12 months (we're annual only right now)
Expiration Date - Expiry on the offer itself. Usually 30 days out is fine.
Configure pricing:
Set as upfront payment (non-FPS offer)
Enter the negotiated price
Currency: USD (can do EUR, GBP, JPY if needed)
PostHog credits are post-discount – the credit balance we apply equals the discounted amount the customer pays through AWS, not the pre-discount list value
Choose EULA type:
Use Standard Contract for AWS Marketplace unless legal says otherwise
If custom EULA needed, upload the PDF (max 5 docs)
Review and submit - Takes ~45 minutes to generate in AWS (yes, really takes that long sometimes)
Option 2: Via Clazar platform
If you need more control or Salesforce isn't cooperating:
Log into Clazar at app.clazar.io
Navigate to Private Offers in the main menu
Click "Create New Private Offer"
Fill in buyer details:
Company name
AWS Account ID (must be exact)
Configure offer details:
Friendly offer name
Expiration date (when offer becomes void)
Contract duration
Start date (first service day if net new, day of renewal otherwise)
Offer type: Choose "Contract" with upfront payment
Set dimensions and pricing:
Add your product dimensions
Set prices for each dimension
For annual deals, configure as single upfront payment
PostHog credits are post-discount – the credit balance we apply equals the discounted amount the customer pays through AWS, not the pre-discount list value
Legal terms:
Select EULA type (Standard Contract or Custom)
Upload any additional documents if needed
Review the status tab - Should be green when ready
Submit the offer
After creating the offer
Wait for generation (~45 minutes)
Clazar sends notifications when the offer is live
Share with customer:
Send them the private offer URL
Include the Offer ID for reference
Remind them to log into the AWS account specified
Track in Salesforce - Status syncs automatically via Clazar
Common issues & solutions
Customer can't see the offer:
They're not logged into the right AWS account
Offer expired (check expiration date)
Wrong AWS account ID used (most common issue)
Offer needs changes after creation:
Can't edit accepted offers
Create an Agreement-Based Offer (ABO) for modifications
Customer accepts ABO, which cancels the previous agreement
Payment not showing up:
AWS disbursements take time (check the disbursement schedule)
Verify the offer was actually accepted in AWS
Pro tips
Double-check AWS Account IDs - This is where most mistakes happen
Set realistic expiration dates - 30 days is standard, but adjust based on deal timeline
Keep offers simple - Complex payment schedules = more room for error
Document everything in Salesforce - Let Clazar sync do the heavy lifting
We offer shared Slack channels to customers and prospective customers in several circumstances:
Prospective, new customers can have a shared Slack channel for the duration of a trial period, and keep a shared Slack channel after the trial if they qualify with at least $20k in annual, committed spend OR a subscribe to a support package which includes a shared Slack.
Product-led customers can earn a shared Slack channel by growing beyond $20k in annualized spend.
Existing customers can earn a shared Slack channel by committing to $20k in annual spend OR growing beyond $20k in annualized spend.
We use shared Slack channels to provide timely support and to build relationships with those at our customers shipping things with PostHog.
Shared Slack channels allow many folks at PostHog to support our customers. And, a shared Slack channel must be configured correctly in order for this support to work.
Setting up a Shared Slack Channel via Slack Connect
We use Slack Connect to share Slack channels with our customers.
To get a shared Slack channel going, follow these steps:
Create a new Slack channel - the expected syntax for the name is posthog-[customername].
When determining the [customername], make sure to make it searchable (avoid acronyms, if possible).
Obviously, invite the relevant customer folks! Be sure that you're inviting them to the channel you've created and not our Slack workspace.
Invite certain leaders who want to help monitor the channel, including: Tim, Ben, Abigail, Simon, your team lead and anyone else internal who may be connected to the customer. PostHog folks will sometimes join the channel if they're interested in the customer or the use-case
Invite SupportHog to ensure those from PostHog and the customer can create support tickets from Slack threads - use a slash command in Slack to invite it: /invite @SupportHog. Once it's in the channel, a ticket can be raised by reacting to any message with the :ticket: emoji or by mentioning @SupportHog in a thread.
Set your preferences to "Get notifications for all messages" in the channel -- this will ensure you don't miss a message and allow for speedy support.
Ensure that the Slack channel name is recorded on the relevant Salesforce Account record in the Slack Channel field.
Grab the Admin Panel link (from Vitally under PostHog Default Dashboard) and in the channel add this as a new link. Name it Org Link and add a new folder called Support. This is helpful to our Support Team for quickly accessing the customer's account when questions are posted in Slack.
Add your role and title to the channel description (e.g. Technical CSM: FirstName LastName). This will help team members identify who's the main point of contact for this customer.
If you have any questions as you go, ping your colleagues for support in your team channel.
Using MS Teams
Some customers may wish to use MS Teams rather than Slack. SupportHog works in Teams without a separate app - as long as SupportHog is in our Teams instance, customers can raise tickets by mentioning @SupportHog in a channel thread. For shared channels, you must also add the channel to the SupportHog polling list (see below). Note that the :ticket: emoji reaction is Slack-only; in Teams customers should @mention SupportHog to raise a ticket.
First you will need an MS Teams licence - ask Simon, or Dana for one. Then follow these steps:
In Teams go to "See all your teams" and then "Create team". When naming the team the expected syntax is [CustomerName-PostHog]. Make sure to set the team type to Public and name the first channel "Shared" then finish creating the team.
If the channel is a shared channel (for example, a channel shared with the customer's own Teams tenant), Teams does not send SupportHog events for it. Add the channel to the polling list in SupportHog Teams settings so that SupportHog polls it for new messages. If you do not do this, @SupportHog mentions in the channel do not create tickets.
Test that mentioning @SupportHog in the channel raises a ticket correctly before adding the customer.
Once you've confirmed it's working, invite the relevant customer folks by adding them as members to the team!
If a customer says that @SupportHog did not create a ticket in Teams, first make sure that their channel is in the polling list.
Onboard Your Customer to Slack Support
Welcome them to the channel when they join!
Set context for the channel's purpose and timing (if applicable). Let them know that they may hear from anyone at PostHog who is monitoring the channel, and also don't miss the opportunity to train them how to open a ticket with SupportHog.
A message like this one does wonders to help them understand how to open a ticket if you're not online to help yourself:
We also have an app here that will open a support ticket if I'm sleeping. You only have to add the :ticket: emoji to the thread and it will open a ticket automatically, and capture the back and forth in the specific Slack thread that received that emoji. You can also mention @SupportHog in a thread to open a ticket as well. It's a good habit to get into in order to make sure our distributed team can help.
A question we often get asked is: "What makes an excellent TAM?" This touches almost every stage of the role, from candidates (what would I have to do to succeed at this potential role?) to new hires (where should I be spending my time?) to folks in their first year (how do I know I'm doing well?) to old-timers (how do I keep up with the rest of the team?)
An excellent TAM:
| General Principle | Specific Examples | |---|---| | Distinguish yourself from other vendors with personalized outreach | Record personalized videos, submit PRs for a customer's software, send personalized food or merch, sign up for their product, invite them to events, or make donations in their name | | Dig into a customer, find what will be valuable to them, and surface it in a way that deepens the relationship | Get the content right — saving money, expert recommendations, ideas for success beyond PostHog — and deliver it in a way that earns attention | | Take ownership of a customer problem and see it through to resolution | Even when a full fix isn't possible, owning the issue and driving it to conclusion builds trust — people notice when you see things through | | Build relationships for the long term so that today's work pays off a year from now | Don't write off a quiet or unresponsive customer — the relationship being built now is for next year's expansion, not this quarter's | | Balance cross-sell with non-sales value so customers feel helped, not sold to | Avoid making every interaction a revenue conversation — give them value that doesn't require opening the wallet | | Show sincere interest in the customer's business and back it up with real knowledge | Congratulate them on product launches, give feedback on their product, leave them reviews — and actually know their product well enough to do so | | Have the technical depth to get hands dirty and help with technical questions | You shouldn't be implementing for customers as a rule, but being capable of it demonstrates you understand enough to be genuinely useful | | Don't accept "we're good" as a final answer — keep engaging to find where you can help | "Talk to us in 6 months" usually means "don't upsell me" — respond with concrete suggestions on cost reduction or real pain points instead | | Regularly share learnings — both wins and failures — publicly with the team | When you learn something (especially from a mistake), sharing it helps others avoid the same issues and raises the whole team's effectiveness | | Develop a sense for when an account is at risk and act proactively | Be close enough to your accounts that you can detect when something feels off, and address it before it becomes a problem | | Balance directness and transparency with knowing when to give a customer space | Understanding what the right balance looks like for each individual customer is the art of the role | | Spot gaps in the sales process and proactively fix them rather than complain | An excellent TAM doesn't sit on process frustrations — they take ownership and make improvements | | Identify the customer's key business goals and align PostHog directly to those outcomes | If a customer wants to increase conversions or grow premium plans, show specifically how PostHog helps reach that goal — make it essential, not just a nice-to-have | | Enable and upskill your customer champion so they look good within their org | Do the hard work for your champion, then let them take all the credit | | Be a relentless advocate for customer interests internally | TAMs are closest to customers — engineers need to hear from you about how customers are actually feeling | | Continuously grow your PostHog expertise to keep pace with the product | PostHog is constantly changing — never shy away from selling a new product because of unfamiliarity; learn it |
As team lead in a customer-facing role you'll be responsible for making sure that your team is exceeding expectations when it comes to their specific role at PostHog. This generally means that:
They have a solid plan for any managed customers in their book of business or deals in their pipeline
They are proactively building relationships with their customers, even those who are hard to engage with
They are flagging any potential churn as soon as they become aware of it
You are proactively helping them when they are struggling with what to do next on a customer or deal
You are providing continuous feedback to them, especially when their performance is below expectations
Team-specific responsibilities
Product-led Sales
Technical Account Managers (TAMs) own a book of business of nominally around 15 customers with an ARR of $1.5m, and also look to bring new customers into that book via product-led leads.
Once a TAM has hit 15 managed customers or ARR of $1.5m, we should stop generating new product-led leads for them to allow them to focus on and grow their existing book. Flag this to Simon (Mine as backup) when this needs to happen.
If a TAM's book of business is too big then your first port of call should be to balance customers across your team, failing that ask for help from your peers in other teams (Simon as backup).
TAMs will want to bring new leads into their book of business so that they count towards their quota. It's your job to make sure that they have a solid relationship with the customer and a plan in place for growing them too. Once you're happy, then let Simon know who will review and add them to the quota tracker.
With big customers over $100k in ARR you should be prepared to lean in and help the TAM with that customer more directly, owning different levels of the relationship.
Take the lead in driving churn risk and cross-sell team calls, ensuring that we stick to planning and next steps rather than storytelling.
Ensure that TAMs are on top of any credit renewals well before they expire.
Check the TAM quota tracker to see if there are any discrepancies and encourage your team to do so regularly as well.
Coming up to the end of the quarter, work with your team to identify any customers that are ready to be owned by a Customer Success Manager. Review these with Simon ahead of quarter end so that we can make for a clean transition of customers.
Set the New Owner trait in vitally to EU CSM or US CSM based on geography.
Customer Success
Customer Success Managers (CSMs) own a book of business of around 30 customers with an ARR of $1.5m and focus mainly on keeping them as customers (retention).
Once a CSM's book is full, work to balance customers across the team ideally with a reasonable timezone overlap with the customer.
Take the lead in driving churn risk team calls, ensuring that we stick to planning and next steps rather than storytelling.
Ensure that CSMs are on top of any credit renewals well before they expire.
Populating a new CSM's book
When looking at accounts to include in a new CSM's book, the following priority order applies:
Any customer paying $100k+ a year with no dedicated human (TAM or otherwise)
Accounts tagged as csm handover needed or csm overlay needed in PostHog Customer Analytics
Other accounts not covered by a PostHog human in descending ARR order
For accounts in bucket 2 we have region tags which are automatically applied to the account when the handover or overlay tags are added to the customer (runs once a day). The regions are covered as follows:
EU Team: Europe, Africa, Asia
NA Team: North America, South America, Oceania
If an account is flagged as multi region or there is no explicit tag review these and make a decision.
Onboarding
The Onboarding team operates at scale, supporting hundreds of customers whose MRR falls below the TAM/CSM threshold. As a result, the number of customers in the program, as well as the ARR represented, can fluctuate from month to month. The team is currently focused on customers whose first bill is forecasted at $500+ MRR. Its north star metric is maintaining 90% logo retention through customers’ first three months.
Make sure the Onboarding Specialists prioritize work effectively, engage with customers ahead of renewal, and prevent accounts from falling through the cracks.
Ensure the Onboarding Specialists adapt to customer needs, continue providing value, and maintain a high-quality bar.
Lead the team’s continuous improvement efforts across internal processes and the overall onboarding program.
Ensure high-spend accounts are properly qualified for Sales handoff and that the handoff process runs smoothly.
Monitor team coverage and customer volume to identify and flag hiring needs proactively.
Other things we collectively need to stay on top of
Tracking new products
When we know that a new product is being launched, we need to ensure that Vitally tracking is in place for that product before it is launched. This involves:
Updating the Postgres integration to ensure that we are tracking the following traits for the product:
product_name_ltv added to the completed CTE - the lifetime value of the product
product_name_forecasted_mrr added to the forecasted CTE - the MRR forecasted for the product
product_name_last_month added to the last_month CTE - the last month payment for the product
product_name_billing_limit added to the main query - the current billing limit for the product
also add the traits from the 3 CTEs above into the main query
Once the traits are in place, create a success metric to capture the product's data usage if applicable.
Sum of a property on events -> billing usage report -> product_count_in_period over the last 30 days
If there is a specific engagement to track how people use the product in PostHog add it to the Vitally engagement events Action
If you do this, also ensure there is a corresponding success metric for this (Total event count over 14 days)
Incident comms
We need to ensure that teams are able to proactively follow our incident comms process. We're not quite ready for a full on-call rotation yet, but Simon or Dana take the lead as Communications Manager On-Call (CMOC) when an incident is declared in EU working hours, and Landon or Tyler take the lead when it's during the US working day.
Customer: search for customer by Organization Name or ID
Status: set to Active
Target: set to whatever is needed (paid, teams, enterprise)
Type: set to Standard
Expiration date: set it to whatever is needed (2 weeks, 4 weeks for larger ($100k+) customers, etc)
Check Silence notifications if you don't want them to get trial notifications
Click Save
The next time that Customer visits PostHog, their AvailableFeatures will be updated to reflect the standard premium features (they might have to refresh their page to properly sync the new billing information).
Once this date passes their AvailableFeatures will be reset to the free plan unless they have subscribed within this time.
Additional steps for existing customers with paid subscriptions For customers with existing paid subscriptions we need to complete additional steps to make sure they are billed correctly.
Important: Ask Mine to update Stripe and billing admin so she can make sure revenue numbers are unaffected and customer isn't billed while on trial.
Follow the steps above to create a trial.
Remove Stripe Subscription ID in the Billing Admin (keep the Stripe Customer ID).
Set all products in the product map to a free status.
Cancel subscription in stripe: Ensure the subscription is canceled in Stripe so they are not billed during the trial.
Create new subscription before trial ends and update Billing Admin so customer experience isn't affected when transitioning back to a paid plan.
Consider framing a collaborative method for progressing in the trial period with timed objectives. If it's new and depending on the level of engagement, we can use a detailed success plan.
Spend caps during a trial
A trial lifts the free tier so a customer can try what they do not pay for. It leaves a spend limit they set exactly as it stands outside the trial, on every product.
Four products also get a cap where the customer set no limit: Replay Vision, Desktop, PostHog AI, and Inbox. These meter model tokens, so an unlimited trial on them is expensive for us. Every other product the customer set no limit on runs unlimited for the length of the trial, which is what a trial is for.
A customer on a paid plan pays for what they use, so their own limit is the figure that governs. A customer with no subscription pays nothing, so the cap is what the trial lends them.
An addon reads the limit on its parent. For example, Mobile Session Replay follows the Session Replay limit, and Batch Exports follows Realtime Destinations.
If a prospect needs more than this, raise their spend limit rather than removing it.
Our documentation is a critical piece of PostHog's context flywheel – a system that connects our codebase to our docs, which then feeds into our AI agents, the Wizard, and PostHog Desktop. When documentation is outdated, the agents that help customers integrate PostHog become outdated too.
This means your knowledge directly powers our AI tools. When you write down what you know, it doesn't just help humans – it helps robots help customers faster.
Why your contributions matter
The team has automated writing documentation from PR merges using InKeep, which indexes our codebase and docs to create first-pass drafts. But there's knowledge that only comes from working directly with customers:
Common integration patterns and gotchas
Real-world use cases and configurations
Cross-selling playbooks and discovery questions
Troubleshooting steps for edge cases
This knowledge lives in your head. When you write it down in the handbook, it can be transformed into skills – portable packages of context that the AI Wizard can use to help customers.
How to contribute
1. Write it in the handbook first
The handbook is the appropriate place to document playbooks, processes, and tribal knowledge. We have Markdown rendering for both the documentation and handbook, so content can flow between them.
Good things to document:
How you help customers solve specific problems
Discovery questions that uncover customer needs
Common configurations you walk customers through
Troubleshooting steps for issues you see repeatedly
2. Make it actionable
The context mill transforms handbook content into skills for the AI Wizard. To make your content skill-ready:
Be specific: Include actual steps, not just concepts
Show examples: Real code snippets and configurations help
Explain the "why": Context about when to use something helps the AI apply it correctly
Use clear structure: Headers, bullet points, and numbered steps work better than walls of text
When you write something down, ask: "Could an agent do this automatically?"
For example, if you write a playbook for gathering a customer dossier, that could become an automated web search agent task. If you document how to identify cross-sell opportunities, that becomes a skill the Wizard can use.
What gets turned into skills?
Skills are defined using a YAML specification that allows for different variants based on app detection and context. The team currently has over 60 skills the Wizard can use.
Your handbook contributions can become skills that:
Help customers integrate specific products
Run migration analyses from competitors (Amplitude, Sentry, etc.)
Diagnose common issues
Generate tracking plans based on customer needs
The Wizard and how it helps customers
The AI Wizard is a one-line npx command that runs an agent to integrate PostHog:
npx -y @posthog/wizard@latest
Here's what it does automatically:
Instruments multiple products like Product Analytics, Web Analytics, Session Replay, Error Tracking, and others)
Installs the right SDKs for their stack
Scans their codebase to understand their product
Creates 10-15 custom events based on product flows it identifies
Writes both client-side and server-side code for full-stack implementations
Creates an insight and dashboard in PostHog
This dramatically reduces manual integration work – what might take 3-5 hours happens in minutes. And it produces customized code tailored to each customer's setup.
The Wizard is agentic software that runs on our docs. When you write something down, the Wizard can execute it as a skill – it's like turning documentation into executable code.
So ask yourself: if an agent can read, analyze, and understand a user's codebase, what else could it discover or build to help the user get value from PostHog faster?
Those answers can become Wizard skills – and new ways of creating customers.
How this helps you help customers
Close the gap in customer conversations
The Wizard and skills architecture lets you close the gap between customer-facing hypotheticals and technical diagnostics without needing engineering present. If a customer asks "how would I track X?", you can point them to the Wizard or a specific skill.
Portable diagnostics
If customers are hesitant to run an agent on their codebase, they can receive the open-source skills package directly. This gives them 80-95% of the Wizard's functionality to run locally with their own tools.
Better onboarding
For new customers, the Wizard provides an excellent launchpad – 10-15 best-practice events that help them overcome the initial difficulty of deciding what to track. The best approach is to:
Run the Wizard first
Review what it did together with the customer
Come up with a plan and tweaks
The Wizard helps you get past the blank page. It's much easier to iterate from there!
Getting started
Identify something you repeat: What do you explain to customers often?
Write it down: Create a handbook page or add to an existing one
Make it specific: Include actual steps, code, or configurations
Let the team know: Share in Slack that you've added something that might make a good skill
The written-down knowledge also enables automation beyond the Wizard – like having agents gather customer dossiers based on your specifications or analyze competitor implementations before a call.
Your knowledge is valuable. Write it down, and it becomes executable.
Using PostHog's data pipelines (CDP), you can create a real-time feed of customer activity directly in Slack. This lets you monitor how users in your book of business are engaging with PostHog without constantly checking dashboards or running queries.
This is valuable for getting a pulse on account health and engagement patterns. You'll see who's actively using the product, which features they're exploring, and when they might be hitting friction points. It's not meant to replace proper data analysis, but it gives you the "vibes" and can help you time your outreach more effectively. For example, if you notice someone reading a lot of feature flag docs and then creating several flags, you know they're actively working on something and might appreciate a quick check-in.
A word of caution: don't be a creep about this. Use it to inform when and how you reach out, not to surveil every click. If you notice someone's activity suggests they need help, check in naturally without revealing you're monitoring their every move.
How to set up your event stream
1. Get your account organization IDs
Query PostHog's data warehouse to pull Salesforce data and create a CSV of all PostHog organization IDs for accounts you own. This gives you the list of orgs to monitor.
2. Create a CDP destination
Set up a new data pipelines destination using a webhook endpoint. This is where you'll send the filtered events.
3. Filter for your accounts
Configure the destination to filter for all events where the organization ID matches your CSV list of org IDs. This ensures you only see activity from your accounts.
4. Select relevant events
Add filters for events that represent meaningful user actions across product areas:
Product analytics & insights:
insight created
cohort created
action created
annotation created
dashboard created
Session replay:
recording analyzed
viewed recordings from experiment
Feature flags & experiments:
feature flag created
experiment created
experiment launched
experiment completed
experiment viewed
Surveys:
survey launched
AI & Max:
chat with ai
AI generation (LLM)
ai_hog_function_prompted
ai_hog_function_accepted
sql-editor-accepted-suggestion
LLMa events for seeing user prompts
Data pipelines:
batch export enabled
batch import created
export succeeded
Error tracking:
error_tracking_issue_created
Engagement & product intent:
person viewed
user showed product intent
Pageview (where url contains "docs")
toolbar mode triggered
Billing & account health:
billing product activated
billing limits updated
Hit billing limit
billing addon removed
billing subscription paid
billing subscription cancelled
billing invoice payment failed
annual plan credit purchase
billing trial activated
autocapture_opt_out team setting updated
session_recording_opt_in team setting updated
autocapture_exceptions_opt_in team setting updated
Team growth:
team member invited
5. Customize the payload
Modify the webhook payload to include:
User email
Event name
Current URL
Any other properties valuable for your real-time stream (e.g., organization name, event properties)
You can link right to replays (docs), just know they may not be available immediately
6. Route to Slack
Send the data to a Slack App endpoint, Zapier, or Relay.app to transform and redirect the events to your personal channel like your-name-alerts or your-name-user-event-stream.
What you'll get
A real-time feed of user activity that helps you:
Identify active power users and champions
Spot when accounts are exploring new features (cross-sell opportunity)
Notice declining engagement patterns early
Time your outreach when users are actively working on something
Get a general sense of account health without diving into dashboards
Remember: this is supplementary context, not a replacement for proper account analysis and data review.
This guide provides detailed instructions on how to achieve key business metrics using PostHog. Each business type has specific metrics that matter most, and this guide shows you exactly how to set up PostHog to track and optimize for those metrics.
B2B SaaS
Common business problems & personas
B2B SaaS companies often grapple with a core set of challenges that directly impact growth and sustainability:
Key business problems
High churn rates – Customers discontinuing subscriptions, leading to revenue loss and reduced customer lifetime value.
Low trial-to-paid conversion – Users not converting from free or trial plans to paid subscriptions.
Poor feature adoption – Users not utilizing key features that drive product value and stickiness.
Long sales cycles – Extended time from initial lead engagement to customer conversion.
Low customer satisfaction – Reflected in poor Net Promoter Scores (NPS) and negative customer feedback.
Inefficient onboarding – Users dropping off or struggling during initial setup and product adoption.
Expansion revenue challenges – Difficulty identifying opportunities or successfully upselling and cross-selling existing customers.
High support ticket volume – An elevated number of support requests, often indicating underlying product issues or user friction.
Primary personas & their pain points
Product managers
Pain points: Inability to identify which features drive retention, difficulty prioritizing roadmap items, lack of data on user behavior and product usage.
PostHog solutions: Comprehensive feature usage tracking, granular cohort analysis, session recordings for in-depth UX insights, robust A/B testing for feature optimization and validation.
Customer success managers
Pain points: Reactive churn management, challenges in proactively identifying at-risk customers, limited visibility into overall customer health.
PostHog solutions: Data-driven churn prediction models, customizable customer health scoring, proactive engagement tracking, automated alerts for at-risk accounts based on behavioral signals.
Sales teams
Pain points: Extended sales cycles, inefficient lead qualification processes, difficulty understanding specific prospect needs and product fit.
PostHog solutions: Product usage-based lead scoring, detailed prospect behavior tracking, optimization of conversion funnels to accelerate deal velocity.
Marketing teams
Pain points: High customer acquisition costs (CAC), inaccurate campaign attribution, difficulty measuring the true return on investment (ROI) of marketing efforts.
Pain points: Lack of holistic visibility into business health, challenges in making data-driven strategic decisions, cumbersome stakeholder reporting.
PostHog solutions: Intuitive executive dashboards, real-time key metric tracking, automated reporting, and actionable business intelligence insights.
Key metrics & PostHog
MRR/ARR (monthly/annual recurring revenue)
Importance: Measures the predictable revenue a SaaS business generates monthly or annually. It's crucial for forecasting, valuation, and understanding the company's financial health and growth trajectory.
PostHog approach: Track subscription events (subscription_created, subscription_upgraded, etc.) with properties like plan_tier, amount, and currency. PostHog helps analyze conversion funnels (e.g., trial_started to subscription_created), visualize revenue retention with cohort analysis on dashboards, and set up alerts for significant MRR changes. For non-technical users, autocapture on pricing pages and CTAs can power no-code funnels and session recordings to optimize conversion flows and pricing interactions.
CAC (customer acquisition cost)
Importance: The average cost to acquire a new customer. Understanding CAC is vital for marketing efficiency, profitability, and ensuring sustainable growth.
PostHog approach: Track marketing touchpoints (ad_clicked, demo_scheduled) and lead generation form submissions with properties like source, campaign, and UTM parameters. Integrate marketing spend data into PostHog for a unified view. Use funnel analysis to identify efficient acquisition channels and dashboards to visualize CAC trends by channel. Autocapture can track landing page visits and form submissions, enabling non-technical users to analyze lead quality by traffic source and optimize landing page UX with session recordings.
LTV (lifetime value)
Importance: The total revenue a business expects to generate from a single customer relationship over their lifetime. A high LTV indicates strong customer relationships and product value, enabling higher CACs and more aggressive growth strategies.
PostHog approach: Track all revenue-generating activities (subscription_payment, addon_purchase, upgrade) with customer segment and acquisition properties. Conduct cohort analysis for revenue retention and correlation analysis to identify high-value behaviors. PostHog's predictive analytics can forecast LTV. For non-technical users, autocapture can track feature usage and upgrade page visits to understand engagement patterns that correlate with high LTV, allowing for dashboards showing feature adoption by segment and alerts for potential churn signals impacting LTV.
Churn rate
Importance: The rate at which customers cancel their subscriptions or cease to use a service. High churn is detrimental to growth and directly impacts MRR/ARR and LTV, highlighting product-market fit or customer experience issues.
PostHog approach: Monitor engagement and usage patterns (feature_used, login, session_started) with properties like user_activity_level and feature_adoption. Use session recordings to understand behavior of churned users and correlation analysis to pinpoint churn indicators. Set up automated churn prediction models and alerts for at-risk users. Non-technical users can leverage autocapture to track declines in activity, analyze pages churned users stop visiting, and use session recordings to review churned user journeys.
NPS (net promoter score)
Importance: A widely used metric to gauge customer loyalty and satisfaction, indicating a customer's willingness to recommend a product or service. High NPS often correlates with retention and expansion revenue.
PostHog approach: Implement in-app NPS surveys using PostHog's survey feature. Track nps_survey_submitted events with user segment and usage properties. Analyze correlations between NPS and product usage patterns. Non-technical users can easily create surveys, configure triggers, and track completion rates. Dashboards can show NPS trends by segment, and session recordings can analyze user interactions with survey prompts to optimize feedback collection.
Feature adoption
Importance: Measures the extent to which users discover, use, and continue to use specific product features. High feature adoption indicates that users are deriving value, which is crucial for retention, upsell opportunities, and validating product development efforts.
PostHog approach: Track granular feature usage (feature_accessed, feature_completed) with feature name and user segment properties. Use funnel analysis for onboarding flows and session recordings to identify friction. Implement feature flags for controlled rollouts and A/B testing for optimization. Non-technical users can use autocapture for feature page visits and button clicks, analyze user journeys to feature discovery, and create dashboards for adoption rates. Alerts can be set for changes in feature usage.
B2C SaaS
Common business problems & personas
Key business problems
High user churn – Consumers canceling subscriptions after initial excitement
Low activation rates – Users not completing key onboarding steps
Poor user engagement – Users not returning to use the product regularly
High customer acquisition costs – Expensive to acquire individual consumers
Low viral coefficient – Users not referring friends and family
Poor mobile experience – Mobile users having difficulty with the product
Seasonal usage patterns – Inconsistent usage throughout the year
Difficulty scaling support – High volume of individual user support requests
Primary personas & their pain points
Product Managers
Pain points: High user churn, low activation rates, poor user engagement, difficulty understanding consumer behavior
Pain Points: Poor mobile experience, low mobile engagement, mobile-specific bugs, app store optimization
PostHog Solutions: Mobile experience analysis, mobile engagement tracking, mobile bug monitoring, app store performance analytics
Key metrics & PostHog
User Activation Rate
Importance: Measures the percentage of new users who complete key onboarding steps and experience the product's core value. High activation is crucial for retention and indicates a successful onboarding experience.
PostHog approach: Track activation events (account_created, onboarding_completed) with properties like activation step and acquisition source. Use funnel analysis to optimize time-to-value, and cohort analysis to track activation rates on dashboards. Session recordings can help identify activation friction points, and alerts can be set for activation rate drops. Non-technical users can use autocapture for onboarding page visits and tutorial interactions to create no-code funnels and analyze user behavior.
Daily/Monthly Active Users (DAU/MAU)
Importance: Measures user engagement and product stickiness by tracking the number of unique users who interact with the product on a daily or monthly basis. A high DAU/MAU ratio indicates strong, consistent user value.
PostHog approach: Track user activity events like session_started and feature_used with properties such as user segment and session duration. Create dashboards for real-time DAU/MAU tracking and trend analysis. Calculate stickiness (DAU/MAU ratio) and use cohort analysis to track engagement over time. Alerts can be configured for significant engagement drops. Autocapture can track page visits and feature interactions, enabling non-technical users to analyze engagement patterns and identify popular features.
Customer Lifetime Value (CLV)
Importance: Represents the total revenue a business can expect from a single customer account throughout their relationship. CLV is a key indicator of long-term profitability and customer loyalty.
PostHog approach: Track all revenue events (subscription_started, purchase_made) with properties like purchase amount and acquisition source. Use cohort analysis to analyze CLV by acquisition month and correlation analysis to identify high-value behaviors. PostHog's predictive analytics can be used for CLV forecasting. For non-technical users, autocapture on purchase pages and upgrade buttons helps track the user journey to purchase and identify which features drive upgrades, with session recordings providing insights into purchase behavior.
Viral Coefficient
Importance: Measures the number of new users an existing user generates, indicating the effectiveness of viral loops and word-of-mouth growth. A coefficient greater than one signifies exponential growth.
PostHog approach: Track viral events like referral_sent and invitation_accepted with properties such as referral type and conversion rate. Use funnel analysis to optimize referral flows and A/B test referral incentives and messaging. Dashboards can show viral coefficient trends. Non-technical users can use autocapture to track share button clicks and referral page visits, using session recordings to understand and optimize referral behavior.
User Retention Rate
Importance: The percentage of users who continue to use the product over a given period. It's a critical metric for sustainable growth, reflecting long-term product value and user satisfaction.
PostHog approach: Track retention events like user_returned and session_started. Create retention dashboards with cohort analysis by acquisition source to track trends over time. Use session recordings to understand the behavior of retained users and correlation analysis to identify key retention-driving features. Set up automated alerts for retention drops. Autocapture allows non-technical users to track user return patterns and feature usage that correlates with retention.
Mobile App Performance
Importance: Measures the responsiveness, stability, and overall user experience of a mobile application. Good performance is essential for user satisfaction and retention on mobile devices.
PostHog approach: Track mobile-specific events like app_opened and app_crashed with properties such as app version and device type. Use PostHog's real user monitoring for performance and Core Web Vitals tracking. Create mobile performance dashboards, set up crash monitoring with alerts, and use session recordings to identify mobile-specific UX issues. Non-technical users can leverage autocapture to track mobile interactions and compare mobile vs. desktop usage patterns.
E-commerce
Common business problems & personas
Key business problems
High cart abandonment rates – Customers adding items but not completing purchases
Low conversion rates – Visitors not converting to customers
Poor product discovery – Customers unable to find products they want
High return rates – Products being returned frequently
Seasonal inventory issues – Over/under stocking during peak periods
Poor mobile experience – Mobile users having difficulty shopping
Low customer lifetime value – Customers making only one purchase
Ineffective marketing attribution – Difficulty tracking which campaigns drive sales
Primary personas & their pain points
E-commerce Managers
Pain points: Can't identify why customers abandon carts, struggle to optimize product pages, lack visibility into customer journey
Importance: Represents the total value of all goods sold over a specific period. GMV is the primary measure of an e-commerce platform's scale and is essential for understanding top-line growth and market share.
PostHog approach: Track all purchase events (product_viewed, add_to_cart, purchase_completed) with properties like product category, price, and quantity. Connect to your e-commerce platform for comprehensive data. Create dashboards for real-time GMV tracking and product performance analysis by category. Use cohort analysis to track customer value over time and set up alerts for unusual GMV patterns. For non-technical users, autocapture on product pages and "add to cart" buttons can track the conversion journey and identify popular products, with session recordings helping to optimize product pages.
AOV (Average Order Value)
Importance: The average amount spent each time a customer places an order. Increasing AOV is a key strategy for maximizing revenue without increasing the number of customers, directly impacting profitability.
PostHog approach: Track cart and purchase events (cart_updated, purchase_completed) with properties like cart value and discount applied. Use funnel analysis to optimize the cart and identify abandonment points. A/B test pricing and product recommendations to find effective upselling strategies. Use correlation analysis to identify behaviors of customers with high AOV. Non-technical users can use autocapture to track interactions on the cart page, analyze abandonment patterns, and use session recordings to optimize the checkout flow.
Conversion Rate
Importance: The percentage of visitors who complete a purchase. This is a critical metric for gauging the effectiveness of the entire customer journey, from landing page to checkout, and is a primary indicator of site performance and user experience.
PostHog approach: Track all steps in the conversion funnel (page_viewed, product_viewed, add_to_cart, checkout_started, purchase_completed) with properties like traffic source and device type. Create comprehensive conversion funnels to identify drop-off points and use session recordings to understand checkout friction. A/B test checkout flows and product pages to optimize the user path. Non-technical users can use autocapture to track all funnel page visits and interactions, creating funnels and using session recordings to optimize conversion paths with no code.
Cart Abandonment
Importance: The rate at which users add items to their cart but leave without completing the purchase. A high cart abandonment rate often indicates friction in the checkout process, unexpected costs, or a poor user experience.
PostHog approach: Track cart interactions like add_to_cart and remove_from_cart. Use session recordings to understand the behavior of users who abandon their carts, and implement exit-intent surveys to gather direct feedback on abandonment reasons. Create funnels that specifically track the checkout process to pinpoint exact drop-off points. This data can inform cart abandonment recovery strategies. Non-technical users can use autocapture to track all cart page interactions and build abandonment funnels to analyze user behavior.
Customer Lifetime Value
Importance: The total revenue a business can expect from a single customer throughout their relationship. CLV is vital for making strategic decisions about marketing spend, customer acquisition, and retention efforts, ensuring long-term profitability.
PostHog approach: Track all customer interactions, including purchase_completed, return_requested, and support_contacted, with properties like purchase history and acquisition source. Create cohort analyses by acquisition month to understand how customer value evolves. Use correlation analysis to identify behaviors of high-value customers and PostHog's predictive analytics for CLV forecasting. Non-technical users can use autocapture on account and order history pages to track engagement patterns and use session recordings to understand high-value customer behavior.
Marketplace
Common business problems & personas
Key business problems
Supply-demand imbalance – Too many buyers/sellers on one side of the marketplace
Low trust and safety – Users concerned about fraud or poor quality
Poor matching algorithms – Buyers and sellers not connecting effectively
High customer acquisition costs – Expensive to acquire both buyers and sellers
Network effects challenges – Difficulty achieving critical mass
Payment and escrow issues – Complex payment flows and trust concerns
Quality control problems – Inconsistent service/product quality
Geographic expansion challenges – Difficulty scaling to new markets
Primary personas & their pain points
Marketplace Operations Managers
Pain points: Can't balance supply and demand, struggle with quality control, lack visibility into marketplace health
Pain Points: High support volume, poor user satisfaction, difficulty resolving disputes
PostHog Solutions: User journey analysis, satisfaction tracking, dispute resolution insights, support optimization
Key metrics & PostHog
GMV (Gross Merchandise Value)
Importance: Represents the total value of all transactions between buyers and sellers on the platform over a specific period. It is the primary indicator of a marketplace's scale, liquidity, and overall health, reflecting its ability to facilitate transactions and generate value for its users.
PostHog approach: Track marketplace transaction events like listing_viewed, booking_requested, and transaction_completed with properties such as category, price, seller_id, and buyer_id. Integrate with payment processors for comprehensive data. Use PostHog to create real-time GMV dashboards with breakdowns by category, set up seller and buyer performance tracking, conduct cohort analysis to monitor marketplace growth, and create alerts for unusual transaction patterns. Non-technical users can use autocapture to track listing views and booking requests, creating funnels to analyze the path to a completed transaction and using session recordings to optimize the user journey.
Take Rate
Importance: The percentage of GMV that the marketplace captures as revenue (commission or fees). It is a crucial metric for understanding the marketplace's business model effectiveness and profitability. Optimizing the take rate is key to sustainable growth.
PostHog approach: Track commission events like commission_earned from transaction_completed events, with properties for transaction amount, commission percentage, and category. Analyze revenue and profitability by category on dashboards. This allows for identifying opportunities to optimize the take rate, for example by analyzing its drivers with correlation analysis and setting up alerts for significant changes. Non-technical users can build dashboards to monitor take rate trends across different product categories or seller tiers, helping to inform pricing strategy without writing any code.
Supply/Demand Balance
Importance: Measures the equilibrium between the number of sellers (supply) and buyers (demand) on the platform. A balanced marketplace ensures a good user experience for both sides, preventing situations like too few products for buyers or too few customers for sellers, which can lead to churn.
PostHog approach: Track supply-side events (listing_created, service_offered) and demand-side events (search_performed, booking_requested). Use properties like category, location, and search terms to analyze supply-demand gaps on dashboards. Funnel analysis can reveal booking conversion rates, while alerts can notify of imbalances, helping to identify and act on new market opportunities. Non-technical users can create dashboards that visualize searches with no results, providing a simple way to spot unmet demand and guide supply-side growth efforts.
Network Effects
Importance: Measures how the value of the platform increases for users as more people use it. Strong network effects create a powerful competitive advantage (a "moat") and are the engine of sustainable, viral growth for marketplaces. It's what makes a marketplace more valuable as it scales.
PostHog approach: Track network interaction events like user_referred, invitation_accepted, and cross_side_activity (e.g., a user being both a buyer and seller). Use properties to distinguish user types. Dashboards can visualize network growth and viral coefficients. Cohort analysis is key to measuring how network effects develop over time for different user groups, and alerts can highlight opportunities for growth. Non-technical users can use autocapture on referral pages and share buttons to analyze the effectiveness of viral loops and optimize the user flow with session recordings.
Trust & Safety Metrics
Importance: Trust is the currency of a marketplace. These metrics, such as user ratings, review rates, fraud reports, and dispute rates, measure the level of safety and reliability on the platform. High trust is essential for encouraging transactions, retaining users, and building a strong brand reputation.
PostHog approach: Track trust-related events like review_submitted, dispute_filed, and fraud_detected, enriched with properties on user reputation and transaction history. Dashboards can monitor trust scores and fraud rates. Session recordings are invaluable for investigating suspicious user behavior and understanding how trust is built (or broken) in user flows. Set up alerts for fraud signals and use correlation analysis to identify key indicators of trust. Non-technical users can create surveys to collect user feedback on trust and use session recordings to review the user journey for those who file disputes.
Developer Tools
Common business problems & personas
Key business problems
Low developer adoption – Developers not integrating or using the tool
High API error rates – Poor API performance and reliability
Poor documentation engagement – Developers struggling to understand the product
Low community engagement – Lack of developer community growth
High support ticket volume – Developers needing extensive support
Poor onboarding experience – Developers dropping off during setup
Low feature adoption – Developers not using advanced features
Difficulty measuring developer success – Hard to track developer outcomes
Importance: Measures the rate at which developers start using a tool, from initial signup to making their first API call. It's the most critical top-of-funnel metric for developer tools, as it indicates the health of the onboarding process and the tool's initial appeal. High adoption is a leading indicator of future growth and product-market fit.
PostHog approach: Track key developer touchpoints like account_created, sdk_installed, and api_call_made with properties for tech stack and company size. Create adoption funnels to analyze the journey from first contact to active use, identifying drop-off points. Use cohort analysis to track developer retention over time and map the developer journey to understand common paths to success. Alerts can signal developer churn risk. Non-technical users, like DevRel teams, can build these funnels and dashboards without code to monitor adoption trends and measure the impact of their initiatives.
API Usage
Importance: Tracks the frequency, volume, and patterns of API calls made by developers. This metric is vital for understanding which features are most valuable, how developers are integrating the product, and the overall health and performance of the API. It directly reflects product engagement and stickiness for a developer-focused product.
PostHog approach: Instrument all API endpoints to track events like api_request and api_error, with properties for the specific endpoint, response time, and error type. Create API performance dashboards to monitor usage, latency, and error rates in real-time. Set up alerts for performance degradation or spikes in errors. Use correlation analysis to understand which usage patterns are associated with retention or expansion. Non-technical users can use dashboards to see which endpoints are most popular and identify which customers are experiencing the most errors.
Documentation Engagement
Importance: For developer tools, documentation is the product. This metric measures how developers interact with documentation, including page views, search queries, and time spent on pages. High engagement indicates that the documentation is useful and helps developers solve problems, which is critical for adoption and reducing support load.
PostHog approach: Track documentation interactions like docs_page_viewed, code_sample_copied, and tutorial_completed, with properties for the page, search terms, and user segment. Use session recordings to see where developers get stuck or confused. Analyze search patterns to identify content gaps and create dashboards to monitor documentation effectiveness. Non-technical users, like technical writers, can use these insights to prioritize content updates and improve the developer experience without needing to write code.
Community Growth
Importance: Measures the health and vibrancy of the developer community around a product (e.g., on GitHub, Slack, Discord). A growing, active community provides social proof, drives word-of-mouth adoption, offers scalable support, and is a rich source of product feedback. It acts as a moat and a powerful growth engine.
PostHog approach: Track community interactions from various platforms by sending events like forum_post_created, github_issue_opened, or community_event_attended. Use properties to segment by contribution level and topic. Create dashboards to monitor community engagement and growth trends. Use cohort analysis to track member retention and identify "power users" who can become community champions. Non-technical users, like community managers, can easily track these metrics to demonstrate the value of their programs.
Support Ticket Volume
Importance: The number of support tickets created by developers. While some tickets are expected, a high volume, especially on recurring themes, points to friction in the product, confusing documentation, or a poor onboarding experience. Analyzing this data is key to improving the product and reducing operational costs.
PostHog approach: Integrate your support system (e.g., Zendesk, Jira) with PostHog to track support_ticket_created and support_ticket_resolved events. Enrich these events with properties like ticket type, priority, and resolution time. Use correlation analysis to link support tickets to specific in-product behaviors or documentation pages, identifying the root cause of developer friction. Dashboards can help monitor support trends and efficiency. This allows non-technical team members to identify which product areas are generating the most support load.
Fintech
Common business problems & personas
Key business problems
High fraud rates – Sophisticated fraud attempts and false positives
Importance: Measures the total number or value of transactions processed by the platform. This is a fundamental indicator of a fintech product's adoption, usage, and overall scale. It directly impacts revenue and is a key signal of market traction and business health.
PostHog approach: Track all financial transaction events like transaction_initiated, transaction_completed, and transaction_failed with detailed properties such as transaction type, amount, currency, and user segment. Use dashboards for real-time monitoring of transaction volume and success rates. Correlation analysis can help understand what user behaviors lead to more transactions, and alerts can be set for unusual spikes or dips in activity. Non-technical users can build funnels to analyze the transaction flow and identify drop-off points without writing any code.
Fraud Rate
Importance: The percentage of transactions that are fraudulent. In fintech, managing fraud is critical for financial stability, maintaining user trust, and meeting regulatory obligations. A low fraud rate is essential for long-term viability and building a reputable platform.
PostHog approach: Track fraud and risk-related events such as fraud_detected, risk_assessment_failed, or verification_completed. Enrich this data with properties like risk factors, fraud type, and user behavior patterns. Session recordings are invaluable for investigating suspicious user behavior to understand fraud vectors. Create dashboards to monitor fraud rates in real-time and set up alerts for emerging fraud patterns. Non-technical risk teams can use session recordings to review suspicious sessions flagged by alerts.
Compliance Metrics
Importance: Measures adherence to financial regulations like KYC (Know Your Customer) and AML (Anti-Money Laundering). For fintech companies, compliance is not optional; it's a license to operate. Tracking these metrics is crucial for avoiding fines, legal penalties, and reputational damage.
PostHog approach: Track all compliance-related events, such as kyc_started, kyc_completed, and aml_check_failed. Use properties to log the compliance type, status, and user segment. This creates a detailed audit trail for regulatory purposes. Dashboards can provide a real-time view of compliance status and help monitor the efficiency of these critical flows. Alerts can be configured to flag compliance failures, allowing teams to act quickly. Non-technical compliance officers can use funnels to analyze and optimize the KYC process.
Customer Acquisition Cost
Importance: The total cost to acquire a new, verified customer. Fintech often has high acquisition costs due to marketing, compliance, and verification expenses. Understanding and optimizing CAC is crucial for ensuring profitability and scaling the business sustainably.
PostHog approach: Track the entire acquisition funnel, from ad_clicked and account_opened to verification_completed and first_transaction. Enrich these events with properties like acquisition source, campaign, and verification costs. Use funnel analysis to identify drop-off points in the onboarding and KYC process. A/B testing can be used to optimize landing pages and onboarding flows to reduce CAC. Non-technical marketers can use dashboards to compare the CAC and LTV across different channels.
Regulatory Reporting
Importance: This tracks the ability of the company to generate accurate and timely reports for regulatory bodies. Efficient and reliable reporting processes are essential for demonstrating compliance and avoiding penalties. While PostHog doesn't generate the reports, it can monitor the internal processes that do.
PostHog approach: Track internal events related to the reporting process, such as report_generated, audit_trail_requested, and compliance_check_completed. Use properties to specify the report type and its status. This provides visibility into the operational health of the reporting systems. Dashboards can be used to monitor the success and timeliness of report generation, and alerts can be set up to flag any failures or delays in the process, ensuring the compliance team is aware of any issues.
Healthcare/Medtech
Common business problems & personas
Key business problems
Poor patient outcomes – Patients not achieving desired health results
Low user adoption – Healthcare providers not using the system effectively
Compliance violations – Difficulty meeting HIPAA and other regulatory requirements
Importance: This is the core metric for any healthcare product, measuring the actual health impact on patients. Demonstrating positive patient outcomes is crucial for clinical validation, provider adoption, regulatory approval, and building patient trust. It is the ultimate measure of product value and efficacy.
PostHog approach: Track key events in the patient journey, such as treatment_plan_started, outcome_measured, and follow_up_completed. Use properties to segment by treatment type, patient demographics, and specific outcome metrics. Cohort analysis can track how outcomes trend over time for different patient groups. Dashboards can visualize progress towards clinical goals, and correlation analysis can help identify which product features are linked to better outcomes. Non-technical users, like clinicians, can use dashboards to monitor patient progress without writing code.
Compliance Metrics
Importance: Healthcare is a highly regulated industry (e.g., HIPAA in the US). Compliance metrics track adherence to these regulations, particularly around data privacy and security. Failure to comply can result in severe penalties, loss of trust, and legal action, making it a foundational requirement for any MedTech product.
PostHog approach: Track all compliance-related events, such as hipaa_audit_trail_accessed, data_access_logged, and patient_consent_obtained. Properties should include the user role, type of data accessed, and audit results to create an immutable log. Dashboards can provide a real-time view of compliance activities, and alerts can be set up for any unauthorized access attempts or compliance failures. Non-technical compliance officers can use these dashboards to monitor activity and generate reports.
User Adoption
Importance: Measures how effectively healthcare providers (doctors, nurses, etc.) are integrating a new tool into their daily work. Low adoption by clinicians can undermine the intended benefits of a technology, regardless of its potential. High adoption is key to realizing efficiency gains and improving patient care at scale.
PostHog approach: Track user interactions such as feature_used, workflow_completed, and training_module_completed. Segment by user role (e.g., doctor, nurse) using properties. Adoption funnels can show where users drop off during onboarding. Session recordings are invaluable for understanding how clinicians use the product in a real-world context. Alerts can flag low adoption in specific departments. Non-technical training teams can analyze session recordings to improve their training materials.
Clinical Workflow Efficiency
Importance: Measures the time and effort required for clinicians to complete tasks using the product. In the high-pressure healthcare environment, time is a critical resource. Improving workflow efficiency can reduce clinician burnout, lower operational costs, and allow more time for direct patient care.
PostHog approach: Track workflow events from start to finish: workflow_started, step_completed, workflow_completed. Use properties to capture the duration of each step and the user role. Funnel analysis is perfect for identifying bottlenecks where users get stuck or take too long. Dashboards can monitor average completion times for key workflows. Non-technical managers can use these funnels to identify areas for process improvement without needing technical assistance.
Data Accuracy
Importance: In healthcare, critical decisions are made based on patient data. Inaccurate or incomplete data can lead to misdiagnosis, incorrect treatment, and serious patient harm. This metric tracks the integrity and reliability of the data within the system, which is fundamental to patient safety.
PostHog approach: Track data entry and validation events like data_entered, data_validated, and error_detected. Use properties to specify the data type, validation method, and error type. Create dashboards to monitor data quality trends and error rates. Correlation analysis can help identify if specific user roles or workflow steps are associated with higher error rates. Alerts can notify teams of spikes in data entry errors, allowing for swift investigation.
Content/Media
Common business problems & personas
Key business problems
Low content engagement – Users not consuming or interacting with content
Poor content discovery – Users unable to find relevant content
Low subscription conversion – Free users not converting to paid subscribers
Poor ad performance – Low click-through rates and ad revenue
High content production costs – Expensive to create quality content
Poor user retention – Users not returning to consume more content
PostHog solutions: Subscription optimization, ad performance tracking, monetization strategy insights
Key metrics & PostHog
Engagement Rate
Importance: Measures how actively users are interacting with content beyond just viewing it (e.g., likes, shares, comments, time spent). It's a key indicator of content quality and audience resonance. High engagement suggests that the content is valuable, which is crucial for building a loyal audience and driving retention.
PostHog approach: Track engagement events like content_viewed, time_spent_on_page, video_played_to_75%, and article_shared. Use properties to segment by content type and user segment. A custom "engagement score" can be created using formulas in PostHog to weigh different interactions. Cohort analysis can track how engagement evolves for different user groups. Non-technical editors can use dashboards to see which articles are most engaging to inform their content strategy.
Content Performance
Importance: Provides a holistic view of how individual pieces of content contribute to business goals, from views to conversions. Understanding what content performs well is essential for optimizing content strategy, allocating production resources effectively, and maximizing the ROI of content creation.
PostHog approach: Track the content lifecycle with events like content_published, content_viewed, and content_shared, enriched with properties like category, author, and format. Use correlation analysis to identify the attributes of successful content (e.g., "how-to" articles over 1500 words drive the most shares). Dashboards can rank content by performance, and alerts can notify teams when a piece of content starts trending. Non-technical content teams can use these insights to double down on what works.
User Retention
Importance: Measures the percentage of users who return to the platform over time. For media companies, retention is the lifeblood of the business, as it's far more cost-effective than acquisition. High retention indicates that users find ongoing value in the content, which is key for long-term growth and subscription revenue.
PostHog approach: Track retention by monitoring user_returned or session_started events. Use PostHog's retention cohorts to analyze how retention differs by acquisition source or first content consumed. Correlation analysis can identify behaviors (e.g., subscribing to a newsletter) that are leading indicators of retention. Churn prediction models can help proactively identify at-risk users. Non-technical marketers can use cohorts to understand the long-term value of users from different campaigns.
Ad Revenue
Importance: For ad-supported media companies, this metric directly measures financial performance. Optimizing ad revenue involves balancing user experience with monetization, making it crucial to track metrics like impressions, click-through rates (CTR), and revenue per user.
PostHog approach: Track ad-related events like ad_impression, ad_click, and ad_revenue_generated. Use properties to segment by ad type, placement, and user segment. A/B test different ad placements and formats to see what generates the most revenue without harming engagement. Dashboards can monitor ad performance in real-time, and alerts can flag underperforming ad units. Non-technical revenue teams can use these dashboards to track progress against revenue goals.
Subscription Metrics
Importance: For subscription-based media companies, metrics like conversion rate, subscriber LTV, and churn are the ultimate measure of business health. They track the ability to convert casual readers into paying subscribers and retain them, directly reflecting the perceived value of the premium offering.
PostHog approach: Track the entire subscription funnel with events like paywall_hit, subscription_started, subscription_renewed, and subscription_cancelled. Use funnel analysis to identify drop-off points in the conversion process and properties like plan type to segment subscribers. Cohort analysis is essential for tracking subscriber LTV and churn over time. Non-technical product managers can use funnels to optimize the checkout flow and A/B test different paywall strategies.
We firmly adhere to laws in countries where we do business, and welcome everyone abiding by those legal restrictions to be our customers - paid or free, in all but a few very exceptional circumstances:
The customer is engaging in illegal or unlawful behavior.
The customer is encouraging violence or discriminating against legally protected groups.
In these cases, we may choose not to do business with the customer.
Sanctioned countries and companies
US laws mean we may also be prohibited from working with certain companies, due to ongoing US sanctions. In this case we do not have discretion - we are banned from working with these companies entirely.
If you need to check if a particular company appears on a US sanctions list, you can use the US Treasury's Sanction Search. In particular, you should be mindful of companies that sign up which are based in the following territories:
Balkans
Belarus
Burundi
Central African Republic
Crimea
Democratic Republic of the Congo
Iraq
Libya
Lebanon
Myanmar (formerly Burma)
Russia
Sudan
South Sudan
Somalia
Ukraine
Venezuela
Yemen
Zimbabwe
US sanctions mean that we are not allowed to offer services at all to _any_ companies based in:
Cuba
Iran
North Korea
Syria
Update for June 2024 US sanctions against Russia
In June 2024, the US Treasury's Office of Foreign Asset Control issued updated sanctions against Russia which prohibit the sale or supply of services to individuals or organizations in Russia. The sanctions take effect on September 10, 2024 and continue indefinitely.
We must comply with these sanctions, so in August 2024 we contacted impacted individuals to let them know we would make the following changes on September 9th, 2024:
We no longer accept any payments from individuals or organizations based in Russia
We block access to PostHog for all individuals in Russia, based on their IP
We terminated paid accounts with all customers located in Russia
There are some exemptions to the sanctions including any service to any entity located in the Russian Federation that is owned or controlled, directly or indirectly, by a U.S. person.
If a customer believes they've been incorrectly impacted by our response to these sanctions, or have further questions about them, ask them to contact sales@posthog.com so we can investigate.
Dealing with the above
If you find a paying customer who we should not be doing business with according to the rules above, use the following process:
First get in touch with all active users in the account via a group email to let them know that:
As they are a Russian company, we can not do business with them and link this handbook page.
You'll be cancelling their paid subscription today
They will be given a few days grace to export any data, and then access to PostHog will be suspended
In Stripe, cancel their subscription (don't collect any due fees) and also set is_blocked_from_subscribing to true in their customer metadata. You can access their Stripe customer record via Customer Analytics.
After 3 business days, suspend their access to PostHog using the Billing Admin.
Checking whether we can do business with a customer
If you work in Sales, CS & Onboarding, or Support and are not sure if we are able to work with a customer you are dealing with, ask in #legal and one of the team will be able to let you know either way. For the most part, these edge cases are to do with customers attempting to work around sanctions in their country, though other edge cases can also occur.
Customers who track adult or other potentially offensive content aren't automatically excluded - we have content warnings set up in PostHog Support for them. If you are working with their account more regularly as part of the Sales or CS & Onboarding teams, we also recommend that you avoid logging in as them, and that you provide any training using demo data.
AKA our Value Proposition, these are some of the things we've found useful to share when chatting to customers about why PostHog is different and better than our competitors. As a company, the primary user persona we are building for are Product Engineers, so we focus on them first. We then provide messaging for the other roles we may encounter in an inbound sales cycle, and still want to be successful when selling to them.
Product Engineers
One-liner
We help you debug and ship your product faster.
Summary
By integrating PostHog into your app, you’ll be able to track and diagnose errors, roll out and test new features and gain a better understanding of your user behavior. With that greater understanding, you'll then be able to take action on it and respond to your user needs quickly and effectively. Getting all of these capabilities through one SDK means you reduce the overhead of maintaining your app and can focus on shipping your product.
Use cases
Automated error tracking for front and back end, coupled with other capabilities like product analytics and session replay lets you understand where the biggest issues are in your app, see them happening in real time and then diagnose and fix them.
Target new features at a segment of your user base, see them experiencing them in real time and get feedback via surveys on what’s working and what’s not.
Test out new features by splitting old and new experiences between users - PostHog’s statistical model will help you understand which variant of a feature to choose and then safely roll that out to all of your users.
Understand and debug how your users consume AI in your product and monitor performance and cost when using different models.
Respond to churn by triggering a survey when a subscription is canceled to understand what went wrong for them and how you can improve your product.
Product Managers
One-liner
Self-serve analytics without needing to ask your engineers or data team for help.
Summary
After your engineers integrate the PostHog SDK, you’ll be able to self-serve analytics without asking your data team for insights. We automatically track user interactions with your app and then let you tag key events for use in analytics. You’ll also be able to navigate from the data to individual user interactions to see how users interact with your app and make informed product decisions, and then finally use behavioral triggers to send feedback surveys and more all without engineering effort.
Use cases
Create trends, funnels and other insights without asking your engineers to instrument events. We automatically track pageviews, clicks, rageclicks etc and then make it easy to visualize these with insights Product Managers will be familiar with.
Easily uncover user friction by following the drop-offs in a funnel to replays to understand what the user experiences. Surface any errors to your engineering team via issue assignment to get your user problems solved quickly.
Enrich your product data with revenue and other data to gain a deeper understanding of what drives revenue growth in your product. It’s only a few clicks to integrate most data sources and then you’ll be able to enrich your user data with additional metrics without a data team. We do the heavy lifting for you.
Ask questions of your product - We create the insights for you, all you need to do is ask PostHog AI questions about your product.
Respond to churn by triggering a survey when a subscription is canceled to understand what went wrong for them.
Create event-driven workflows to automatically reach out to customers who hit a certain point in your product journey.
Marketing
One-liner
A familiar analytics experience with all of the integrations you need to decide where to focus your marketing efforts.
Summary
By deploying our simple JavaScript snippet on your website you’ll capture all of the data you need to measure channel performance, and then visualize that data in a familiar format without any additional report writing. Optionally hook up Stripe or other revenue sources to measure revenue attribution.
Use cases
Replace Google Analytics to get a view on your marketing data which is familiar to experienced marketers. Recent updates to GA4 have not sat well with that persona so folks are looking for something more familiar.
Ad platform connection provides pre-built insights to help you understand your campaign performance and associated costs.
Data Engineers
One-liner
A complete developer platform which fits into your existing data stack.
Summary
Using PostHog's CDP lets you aggregate data from multiple technologies and platforms. It takes a few clicks to set up exports of that data to your data warehouse, and your product and engineering teams can self-serve their own analytics from within PostHog.
Use cases
Aggregate your user and error data from web and mobile apps, backend systems, ad platforms and others into your data warehouse via our simple to set up batch exports. Avoid needing to set up ETL jobs from disparate sources and figuring out APIs.
Let your engineers and product team self-serve analytics and error tracking from within a familiar platform.
Analytics is an after-the-fact passive activity, but your events in PostHog can be so much more than that. You can use PostHog events to react to customer behaviors, without investing engineering time to make those workflows.
Our usage-based pricing means that you’ll only pay for what you use and have full control of those costs, unlike opaque software contracts, where the prices go up every year with zero innovation attached.
The Developer Marketing team has created sales enablement materials, covering some product information and general objection handling for specific products. These exist as Google Docs as they are living documents, but are listed below.
Pricing principles covers what we charge for and the principles we hold ourselves to. This page covers the actual work: what you analyze and write, who reviews, who you communicate changes to, and in what order.
Budget roughly six weeks from the first draft of your RFC to migration/launch day. This is definitely a cross-team effort, so communicate changes openly and early to get it across the line effectively.
RFC
Do the analysis first
The RFC is where you show your work and your thinking, so do the work before you open the PR. This often contains:
New prices, modeled against old prices and competitors, with real usage data. A single "they charge $X" comparison isn't enough. Ideally show this with either modeled scenarios or real user data, so you can see how a customer's bill compares against competitors and how it will change.
Revenue changes. Will we make more or less money? How much will it change by?
Unit economics. What does it cost us to serve, and what's the margin at each tier?
Revenue dynamics. For example, how does the change shift the revenue concentration on your biggest customers?
At-risk revenue. We can't always be the cheapest if competitors use different pricing models. If price changes include an increase and may cause churn risk, model it.
This isn't an exhaustive list. If something here is irrelevant, remove it. If something else is relevant, add it.
Format
This should be formatted in a way that is easy to read and review. A spreadsheet is the common way and can be linked to in the RFC (Example spreadsheet).
Constraints
Your pricing is also constrained by the product architectures billing supports. Check the product definition guide in the billing repo while working through your pricing.
Write it
Open an RFC in requests-for-comments-internal. Include the breakdown above, what this does to existing customers, and your analysis / spreadsheet, and be explicit about what you're not changing. Deferring a decision is fine but mention it and why you've decided to defer. We don't want to be changing prices too often so there should be a reason why we're not bundling the changes together.
For existing customers, grandfather the old pricing. For beta-to-GA price changes, the grandfathering period is usually 1 month. For changes to existing GA pricing, it's usually 2 months.
Reviewers
Get a mix. At minimum:
Your team: they have usage and customer context.
Someone from the billing team: they understand what's possible with the current billing architecture and whether changes are worth the engineering time.
Someone from Blitzscale: whoever has the most industry context on your product and/or pricing experience.
If it's your first pricing RFC, your onboarding buddy PM.
Review process
You do not need full consensus. You are ultimately the driver but each reasonable objection should be resolved or answered. A good RFC will have discussion around it, so buffer in time for answering questions, additional research, and a possible revision or two.
Implementation
Once you've decided to move ahead with your new pricing scheme, you can begin implementing. Implementing a pricing change can often feel like juggling because you're working across a few teams with a single launch date. Communicating publicly and early helps.
The moment you have a launch date (mentioned below), tell everyone who has to do work:
Your PMM, or the Developer Marketing team if you don't have one
TAMs, AEs, CSMs, and support
Paid ads
Giving at least two weeks' notice is ideal. If billing hands you a date less than two weeks out, which happens because they move fast, tell everyone ASAP. Below covers how to work with each team.
To make this a smooth process, it helps to start with a new "Grandfathering" tab in the spreadsheet with the following data for the orgs you are grandfathering:
Org ID
Org Name
Recent bill on old pricing
Estimated bill on new pricing
Current plan (paid, extended free tier, grandfathered, etc.)
Account manager (if managed)
Owner and admin emails
This can be created with the building-usage-and-revenue-dataset skill and is used across billing changes, customer outreach, the email blast, etc., so it will let you easily work with all the necessary teams as you implement the changes.
You can also add large customers (of other products) who are close to crossing the free tier even though they aren't paying yet.
Billing
Kick off with the billing-pricing-changes skill in the billing repo. It generates the pricing PR, then billing takes it from there.
Billing then gives you migration date options based on their capacity and what else is queued. This date is your launch date. It's when new customers get the new price and when the grandfathering clock starts for everyone else.
The first thing they'll need is that "Grandfathering" tab as they use the list of org IDs to grandfather accounts when the pricing changes go into effect.
Notifying
Split by whether the account is managed.
Managed accounts
TAMs, AEs, and CSMs handle these. Post the spreadsheet in #group-cs-sales-support with an overview of the changes and the reason why.
This is where the old bill, estimated new bill, and account owner become useful. Everyone can communicate the pricing changes clearly to their respective accounts.
Non-managed accounts
PMMs typically write the emails but if your product doesn't have one, #team-marketing will help. Start from a recent pricing-change email (ask the PMs) rather than a blank page.
If the price is going up, the email should say so plainly. Don't talk around it.
Build it in Workflows: an email step, a static cohort of the grandfathered orgs' owners and admins, and a batch trigger filtered on that cohort. Exclude managed accounts. Those customers are getting a conversation instead.
You can schedule the send or send it manually on the day, once you know the migration went fine.
The email should come from you or the PMM, not a generic address.
Start the sender permission on day one. Being added as an approved sender needs project 2 admin, and finding someone who can do it can take days. It's the longest-lead item on this whole list, and a two-minute job for the right person. Ask in #team-workflows.
Marketing
Docs, blogs, and the pricing page
The pricing page calculator updates from the billing migration, but double-check it renders. Most product page calculators pull from the same billing API, so they update too. The exception is a product with a custom pricing logic (like /replay-vision/pricing for a launch promo). Check that's not the case for your product. Additionally, have an agent comb the posthog.com repo for the old price. It shows up in more places than you'd expect: product docs, comparison blog posts, "best X tools" roundups with worked cost examples, and SEO descriptions. Some pages carry a "pricing current as of" date that needs bumping too.
Paid ads
The paid ads team runs ads with your price in them, on Google, LinkedIn, Reddit, and more. Give them the date with the same two weeks' notice as everyone else, and tell them you've already handled docs and blogs so they only need to worry about ad copy.
Launch day
Internal. Post in #tell-posthog-anything with the before and after tables, the grandfathering terms, and a link to the RFC. Add any other important information, like whether the change is margin positive.
External. Check with billing that the migration went through and confirm the email went out.
Launch checklist
Open the pricing PR with the billing-pricing-changes skill
Get the launch date from billing
Create the grandfathering tab with the building-usage-and-revenue-dataset skill
Send billing the org IDs to grandfather
Notify TAMs, AEs, CSMs, and support
Notify the Developer Marketing team
Notify the paid ads team
Ask #team-workflows to add you (or the PMM) as an email sender
Create the static cohort of owner and admin emails
(If no PMM) Create the email, set up the batch trigger, and add the cohort
Sweep posthog.com for the old price and check the pricing calculator renders
Post the change in #tell-posthog-anything on launch day
Confirm the migration went through, then send the email
After launch checklist
Confirm the ads and the pricing page are updated
Update this page with whatever information we missed
"Help me understand how my AI features perform, what they cost, and how users interact with them."
Track model performance: latency, cost per query, token usage, error rates across providers and models
Evaluate AI output quality and detect regressions after prompt or model changes
Understand how users actually interact with AI-generated output (not just whether the model responded)
A/B test prompts, models, and parameters against real user behavior metrics
Monitor cost attribution by user, organization, or feature so you know where your OpenAI bill is going
Catch model failures, hallucinations, and timeouts alongside traditional application errors
This is the fastest growing segment of our customer base. AI-native companies are adopting PostHog at a high rate, but often only for AI Observability or only for Product Analytics. The cross-sell opportunity is significant because AI products have unique observability needs that span multiple PostHog products.
The buyer persona is distinct: AI engineers care about model-level metrics (latency, cost, token usage, accuracy) first, user-level analytics second. Leading with the AI story opens the door to everything else.
What PostHog products are relevant?
AI Observability (core) — Model performance, cost tracking, latency monitoring. Trace individual LLM calls with inputs, outputs, token counts, latency, and cost. Aggregate views by model, provider, feature, user, or organization.
AI Evals — Score and evaluate AI outputs, proactively surface quality issues and user struggles. Run automated evaluations after prompt or model changes to catch regressions that look "fine" from an error rate perspective but degrade user experience. This is a bridge product: its primary home is AI/LLM Obs, but it unlocks value in Product Intelligence (surface where users struggle based on output quality) and Release Engineering (catch quality regressions after prompt/model changes).
Product Analytics — User behavior around AI features. How do users interact with AI-generated output? Do they accept suggestions, reject them, regenerate? Which users/organizations drive the most AI usage (and cost)? Funnels and retention for AI-powered flows.
Experiments — A/B test prompts, models, and parameters against real user behavior metrics. "Does GPT-4o produce better outcomes than Claude for this use case?" measured not by model benchmarks but by user conversion, retention, and satisfaction.
Error Tracking — Catch model failures, hallucinations (if detectable), timeouts, rate limit errors. Traditional error tracking applied to the AI layer. When combined with AI Observability, you get both the exception and the model-level context.
Session Replay — See the user experience of AI features. Watch how users interact with AI-generated content: do they read it? Copy it? Regenerate? Leave? This qualitative layer is especially valuable because AI feature UX is hard to quantify with events alone.
**Prompt management (beta)** — Version, store, and roll out prompts from PostHog rather than hardcoding them, then tie a prompt version to the generations it produced.
PostHog AI — Query model performance data in natural language. "Which prompts have the highest latency and cost?" or "Show me the error rate by model this week." Useful for AI engineers who want fast answers about their own AI infrastructure. (Example prompts)
self-driving — An AI-observability scout watches generations for cost spikes, latency regressions, and quality drops on a schedule, and files an investigated report. For a team whose AI feature is the product, this is the loop applied to the thing they care most about.
Adoption path and expansion path
Entry point
Usually AI Observability or Product Analytics. Two common patterns:
Model-first: AI engineer wants to understand model performance: latency, cost, token usage. They start with AI Observability for tracing and cost attribution, then realize they need to understand how users interact with the output (Product Analytics), whether the output is actually good (AI Evals), and how to test improvements (Experiments).
Product-first: AI product team is building a product with AI features and starts with Product Analytics to track user behavior. They realize they need model-level metrics alongside user metrics, which pulls in AI Observability. From there, they want to evaluate quality (AI Evals) and test prompt/model changes (Experiments).
AI Observability → AI Evals: They can see model performance metrics (latency, cost, tokens). They need to know if the output is actually good. Evals score quality and detect regressions after changes.
AI Evals → Product Analytics: They know the model is performing well technically. But are users actually getting value from the AI features? Product Analytics tracks how users interact with AI output: acceptance rates, regeneration rates, downstream conversion.
Product Analytics → Experiments: They've identified differences in AI feature performance. Now they want to test improvements: different prompts, different models, different parameters. Experiments lets them A/B test with real user behavior as the success metric.
Experiments → Error Tracking: They're iterating on AI features. Error Tracking catches model failures, rate limit errors, and timeouts. Combined with AI Observability, they get the full picture: exception + model context.
Error Tracking → Session Replay: They're catching errors and measuring metrics. Session Replay shows them how users experience AI features, especially in ambiguous cases where the model didn't error but the output wasn't helpful.
Alternate expansion paths
Starting from Product Analytics: An AI product team already using PostHog for product analytics. They add AI Observability to get model-level metrics alongside their user behavior data. From there, AI Evals and Experiments are natural adds.
Starting from Error Tracking: Team catching model failures with Error Tracking. They realize traditional error tracking misses quality regressions (model responds but with worse output). AI Evals fills this gap, pulling in AI Observability for the full model-level context.
Business impact of solving the problem
AI-native companies are the fastest growing customer segment. Getting in early with AI Observability means PostHog becomes the default platform as these companies scale. AI-native startups that adopt PostHog at seed stage often grow into significant accounts.
AI products touch several use cases at once. AI products sit at the intersection of multiple PostHog use cases: model observability (AI/LLM Obs), user behavior analytics (Product Intelligence), release management for prompt/model changes (Release Engineering), and error tracking for model failures (Observability). One AI customer can reasonably adopt products from 4+ use cases.
No one else has this combination. Langfuse and Helicone do LLM tracing. Amplitude does product analytics. Sentry does error tracking. No one connects model performance → output quality → user behavior → business outcomes in one platform. That's PostHog's pitch.
AI Evals is the bridge product. For any account building AI features, AI Evals connects AI/LLM Observability to Product Intelligence (are users struggling based on output quality?) and Release Engineering (did a prompt change cause a quality regression?). It's a natural entry point into multiple use cases from a single product.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | |---|---|---|---| | AI Engineer | ML Engineer, AI Engineer, Applied AI | Model performance, cost optimization, latency, quality | "Can I see cost per query by model, trace individual calls, and detect quality regressions?" | | AI Product Manager | AI PM, Product Lead (AI features) | User experience of AI features, adoption rates, business impact | "Can I see how users interact with our AI features and whether they drive retention?" | | AI Founder | Founder, CTO at AI-native startup | All of the above. Cost control. Speed. Not paying for 5 tools. | "How fast can I set this up and how much does it replace?" | | AI Product Engineer | Full-stack engineer building AI features | Instrumentation, debugging, prompt iteration cycle time | "How easy is it to instrument? Can I see trace-level detail for debugging?" |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | |---|---|---| | AI Observability is active | Product usage data | AI/LLM Obs use case is live. Full expansion path available. | | Company tags include "AI" or "LLM" or "ML" | Company info / tags | AI-native or AI-building company. This use case is likely relevant even if they haven't adopted AI Observability yet. | | High Product Analytics usage + AI company | Product usage + company type | They're using analytics but haven't connected model-level metrics. AI Observability is the add. | | Customer mentions Langfuse, Helicone, or "LLM costs" in notes | Vitally notes / conversations | Direct signal. They're thinking about AI observability and may be using a competitor or building it in-house. |
PostHog usage signals
| Signal | How to Check | What It Means | |---|---|---| | LLM-related custom events (e.g., llm_generation, ai_response) | Event property explorer | They're tracking AI events in Product Analytics. AI Observability would give them model-level detail. | | High AI Observability trace volume | Product usage metrics | Active AI instrumentation. Ripe for AI Evals and Experiments. | | Experiments on AI-related features | Experiments list | They're already A/B testing AI features. Validate they're using LLM Obs for model-level measurement. | | Error Tracking exceptions from AI/model code | Error tracking events | Model failures are happening. AI Observability gives context beyond the stack trace. |
Command of the Message
Discovery questions
What AI/LLM features are you building? How central are they to your product?
How do you track model performance today? Cost, latency, token usage — where does that data live?
When you change a prompt or switch models, how do you know the output quality held up?
Can you tell which users or organizations are driving the most AI cost?
How do you decide whether to use GPT-4o vs. Claude vs. a smaller model for a given feature? Is that data-driven or gut feel?
When your AI feature produces a bad output, how do you find out? User complaint? Manual testing?
Do you A/B test different prompts or models? How do you measure success — model benchmarks or actual user behavior?
How do users interact with AI-generated output in your product? Do you track acceptance rates, regeneration, or downstream actions?
Negative consequences (of not solving this)
AI costs grow unchecked because there's no visibility into cost per query by user, feature, or model
Prompt or model changes degrade output quality but nobody notices until users complain
Model-level metrics (latency, tokens) are tracked separately from user behavior, so the team can't answer "are users actually getting value from the AI feature?"
A/B testing prompts or models relies on model benchmarks, not real user outcomes, leading to optimizations that don't translate to business results
AI failures (timeouts, rate limits, hallucinations) are caught ad hoc instead of systematically
Desired state
One platform for model performance, output quality, user behavior, and business outcomes
Cost attribution by user, organization, and feature so the team knows where the AI budget goes
Automated quality evaluation after every prompt or model change
A/B testing of prompts and models measured against real user behavior
AI errors caught proactively alongside traditional application errors
The full picture: model trace → output quality score → user interaction → business outcome, all connected
Positive outcomes
AI costs decrease through visibility and optimization (knowing which models/prompts to use where)
Quality regressions caught before they reach users at scale
Faster AI iteration cycle: change a prompt, evaluate quality, measure user impact, all in one tool
Better model selection decisions based on user outcomes, not just model benchmarks
Consolidation of AI observability (Langfuse/Helicone) with product analytics and error tracking into one platform
Success metrics
Customer-facing:
AI feature usage and adoption rates improve (users get more value from AI output)
AI costs per unit of value decrease (better model selection, prompt optimization)
Quality regression detection time decreases (evals catch issues faster)
Prompt/model experiment velocity increases
TAM-facing:
Customer expands from LLM Obs-only to multi-product (Product Analytics, Experiments, Error Tracking)
AI Evals adoption grows (quality evaluation is active, not just tracing)
Experiment count on AI features increases
Non-AI products start being adopted (Session Replay, Feature Flags) as the broader platform becomes familiar
Competitive positioning
Our positioning
Model performance + user behavior in one platform. Langfuse traces your LLM calls. PostHog traces your LLM calls AND shows you how users interact with the output AND lets you A/B test improvements AND catches errors. No one else connects the full stack.
Model performance measured against user outcomes. Other AI observability tools optimize for model performance (latency, cost, perplexity). PostHog lets you optimize for user outcomes: did the user accept the suggestion? Did they convert? Did they come back?
Experiments on prompts/models measured by business metrics. A/B test GPT-4o vs. Claude measured not by BLEU score but by user conversion and retention. This is what actually matters for AI product decisions.
AI observability + traditional observability. Error Tracking catches model failures. Session Replay shows the user experience. Product Analytics measures business impact. It's one platform, not AI observability siloed from everything else.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | |---|---|---|---| | Langfuse | Open-source LLM tracing, prompt management, evals | Broader platform (product analytics, experiments, replay, error tracking); user behavior metrics; we now ship prompt management and evals too | Longer track record on LLM-specific tooling; strong open-source community | | Helicone | LLM request logging, cost tracking, caching | Broader platform; user behavior connection; experiments; not a single-purpose tool | Simpler to set up for basic LLM logging; built-in caching/rate limiting features | | Braintrust | LLM evals, logging, prompt playground | Broader platform; user behavior metrics; production monitoring not just offline evals; we ship LLM-as-a-judge, code-based, and sentiment analysis | Better prompt playground and offline iteration workflow; deeper dataset tooling | | Datadog LLM Monitoring | LLM tracing as part of broader APM | Product analytics integration; user behavior; better pricing for AI-native startups | Full APM stack; enterprise-grade; part of existing Datadog deployment for bigger companies |
Where PostHog stands: Our strongest position is with AI-native startups and teams building AI features inside existing products. The pitch is "one platform for everything" instead of Langfuse + Amplitude + Sentry + a flag tool. We're weaker against enterprise teams already embedded in Datadog. Our sweet spot is AI teams that want model performance connected to user outcomes in one place, without managing four vendors.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | |---|---|---| | AI Observability is newer than Langfuse | Teams deep in a Langfuse workflow may find specific rough edges | Be honest about track record rather than feature gaps — prompt management and evals both ship. Position the breadth of the platform (analytics, experiments, replay) as the reason to consolidate. | | AI Evals may not support all evaluation frameworks | Teams with custom eval pipelines may want more flexibility | Check current eval capabilities. For custom frameworks, PostHog's API and data warehouse can integrate with existing eval pipelines. | | Session Replay for AI chat interfaces can be noisy | Chat-based AI products generate a lot of replay data per session | Configure sampling rules. Focus replay viewing on sessions with error events or low AI quality scores. |
Getting a customer started
What does an evaluation look like?
Scope: Instrument their primary AI feature with AI Observability tracing. Set up cost attribution by model and feature. If they have a prompt change planned, set up AI Evals before and after.
Timeline: 1 to 3 days to start capturing LLM traces. 1 to 2 weeks for meaningful cost and performance data. Eval comparisons depend on the change cycle.
Success criteria: Can you see cost per query by model? Can you trace individual LLM calls with inputs and outputs? Can you detect a quality regression after a prompt change?
PostHog investment: AI Observability free tier covers 100K events/month. Product Analytics free tier covers 1M events. Experiments are included with Feature Flags.
Key requirement: They need to instrument their LLM calls using the PostHog SDK or API. See the AI Observability installation docs for integration guides by framework — there are 20+, including OpenAI, Anthropic, Vercel AI SDK, LangChain, LangGraph, LiteLLM, Bedrock, and OpenRouter.
[ ] Enable Error Tracking for model failures, timeouts, and rate limit errors
[ ] Set up Product Analytics tracking for AI feature user interactions (accept, reject, regenerate, downstream actions)
[ ] Enable Session Replay to watch how users interact with AI output
[ ] Plan first Experiment on an AI feature: different prompt, different model, or different parameter
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | |---|---|---|---| | AI Observability only | AI Evals | They can see model metrics but don't know if the output is actually good | "You can see your model's latency and cost. But do you know if the quality held up after your last prompt change?" | | LLM Obs + AI Evals | Product Analytics | They know model performance and quality. They don't know how users interact with the output. | "Your model is fast and the quality is high. But are users actually accepting the suggestions and converting?" | | LLM Obs + Product Analytics | Experiments | They see model metrics and user behavior. They want to improve. | "You can see GPT-4o costs more but users seem to prefer it. Want to run a proper A/B test to quantify the difference?" | | AI feature releasing changes | Release Engineering (Feature Flags) | They're changing prompts/models and want controlled rollout | "When you change your prompt, do you ship to everyone at once? Feature flags let you roll out to 5% first and measure before going wide." | | AI features in PostHog | Product Intelligence (for the product team) | AI team is in PostHog. The broader product team should be too. | "Your AI team uses PostHog for model metrics. Has the product team seen what they can do with funnels and retention for non-AI features?" | | Error Tracking for AI errors | Observability (full stack) | They're catching AI errors but not traditional application errors | "You're tracking model failures. Are you also catching the non-AI exceptions? Error Tracking works for your entire stack." |
Competitive battlecard:To be added: Langfuse / Helicone competitive positioning
Appendix: Company archetype considerations
| Archetype + Stage | Framing | Key Products | Buyer | |---|---|---|---| | AI Native — Early | "You need to understand your model costs, catch quality regressions, and see how users interact with your AI features, all without hiring a data team or buying 4 tools." Speed and simplicity. One platform. | AI Observability, AI Evals, Product Analytics, PostHog AI | Founder, AI engineer, founding PM | | AI Native — Scaled | "You're scaling AI features across your product. You need cost attribution by team/feature, automated quality evaluation, prompt/model experimentation, and the ability to connect model performance to business outcomes." | AI Observability, AI Evals, Product Analytics, Experiments, Error Tracking, Session Replay | Head of AI/ML, AI PM, VP Eng | | Cloud Native — Any (building AI features) | "You're adding AI features to an existing product. PostHog already tracks your users. Now connect model performance to user behavior so you can optimize the AI experience alongside everything else." The pitch here is extending their existing PostHog usage, not adopting a new tool. | AI Observability, AI Evals (added to existing PostHog stack) | Engineering team building the AI feature, PM who owns the AI feature |
"When a customer tells us something is broken, we see the whole story in one place, fix it, and ship the fix, without bouncing between multiple tools or wasting engineering time trying to reproduce it."
Give support one inbox for every customer conversation, with the sender's session, events, and errors already attached
Build a repeatable debugging workflow where support, product, and engineering share the same context
Give support teams the ability to see what actually happened, not just what the user reported
Connect technical debugging (errors, logs) to user behavior (replay, analytics) and satisfaction signals (NPS, CSAT)
Trace AI-powered workflows end to end when things go wrong
Turn recurring tickets into shipped fixes instead of a growing backlog
Most companies don't have a customer experience system. They have tickets in one place, errors in another, logs somewhere else, analytics owned by product, and engineers manually trying to reproduce bugs. The goal of this use case is to collapse that into one workflow, where the conversation, the evidence, and the fix live in the same platform.
Support is what makes this a system rather than a collection of tools. It's our customer support product — a chat widget, a shared inbox, and email, Slack, and GitHub channels — and because PostHog already captured what happened in the product, each ticket arrives with the sender's session replay, recent events, and exceptions attached.
You can sell this use case without moving their helpdesk. Plenty of good-fit accounts have a helpdesk they aren't replacing this quarter, and the use case still works: they keep tickets in Zendesk or Intercom, and PostHog becomes the context and debugging layer their agents open alongside it. Their helpdesk is also already a self-driving signal source, so recurring tickets can become PRs without moving the inbox at all. Lead with Support where the helpdesk is in play, and lead with Session Replay where it isn't.
What PostHog products are relevant?
Support (core) — One inbox for every customer conversation, whether it arrives from the in-app widget, email, Slack, or GitHub issues. Each ticket carries the sender's session replay, recent events, exceptions, and previous tickets. Statuses, priorities, assignment, tags, private notes, and saved views. The core — widget, inbox, all channels, workflow automation, and imports — is free with no per-seat charge.
Session Replay — See exactly what the user did, not what they think they did. Capture console logs and network calls alongside the visual recording. Widget tickets attach the customer's session automatically, so replay is one click from the conversation.
Error Tracking — Capture frontend and backend exceptions tied to users and releases. Exceptions from the customer's session surface directly on the ticket, and you can see whether other users hit the same issue.
Product Analytics — Understand what a user was trying to do before something broke. Identify patterns in drop-offs, error frequency, and issue clustering across users or accounts. Support emits $conversation_ticket_created and related events, so ticket volume is queryable next to product behavior.
Group Analytics + Person Profiles — Give support and CS a clean, holistic view of a user or account. Tickets link by distinct ID, so a ticket, a person, and an organization are the same object across products.
Workflows — Rules the customer controls, with no autonomous AI involved: set SLAs by channel or priority, auto-assign by customer email domain, auto-tag, reopen on customer reply, escalate. This is how a growing support team keeps the inbox sane.
Logs — Inspect structured backend logs connected to the same user session. When replay and error tracking show what happened on the frontend, logs show what happened on the server, and a log line links straight back to the replay it came from.
AI Observability — See prompts, outputs, latency, and token usage for AI-powered workflows. When an AI feature misbehaves, trace it back to the specific generation.
Surveys — Capture frustration signals (NPS, CSAT) and tie them directly to broken flows. When someone leaves a low score, you can click through to their session and see what went wrong.
Experiments — Validate that fixes actually improved the experience. After resolving a class of issues, measure whether user satisfaction and completion rates improved.
Replay Vision — The support-scale version of session replay. Instead of a human watching recordings one at a time, a scanner reads all of them and tags what happened: task completed, abandoned, blocked by an error. For a support team, that turns "we think a few customers hit this" into a number. Findings land as queryable events.
self-driving — Support conversations, error tracking, session replay, and logs are all signal sources, and external helpdesks (Zendesk, Front, Intercom-likes, Gorgias, Plain) can feed the same inbox. A recurring ticket theme becomes an investigated report with a pull request, so the fix happens instead of the ticket being closed with a workaround.
Adoption path and expansion path
Entry point
Usually Support or Session Replay. Common entry scenarios:
"We pay per seat for a helpdesk and our agents still can't see anything": They have a helpdesk but no product context, so every technical ticket becomes an engineering escalation. Support is the direct answer, and the consolidation math is easy.
"We can't reproduce bugs": Support needs to see what happened instead of relying on screenshots and user descriptions. Session Replay is the direct answer, whether or not tickets move.
"We don't have a support tool yet": Early-stage teams running support out of a shared Gmail inbox or a Slack channel. Support's widget plus the email and Slack channels replaces the mess, for free.
"Something is breaking but we don't know why": Product notices drop-offs or support volume spikes and needs visibility into what's causing them. Product Analytics surfaces the pattern, Session Replay provides the detail.
Support → Session Replay: The ticket tells them what the customer said. Replay shows what actually happened. This is the highest-value connection in the use case, and it's the reason Support is worth switching to.
Session Replay → Error Tracking: Seeing something break visually isn't enough. They want structured, queryable errors tied to users and releases, surfaced on the ticket. Error Tracking makes debugging systematic instead of ad hoc.
Error Tracking → Logs / AI Observability: Now they want to see what happened server-side or inside AI workflows. Logs provide backend context. AI Observability traces AI-specific issues (hallucinations, prompt regressions, latency spikes).
Logs / AI Observability → Surveys: After stabilizing debugging, they want to detect frustration from users who never file a ticket, and measure whether reliability improvements are being felt. Surveys close the feedback loop.
Surveys → self-driving: They're resolving tickets fast but seeing the same issues recur. Recurring conversations become investigated reports with pull requests, so the fix ships instead of the ticket being closed with a workaround.
This expansion happens naturally because each step removes a layer of uncertainty, then removes a layer of work.
Alternate expansion paths
The helpdesk stays where it is (the complement motion). They aren't replacing Zendesk, Intercom, or Front this year. Sell the context layer instead: Session Replay, Error Tracking, Group Analytics, and Person Profiles, with agents pasting replay links into their existing tickets, plus their helpdesk wired up as a self-driving signal source. Land it, prove the resolution-time win, and revisit Support when their helpdesk contract comes up. Note that the Zendesk import is a one-time historical backfill in open beta, not live two-way sync — don't promise a hybrid steady state for the Support inbox itself.
Starting from Session Replay as a replacement for another session recording tool. They adopt Session Replay to replace Hotjar, FullStory, or LogRocket. Expand by introducing autocapture (Product Analytics), Error Tracking for structured bug data, Group Analytics for account-level views, and then Support once support is already living in PostHog day to day.
Starting from GitHub issues. Dev-tool and infra companies where "support" is really an issue tracker. The GitHub channel turns issues into tickets with two-way comment sync, which gets Support adopted without changing anything for their users.
Business impact of solving the problem
Engineering time savings. If bug reproduction drops from 2 hours to 30-60 minutes, teams get fewer context switches, fewer escalations, and more roadmap velocity. Even modest improvements here can justify the cost of the PostHog contract.
Escalation reduction. When support can view replay, check errors, and inspect logs from inside the ticket, they resolve more issues without pulling in engineering. That means the roadmap doesn't stall and customer response times improve.
Helpdesk cost consolidation. Per-seat helpdesk pricing is one of the easier line items to attack. Support's core is free with no per-seat charge, so a growing support team stops paying more every time it hires. Combined with replacing a separate replay tool and a separate error tracker, this is often the clearest hard-dollar case in any use case we sell.
Fixes actually ship. The usual failure mode is the same ticket coming back because nobody prioritized the underlying bug. Recurring conversations become investigated reports with PRs, which converts support volume into product improvement.
Revenue protection. When enterprise customers report issues, speed and clarity matter. Being able to say "here's exactly what happened and here's the fix" builds trust. Slow, unclear debugging erodes it.
AI risk mitigation. For AI-powered products, AI Observability catches the things that would otherwise go unnoticed: hallucinations that are hard to trace, prompt regressions, and latency spikes. Without it, product credibility degrades quietly.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | | --- | --- | --- | --- | | Support Leader | Head of Support, Support Ops | Faster resolution, fewer escalations, agent tooling and seat costs | MTTR, first-response time, escalation rate, cost per seat | | Engineering Lead | EM, Staff Eng | Reproducible bugs, fewer interruptions | Debugging time, context switches | | Product Manager | PM, Product Lead | Understanding friction, user-reported issues | Drop-off rates, issue frequency | | AI Lead | Head of AI, Applied AI Eng | Model reliability, output quality | Output quality, latency, trace coverage | | CS Leader | VP CS, Head of CS | Customer trust, proactive issue resolution | NPS trends tied to product issues | | Founder / CTO (early stage) | Founder, CTO | Handling support without hiring for it, one platform | Time spent on support, tool count, cost |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | | --- | --- | --- | | Users with a support title | User list in Vitally | They're already bringing support folks into PostHog. CX workflow is emerging organically. | | High session replay spend / volume | Product spend breakdown, usage metrics | They're investing heavily in replay. This use case helps them get more value from that spend by connecting replay to errors, logs, and surveys. | | High support ticket volume | vitally.custom.supportTickets | They're dealing with a lot of customer issues. PostHog can help them debug faster, and the volume makes self-driving relevant. | | Known helpdesk in their stack (Zendesk, Intercom, Front) | Account notes, tech stack fields, discovery notes | Direct Support opportunity. Find out when the contract renews and what they pay per seat. | | Multiple user roles in PostHog (eng + support + product) | User list, admin emails | Cross-functional usage signals that CX workflows are already forming. |
PostHog usage signals
| Signal | How to Check | What It Means | | --- | --- | --- | | Support tickets being created | $conversation_ticket_created volume | They've adopted Support. Check whether replay and error tracking are enabled — that's where the value actually lands. | | Support enabled but no replay attached to tickets | Support usage vs replay config | They're using Support as a plain inbox and getting a fraction of the value. Highest-leverage conversation in this use case. | | Widget loaded but few tickets | $conversations_widget_loaded vs $conversation_ticket_created | The widget is installed but hard to find, or identification isn't configured. Worth a config review. | | Session Replay filtered by error events | Replay usage patterns | They're connecting replay to debugging. The CX workflow is clicking. | | Person profile lookups increasing | Product Analytics usage | Support or CS is investigating individual users. Group Analytics could formalize this. | | Error Tracking adoption alongside replay | Product spend data | They're building the debugging stack. Support, logs, and surveys are natural next steps. | | Console log / network tab usage in replays | Replay engagement metrics | They're using replay for technical debugging, not just UX review. Strong CX signal. |
Health score implications
Event volume: Should stay relatively similar (this use case doesn't fundamentally change event instrumentation)
User engagement: More users spending more time in PostHog (support, CS, and product teams joining engineering). Support is a daily-active surface for agents, which makes it one of the stickiest things we can land.
Product count: Should drive adoption of Support, Error Tracking, Group Analytics, Logs, Surveys, and more
Command of the Message
Discovery questions
Where do customer conversations land today, and what does that tool cost you per seat?
How do you currently investigate a reported issue? Walk me through the workflow.
When a ticket comes in, what does your agent already know about that customer, and what do they have to go ask for?
How long does it take to reproduce a bug reported by a customer?
How many tools do you open to debug one ticket?
Can support see backend errors or do they escalate everything to engineering?
What percentage of your tickets are the same handful of issues coming back?
Can you trace an AI output back to its prompt and context?
When someone leaves a low NPS score, can you see what went wrong in their session?
How do you confirm that a fix actually worked for the users who were affected?
Negative consequences (of not solving this)
Paying per seat for a helpdesk that can't tell agents anything about what the customer was doing
Engineering time wasted on reproduction instead of shipping
Constant escalations and interruptions from support to engineering
The same bugs generating tickets month after month because nobody closed the loop back to code
Enterprise deals slowed or lost due to reliability concerns and slow issue resolution
AI features degrading silently with no visibility into output quality
Customer frustration that shows up only at churn, not when it's actionable
Desired state
Every conversation lands in one inbox, with the customer's replay, events, and errors already attached
Support shares one link (replay + errors + logs) and engineering has full context in seconds
Engineers see replay + errors + logs without switching tools or asking "can you try that again?"
Support resolves technical tickets without escalating, because the evidence is already in the ticket
SLAs, routing, and tagging are handled by rules the team controls, not by manual triage
AI output is traceable end to end: prompt, context, output, user reaction
Recurring issues turn into reviewed pull requests instead of a backlog nobody grooms
Fixes are validated against real user behavior, not just "it works on my machine"
Frustration signals (low NPS, rage clicks) are visible immediately and tied to specific sessions
Debugging becomes fast, predictable, and systematized
Positive outcomes
30-70% reduction in debugging time (reproduction to resolution)
Fewer escalations from support to engineering
Helpdesk seat costs removed from the stack
More roadmap velocity (engineering spends time building, not debugging)
Recurring issues actually get fixed, so ticket volume trends down
Higher customer trust through faster, more transparent issue resolution
Clear signal when users are frustrated, tied to exactly what went wrong
Success metrics
Customer-facing:
CSAT/NPS improvement tied to faster issue resolution
Mean time to resolution (MTTR) and first-response time decrease
Reduction in support-to-engineering escalation rate
Reduction in repeat tickets for the same root cause
Helpdesk seat spend eliminated
TAM-facing:
More active users in PostHog (support, CS, product teams joining engineering)
Ticket volume in Support growing, with replay and error context attached
Session Replay usage increasing as debugging workflows mature
Competitive positioning
Our positioning
The conversation and the evidence in one place. Every other helpdesk is a text box with a CRM attached. Support ships with the customer's session replay, events, and exceptions on the ticket, because the same platform captured them. No integration to configure, no sampling gaps, no "can you send a screenshot?"
Unified visibility stack. Tickets, behavior, replay, errors, logs, AI observability, and surveys tied to the same user. Click from an NPS score to a session replay to an error to a log line to the conversation. No other platform connects all of these.
The loop closes in code. Recurring conversations become investigated reports with pull requests the team reviews and merges. Helpdesks generate tickets; we generate fixes.
Developer-first tooling. Built for teams that want control, not black-box dashboards. HogQL, API access, a JS API for building a fully custom widget, and a transparent data model.
Consolidation play, with real dollars. Replace a helpdesk + Hotjar + Sentry + separate logging + survey tool. Support's core is free with no per-seat charge, so the savings grow as their support team grows.
Where we are strongest: We win when teams want the conversation and the technical context in one place, when engineering and product work closely with support, when their helpdesk is priced per seat and their team is growing, when AI is part of the product, and when speed and simplicity matter more than enterprise ceremony.
Where we are weaker: We're not the right fit when they need a mature enterprise CX suite (advanced routing, omnichannel voice, a knowledge base and self-serve help center, CSAT surveying built into the ticket flow), when mature distributed tracing, profiling, or infrastructure monitoring is required, when enterprise ITSM workflows (ServiceNow, Jira Service Management) dominate the support stack, or when security policies prohibit session replay. In those cases, sell the complement motion: keep their helpdesk, add PostHog as the context layer.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | | --- | --- | --- | --- | | Zendesk | Enterprise helpdesk: ticketing, routing, help center, CSAT, voice | Session replay, errors, logs, and analytics on every ticket; free core with no per-seat pricing; recurring tickets become PRs | Mature enterprise CX suite; help center and knowledge base; advanced routing and omnichannel; huge integration ecosystem | | Intercom | Chat-first support with AI agent (Fin) and product tours | Full product context on tickets; developer-first; no per-seat or per-resolution pricing on the core | Mature AI resolution agent; polished messenger and campaign tooling; established help center | | Front | Shared inbox for email-heavy support teams | Product context, replay, errors, and analytics in the same platform; free core | Excellent email collaboration UX; deep email workflow features | | FullStory | Session replay + digital experience analytics | Error tracking, logs, AI observability, experiments all in one platform; developer-first; better pricing | More mature DXP features; enterprise CX tooling; dedicated support workflow integrations | | LogRocket | Session replay + error tracking + performance monitoring | Broader product suite (analytics, flags, experiments, surveys); AI observability; consolidation story | Purpose-built for debugging workflows; tighter Jira/Zendesk integrations out of the box | | Hotjar | Session replay + heatmaps + surveys | Full analytics platform; error tracking; feature flags; engineering-grade tooling; we ship heatmaps too | Simpler UX for non-technical users; lower barrier to entry for marketing/UX teams | | Sentry | Error tracking + performance monitoring + session replay | Deeper product analytics; session replay tied to behavior data; AI observability; surveys | More mature error tracking; broader language/framework support; larger install base | | Datadog | Full observability: APM, logs, metrics, errors, RUM | Product analytics integration; session replay depth; significantly cheaper | Complete observability stack (APM, traces, metrics); enterprise-grade; massive ecosystem |
Where PostHog stands: Our strongest position is against product-led companies already using PostHog for analytics or feature flags who are paying separately for a helpdesk and a replay/debugging tool. Consolidating removes two line items, and Support's free core removes the usual "another line item" objection. We're weaker against teams who bought Zendesk or Intercom for the parts we don't have yet — help center, advanced omnichannel routing, a mature AI resolution agent — and against teams with deeply embedded ITSM workflows (ServiceNow, PagerDuty integrations) or teams that need enterprise-grade distributed tracing. Our sweet spot is companies where engineering, product, and support are closely aligned and want one platform for the full loop from conversation to fix.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | | --- | --- | --- | | No help center or knowledge base | Teams relying on self-serve deflection can't move that part of their stack | Support handles the conversation, not the docs site. They keep their existing help center, or host docs themselves. Be clear this isn't on the near-term plan. | | No live two-way sync with Zendesk/Intercom | Can't run a hybrid steady state with tickets in both tools | The Zendesk import is a one-time historical backfill and is in open beta. Position the move as a switchover, not coexistence. For accounts that won't switch, sell the context layer and wire their helpdesk in as a self-driving signal source. | | AI reply agent isn't available yet | Teams comparing against Intercom's Fin won't find a like-for-like answer | It's coming and will be opt-in and separately billed, so nobody gets surprised on their bill. In the meantime, position Workflows (rules they control) plus self-driving (recurring issues become PRs) — a different answer to ticket volume. | | Ticket routing is manual, plus Workflows | No advanced skills-based or omnichannel routing engine | Manual assignment to a user or role, with Workflows for rule-based auto-assignment (for example by customer email domain), tagging, SLAs, and escalation. Enough for most teams under a few dozen agents; not a Zendesk routing replacement. | | SLAs are derived state, not a status | Teams expecting formal SLA policy management will find it lighter | SLAs are set via Workflows and reported as on track / at risk / breached. Set expectations, and check whether they need contractual SLA reporting or just want to avoid dropping tickets. | | No CSAT built into the ticket flow | Can't auto-send a satisfaction survey on resolution | Use Surveys for CSAT/NPS and tie responses back to sessions. It isn't yet wired into ticket resolution, so it's a parallel motion rather than one flow. | | Log retention is 14 days by default | Teams with compliance-driven long-tail retention needs will ask | Logs is generally available and billed per GB, with custom retention billed per month ($0.05/GB per month retained), set per service or per source. For archival beyond that, batch export to their own storage. | | Session replay privacy controls require configuration | Sensitive data in replays may block adoption for regulated industries | PostHog has extensive privacy controls including masking, blocking, and network payload filtering. Requires upfront configuration. | | Distributed tracing and metrics are alpha | Can't fully replace backend performance monitoring for complex microservice architectures | Be honest: tracing and metrics are alpha and free during alpha, with no service map and no profiling. Position PostHog as the user-facing debugging layer; heavy backend monitoring stays in their existing tool for now. See the Observability playbook for the full gap list. | | Mobile replay limitations | Mobile session replay is newer and less mature than web | Check mobile replay docs for current platform support. Set expectations on feature parity with web replay. |
Exceptions / edge cases:
Healthcare/regulated with strict PHI requirements: Session replay may require significant masking configuration or may not be feasible. Recommend focusing on Support + Error Tracking + Logs + Analytics without replay, or ensure their compliance team reviews PostHog's privacy controls and HIPAA BAA (available with Boost package).
Large enterprise with ServiceNow-centric workflows: If their entire support operation routes through ServiceNow with complex escalation rules, PostHog is a complement (providing the debugging context), not a replacement for their ITSM platform.
High-volume consumer support with omnichannel requirements: If they need voice, SMS, and a large agent pool with skills-based routing, Support isn't there yet. Sell the context layer and keep the door open.
Getting a customer started
What does an evaluation look like?
Scope: Turn on the Support widget on their primary application and connect one more channel (usually email). Enable Session Replay and Error Tracking so tickets arrive with context. Set up Person Profiles so support can look up individual users. Optionally run the Zendesk import to bring history across.
Timeline: Under a day to have the widget live and tickets flowing. 1-2 days to start capturing replays and errors. 1 week to have enough data for support to work real tickets end to end in PostHog.
Success criteria: When a ticket arrives, can the agent see the customer's session, recent events, and errors without leaving the ticket? Can they resolve a technical issue without escalating? Can engineering pick up an escalated ticket with full context? Is first-response time at least as good as their old tool?
PostHog investment: Support's core (widget, inbox, all channels, workflow automation, imports) is free with no per-seat charge. Session Replay free tier covers 5K recordings/month. Error Tracking free tier covers 100K exceptions/month. Product Analytics free tier covers 1M events/month.
Key requirement: They need the PostHog SDK integrated with user identification so tickets, replays, and errors are tied to specific users. If they're already using PostHog, this may just require enabling Support, replay, and error tracking. For logged-in users, walk them through Support's identity verification so tickets persist across devices.
Onboarding checklist
[ ] Enable the Support widget on the primary app, with identity verification configured for logged-in users
[ ] Enable Session Replay with user identification so tickets attach the customer's session
[ ] Enable Error Tracking in the SDK configuration so exceptions surface on tickets
[ ] Set up Person Profiles so support can search for individual users
[ ] Configure privacy controls for any sensitive fields (forms, PII)
[ ] Set up Workflows for SLAs, auto-assignment, tagging, and reopen-on-reply
[ ] Agree on ticket statuses, priorities, and saved views with the support team
[ ] Run the Zendesk import if they're migrating history (org admin required)
[ ] Walk support through opening a ticket and using replay, events, and exceptions (training session)
[ ] Build a "Customer Health" dashboard: ticket volume by account, error trends, replay volume, NPS scores
[ ] Set up alerts for error spikes or new error types
[ ] Enable Logs for backend context alongside replays, and show the log-line-to-replay link
[ ] If applicable, connect Surveys (NPS/CSAT) and tie responses to session data
[ ] Once tickets are flowing, enable Support as a self-driving signal source and review the first reports together
Objection handling
| Objection | Response | | --- | --- | | "We already have Zendesk/Intercom" | Two questions: what do you pay per seat, and when a ticket comes in, what does your agent already know? With PostHog the ticket arrives with the customer's session replay, their recent events, and any errors they hit, because we captured all of it. The core is free with no per-seat charge. And if you're not ready to switch, keep your helpdesk — we can wire it in as a signal source and still turn your recurring tickets into fixes. | | "Is your helpdesk actually mature enough?" | Be honest. It handles the widget, email, Slack, and GitHub channels, statuses, priorities, assignment, tags, private notes, saved views, and rule-based automation. It doesn't have a help center, omnichannel voice, or an AI reply agent yet. If those are must-haves, we're a complement today rather than a replacement, and we'd rather tell you that now. | | "We already have a session replay tool (Hotjar/FullStory/LogRocket)" | PostHog connects replay to your actual customer conversations, plus errors, logs, analytics, and surveys in one platform. With separate tools, your support team still has to switch between 3-4 tabs to debug one issue. Consolidating also saves on vendor costs. | | "Migrating our support tool is too risky" | You don't have to cut over on day one. Start with the widget on one app or one channel while your existing helpdesk keeps running, and see whether your agents resolve those tickets faster. We can import your Zendesk history when you're ready to switch. | | "Our support team isn't technical enough for PostHog" | The inbox is a normal support inbox and the replay viewer is visual. Support doesn't need to write queries. They open the ticket, watch the session, and read the exceptions panel. We can do a training session to get them comfortable. | | "What about AI answering tickets for us?" | An opt-in AI reply agent is coming, and only teams who turn it on get billed for it. But the more interesting thing we do today is the opposite direction: recurring issues get investigated and come back as a pull request you review and merge. Deflecting a ticket is good; making it never happen again is better. | | "Session replay has privacy concerns" | PostHog has extensive privacy controls: input masking, DOM element blocking, network payload filtering, and more. We can configure these during onboarding. HIPAA BAA is available with the Boost package. | | "We're not sure this justifies adding another tool" | This is the opposite of adding a tool. If you're already on PostHog for analytics or flags, Support is enabling more of the platform you pay for, and it can remove your helpdesk and replay tool from the stack. If you're not on PostHog yet, the free tiers let you evaluate without financial risk. |
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | | --- | --- | --- | --- | | Session Replay + Error Tracking (support team in PostHog daily) | Support | They're already debugging in PostHog, but the conversation lives in a per-seat helpdesk that knows nothing about the product. | "Your team is already in PostHog to figure out what happened. What if the ticket itself lived here, with the replay and the errors already attached?" | | Support (inbox only) | Session Replay + Error Tracking | They adopted the inbox but tickets arrive without context, which is most of the value. | "Right now your tickets are just text. Turn on replay and error tracking and every ticket shows you exactly what the customer hit." | | Support with growing ticket volume | Workflows | Manual triage is starting to hurt: tickets sit unassigned, SLAs slip. | "How much time does your team spend deciding who picks up what? You can set rules for assignment, SLAs, and tagging and stop triaging by hand." | | Session Replay only | Error Tracking | They're watching replays to find bugs. Structured error data makes this systematic instead of manual. | "You're watching sessions to find bugs. What if errors were automatically captured and grouped so you could see which ones affect the most users?" | | Session Replay + Error Tracking | Logs | They have frontend context but need backend visibility when debugging server-side issues. | "You can see the user's session and the error. But what was happening on the server at the same time?" | | Session Replay + Error Tracking | Product Intelligence (for the product team) | Support and engineering are in PostHog for debugging. The product team would benefit from the same analytics for feature development. | "Your support team is using PostHog to debug issues. Has your product team seen what they can do with funnels and retention in the same platform?" | | Replay + Errors + Analytics | Surveys (NPS/CSAT) | They're debugging reactively. Surveys let them detect frustration proactively and tie it to specific sessions. | "You're great at debugging reported issues. But how do you find the frustrated users who never file a ticket?" | | Replay + Errors (debugging AI features) | AI Observability | Traditional debugging misses AI-specific issues: prompt quality, hallucinations, latency. | "You're catching errors in your AI features. But are you seeing when the model gives a bad answer that isn't technically an error?" | | High ticket volume, support watching replays by hand | Replay Vision | Support can only watch a sample; a scanner reads every session | "How many tickets say 'it didn't work' with no detail? A scanner can read those sessions and tell you what actually happened in each one." | | Zendesk/Front/Jira alongside PostHog | self-driving | Their helpdesk is already a supported signal source; recurring tickets can become PRs | "Your recurring tickets are a to-do list nobody has time for. What if each one arrived investigated, with a fix attached?" | | Support with the same issues recurring | self-driving | Tickets are resolved fast but the underlying bugs never make the roadmap | "How many of your tickets are the same handful of problems? Those can come back investigated, with a PR you review — so they stop coming back." | | Replay + Errors (engineering in PostHog) | Release Engineering (Feature Flags) | Engineering is in PostHog for debugging. Feature flags for safe releases is a natural add. | "You're tracking bugs after releases. What if you could gate features behind flags and roll back without a deploy?" | | Group Analytics + Person Profiles | Data Infrastructure (Data Warehouse) | They want to combine PostHog user/account data with CRM or billing data for a complete customer view. | "You're looking at users in PostHog. What if you could see their Stripe revenue and HubSpot status alongside their product behavior?" |
How we do support ourselves:Support team — we're migrating off Zendesk onto this product, so our own experience is the reference story
Competitive battlecard:To be added: Zendesk / Intercom / Front / FullStory / LogRocket / Hotjar competitive positioning
Appendix: Company archetype considerations
| Archetype + Stage | Framing | Key Products | Buyer | | --- | --- | --- | --- | | AI Native — Early | "Your AI features will break in ways that aren't exceptions. Drop in the Support widget and every ticket arrives with the session replay and the LLM trace that caused it. All in one place, free tier included." | Support, Session Replay, Error Tracking, AI Observability | CTO, founding engineer | | AI Native — Scaled | "Support escalates AI issues to engineering because they can't see what the model did. PostHog puts the conversation, the replay, and the LLM trace on one screen, then turns the ones that keep recurring into PRs." Bridge to AI/LLM Observability and Product Intelligence. | Support, Session Replay, Error Tracking, AI Observability, Logs, Surveys | VP Eng, Head of Support, AI Lead | | Cloud Native — Early | "Stop asking users to send screenshots and stop paying per seat for a helpdesk. Support gives you one inbox, and each ticket comes with the session and the error already attached." | Support, Session Replay, Error Tracking, Person Profiles | CTO, Head of Support, founding engineer | | Cloud Native — Scaled | "You're paying per seat for Zendesk and your agents still escalate everything because the ticket tells them nothing. PostHog puts replay, errors, and backend logs on the ticket, automates triage with Workflows, and turns recurring issues into merged fixes." Consolidation pitch: replace helpdesk + FullStory/LogRocket + Sentry with one platform. | Support, Session Replay, Error Tracking, Logs, Workflows, Group Analytics, Surveys | VP Eng, Head of Support, VP CS | | Cloud Native — Enterprise | "Multiple teams, multiple products, and context spread across 5 tools. PostHog gives support, engineering, and product a shared view: conversation, replay, errors, logs, and satisfaction data tied to the same user and account. Fewer escalations, faster resolution, better customer trust." Expect a complement motion here if a mature CX suite or ITSM platform is entrenched — lead with the context layer and revisit Support later. | Full CX stack + Enterprise package (RBAC, SSO, dedicated support) | VP Eng, VP CS, Director of Support, CTO | | Dev tool / infra — any stage | "Your users report problems as GitHub issues. Connect the repo and those become tickets with two-way comment sync, so your team works one inbox without changing anything for your users." | Support (GitHub channel), Error Tracking, Session Replay | CTO, DevRel lead, Head of Support |
"Help me unify product data with business data and get it where it needs to go."
Bring external data into PostHog from Stripe, HubSpot, Salesforce, databases, and other sources
Combine PostHog event data with revenue data, CRM data, or other business data for unified analysis
Query across product events and business data without building and maintaining custom ETL pipelines
Export PostHog data to existing warehouses (Snowflake, BigQuery, Redshift) so it's part of the company's data stack
Feed enriched data to downstream tools: BI platforms, ad platforms, CRMs, marketing tools
Naming note: the current positioning for this whole area is the context warehouse — the managed warehouse plus the full context-ingestion pipeline (modelling, pipelines, batch exports). That framing is what ties this use case to self-driving: the warehouse isn't just a SQL bucket, it's the fuel for agents. Don't say "PostHog Data Stack" — that's not a term we use externally. See brand foundations.
This is the "stickiness" use case. Once PostHog is part of a company's data infrastructure, receiving data from Stripe, HubSpot, and databases AND feeding data out to their BI layer, it becomes very hard to rip out. This also makes their product data more valuable as it is enriched with additional business context. Data infrastructure customers also tend to have the highest retention rates.
However, this is also the hardest use case to sell into. Data teams are skeptical of analytics tools playing in the data engineering space. Product maturity matters a lot here.
What PostHog products are relevant?
Data Warehouse (core) — Bring external data into PostHog. Connect Stripe, HubSpot, Salesforce, Postgres, MySQL, Snowflake, BigQuery, and many more sources. Query across PostHog events and external data using HogQL. Build unified dashboards that combine product behavior with revenue, CRM, and business data.
Data Pipelines / Batch Exports (core) — Send PostHog data out to external destinations. Batch exports to S3, Snowflake, BigQuery, Postgres, Redshift, Databricks, Azure Blob. Realtime destinations to Slack, HubSpot, Salesforce, ad platforms, and more. Transformations to clean, enrich, or filter data before it lands.
Product Analytics — The query engine for unified data. Once external data is in the Data Warehouse, Product Analytics becomes the interface for querying across all of it. HogQL gives SQL access to everything. Dashboards combine product events with business metrics.
**Endpoints (beta)** — Turn any saved insight or SQL query into a stable, authenticated, cached HTTP endpoint. This is the answer to "we need this data inside our own product / internal tool / customer-facing dashboard" — previously a custom backend job. Optionally materialize for latency. (Positioning)
**Semantic layer (beta)** — Define metrics and dimensions once so every query, dashboard, and agent uses the same definition. The governance answer for data teams who've been burned by six versions of "active user."
self-driving — Scouts watch the data infrastructure itself: failing warehouse syncs, broken materialized views, data pipeline errors, ingestion warnings. Pipeline breakage is exactly the kind of unglamorous maintenance that sits in a data team's backlog for weeks. External sources also connect through the warehouse, so a data team that's wired up their sources has also wired up the inbox.
Adoption path and expansion path
Entry point
Usually Data Warehouse or Batch Exports. Two common patterns:
Data out (Batch Exports first): Data team wants to export PostHog event data to their existing warehouse (Snowflake, BigQuery, Redshift) so it can be queried alongside other business data in their BI tool. This is the "PostHog as a data source" entry point. They're not replacing their warehouse. They're adding PostHog data to it. Ideally, we want PostHog to be the hub of their data, but this is typically an indicator that they're beginning to think of their data holistically.
Data in (Data Warehouse first): Data team (or product/other team) wants to bring external data into PostHog to enrich product analytics. "Show me retention by Stripe plan" or "Which HubSpot leads are actually active in the product?" requires combining PostHog events with external data. This is the strongest entry point because it keeps teams inside PostHog for analysis.
Primary expansion path
Data Warehouse (bring external data IN) → + Product Analytics (query unified data) → + Batch Exports (send PostHog data OUT)
The logic of each step:
Data Warehouse → Product Analytics: They've connected external data (Stripe, HubSpot, databases). Now they use Product Analytics (and HogQL) as the query interface for unified data. Dashboards combine product events with revenue data, CRM data, and more. PostHog becomes the single analytics interface.
Product Analytics → Batch Exports: They're doing all their analysis in PostHog, but other teams or BI tools still need access to PostHog event data. Batch exports feed their warehouse so the rest of the org can benefit too.
Alternate expansion paths
Starting from Realtime Destinations: They want to push PostHog events to downstream tools in real-time. Conversion events to ad platforms (Meta, Google Ads). User activity to CRM (HubSpot, Salesforce). Alerts to Slack. This pulls in Data Pipelines and naturally leads to "if we can push data out, can we pull data in?" which is the Data Warehouse.
Starting from Product Analytics (HogQL power users): Advanced analytics users writing HogQL queries hit the ceiling of PostHog-only data. They want to join against their Stripe data, their CRM data, or their database. Data Warehouse is the answer.
Business impact of solving the problem
This is the highest-stickiness use case. When PostHog is both receiving data from Stripe/HubSpot/databases and feeding data out to Snowflake/BigQuery/BI tools, ripping it out means rebuilding multiple data pipelines. This creates deep infrastructure-level lock-in that goes beyond any single user or team.
Data infrastructure customers have the highest retention rates. Accounts with active batch exports and warehouse connections churn at significantly lower rates than analytics-only accounts. The integration depth creates switching costs that product satisfaction alone doesn't.
However, this is the hardest use case to sell into. Data teams are skeptical. They've built their stack around tools like Fivetran, dbt, Snowflake, and Looker. They see PostHog as an analytics tool, not a data infrastructure tool. Credibility with data engineers requires demonstrating real technical capability, not just talking about consolidation.
The "lightweight warehouse" pitch resonates with early-stage companies. Teams that don't yet have a Snowflake/BigQuery setup find PostHog's Data Warehouse attractive because it gives them warehouse capabilities (join external data, run SQL) without a separate warehouse vendor. For these teams, PostHog isn't replacing their warehouse. It is their warehouse.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | |---|---|---|---| | Data Engineer | Data Eng, Analytics Eng, Data Platform | Pipeline reliability, query performance, schema flexibility, not maintaining custom ETL | "Is the sync reliable? Can I run complex joins? What's the query latency on large datasets?" | | Data Team Lead | Head of Data, Director of Analytics, Data Lead | Tool consolidation, cost, team productivity, data governance | "Does this reduce our pipeline maintenance burden? What's the cost vs. Fivetran?" | | Product Ops / BizOps | Product Ops, RevOps, BizOps | Unified view of product and business data, self-serve dashboards | "Can I see product usage next to Stripe revenue and HubSpot pipeline without asking the data team?" | | Founder (early stage) | CTO, technical founder, first data hire | Not building a data warehouse yet. Wants unified analytics without a complex stack. | "Can I query my Stripe data alongside PostHog events without setting up Snowflake?" |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | |---|---|---| | Active batch exports | active_batch_exports in Vitally traits | They're already exporting data. The Data Warehouse (bringing data in) is the natural next step, and they're likely not thinking of PostHog being their data warehouse. | | Active external data schemas | active_external_data_schemas in Vitally traits | They've connected external data sources. They're using PostHog as a data platform, not just analytics. | | High rows synced (30 day) | rowsSyncedLast30DaysIfSendingData | Significant data movement. Data Infrastructure is an active use case. | | Customer mentions Fivetran, Snowflake, or "data warehouse" in notes | Vitally notes / conversations | Data team is involved. This use case may be relevant. | | HogQL usage is high | Usage metrics | Power users writing SQL. They're likely to want to query across external data too, or have more complex analytics needs/capabilities. |
PostHog usage signals
| Signal | How to Check | What It Means | |---|---|---| | Batch exports configured and running | Pipeline configuration | They're exporting data. Explore whether bringing data in (Data Warehouse) would add value. What are they doing with the PostHog data in the warehouse? | | External data sources connected (Stripe, HubSpot, etc.) | Data Warehouse source list | Active Data Infrastructure use case. Look for expansion: more sources, more query complexity. | | HogQL queries joining external data | Saved insights with warehouse tables | They're doing unified analysis. This is the power use case. Encourage more connections. | | High realtime destination volume | Pipeline metrics | They're pushing events to downstream tools. Explore whether they need more destinations or more complex transformations. They may also be solving in point solutions when they could simplify in PostHog. |
Command of the Message
Discovery questions
Where does your product data live today? How do you combine it with business data (revenue, CRM, etc.)?
Do you have a data warehouse (Snowflake, BigQuery, Redshift)? How does PostHog data get there?
When someone asks "what's our retention by Stripe plan?" or "which HubSpot leads are active in the product?", how long does it take to answer?
How many custom ETL pipelines are you maintaining? How much engineering time goes into keeping them running?
What tools do you use for data pipelines today? (Fivetran? Airbyte? Custom scripts?)
Do you push PostHog data to any downstream tools? (BI, CRM, ad platforms)
If you could query your Stripe/HubSpot/database data alongside PostHog events in one place, what questions would you ask first?
Negative consequences (of not solving this)
Product data and business data live in separate silos. Answering cross-domain questions requires custom ETL, manual exports or switching between multiple tools/dashboards
Just as bad as difficult to answer questions - teams give different answers to the same question
Data engineers spend time maintaining pipelines between PostHog and the warehouse instead of doing analysis
"Which cohort of users drives the most revenue?" requires stitching data from PostHog, Stripe, and the CRM, which takes days instead of minutes
PostHog events aren't in the warehouse, so BI dashboards that need product behavior data are stale or incomplete
Conversion events don't flow back to ad platforms, so marketing can't optimize campaigns against real product data
Desired state
External data automatically flows into PostHog for enriched product analytics
Product events, revenue data, CRM data, and database data queryable in one place
Anyone can build a dashboard that combines product behavior with business outcomes
No custom ETL pipelines to maintain between PostHog and the rest of the data stack
PostHog data automatically flows to the warehouse for BI and downstream analysis
Positive outcomes
Deeper product analytics: join against revenue, CRM, and business data for richer insights
Faster time-to-answer for cross-domain questions (retention by plan, revenue by feature, engagement by lead score)
Reduced engineering time maintaining data pipelines
External data available in PostHog for teams that prefer PostHog's analytics interface
Query across everything with HogQL. Join PostHog events with Stripe revenue data, HubSpot contacts, or your Postgres database in a single SQL query. No separate BI tool required for many use cases.
Built into the analytics platform. The Data Warehouse isn't a separate product. It's integrated with Product Analytics, dashboards, cohorts, and every other PostHog feature. External data becomes first-class data.
Lightweight warehouse for early-stage teams. Teams without Snowflake/BigQuery get warehouse capabilities as part of PostHog. No separate vendor, no separate setup.
Bidirectional data flow. Data Warehouse brings external data into PostHog. Batch Exports and Pipelines push PostHog data out. Two-way integration with the customer's data stack.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | |---|---|---|---| | Snowflake / BigQuery | Cloud data warehouse | We have analytics built on top; no BI tool needed for product questions; simpler for teams that just need PostHog + business data | Real data warehouse: unlimited scale, advanced SQL, mature ecosystem, governance | | Fivetran | Managed data pipelines (sources to warehouse) | We're the analytics platform AND the pipe; data stays in PostHog for analytics; simpler for early-stage teams | Far more source connectors; more mature data governance; enterprise-grade reliability | | Census / Hightouch | Reverse ETL (warehouse to business tools) | We push data from PostHog directly, no warehouse intermediate step needed; simpler architecture | More destination integrations; audience management features; built for marketing/ops teams | | Segment | CDP (collect events, route to destinations) | We're the analytics platform AND the pipe; no separate CDP needed | More destination integrations; more mature event collection; established in enterprise CDP workflows |
Where PostHog stands: We are not trying to replace Snowflake or BigQuery. For teams with a mature data stack (Fivetran + Snowflake + dbt + Looker), PostHog's Data Warehouse is a complement, not a replacement. Batch Exports feed PostHog data into their stack; Data Warehouse brings their data into PostHog for product-specific analysis. The full replacement pitch only works for early-stage teams that don't have a warehouse yet and want PostHog to serve double duty. Early stage teams may also have experience with the complexity of layering in data systems, so may be more open to centralizing tooling, and Batch Exports always allow teams to not feel vendor lock-in. Be calibrated about which accounts can realistically adopt this as infrastructure vs. a convenience feature.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | |---|---|---| | Data Warehouse query performance at very large scale | Teams with billions of rows in external sources may hit performance limits | PostHog's Data Warehouse is optimized for product analytics query patterns, not general-purpose warehousing. For very large datasets, batch exports to Snowflake/BigQuery may be more appropriate. | | Source connector coverage doesn't match Fivetran | Some niche data sources may not be supported | Check available sources. For unsupported sources, the API and S3/GCS import paths can bridge the gap. | | Data engineering teams may not trust PostHog as a warehouse | Credibility gap: "you're an analytics tool, not a data platform" | Don't oversell. Position as a complement to their existing stack (batch exports out, key sources in) rather than a full replacement. Demonstrate HogQL query capability with their actual data to build credibility. | | Batch export latency may not meet real-time requirements | Teams needing sub-minute data freshness in their warehouse | Batch exports are periodic (hourly default). For real-time needs, use Realtime Destinations instead. Set expectations on latency during evaluation. |
Getting a customer started
What does an evaluation look like?
Scope: Connect one external data source (usually Stripe or their primary database) to PostHog Data Warehouse. Set up one batch export to their warehouse if they have one. Build a dashboard that joins PostHog events with external data.
Timeline: 1 to 3 days to connect sources and exports. 1 week to build meaningful unified dashboards.
Success criteria: Can you query across PostHog events and external data in HogQL? Can you build a dashboard showing "retention by Stripe plan" or "engagement by CRM stage"? Is the batch export reliably delivering data to their warehouse?
Key requirement: They need API credentials for the external data sources they want to connect. For batch exports, they need write access to their warehouse.
Onboarding checklist
[ ] Connect primary external data source to Data Warehouse (usually Stripe or primary database)
[ ] Verify data is syncing correctly and queryable via HogQL
[ ] Build a unified query: join PostHog events with external data (e.g., "retention by Stripe plan")
[ ] Set up batch export to their warehouse (Snowflake, BigQuery, Redshift, S3)
[ ] Verify batch export is running reliably with expected data freshness
[ ] Configure at least one Realtime Destination if they need event data in downstream tools (Slack alerts, CRM sync, ad platform conversions)
[ ] Build a "Unified Analytics" dashboard combining product events with business data
[ ] Introduce the data team to HogQL if they're SQL-comfortable (HogQL docs)
[ ] Identify additional data sources to connect (CRM, other databases, ad platforms)
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | |---|---|---|---| | Batch Exports only | Data Warehouse (bring data in) | They're pushing PostHog data out. Bringing business data in would let them do unified analysis in PostHog directly. | "You're exporting PostHog data to Snowflake. What if you could bring your Stripe data into PostHog and skip the context-switch?" | | Data Pipelines to CRM | Growth & Marketing | They're pushing data to HubSpot/Salesforce. The growth team could use more of the marketing analytics stack. | "You're syncing data to your CRM. Has the marketing team seen Web Analytics and Marketing Analytics for attribution?" | | Data Warehouse + Product Analytics | Product Intelligence (for the product team) | They're doing unified data analysis. The product team should be using the full analytics suite. | "Your data team is doing advanced queries. Are your PMs using funnels, retention, and session replay for product decisions?" | | Data team in PostHog | Any use case for other teams | Data team is in PostHog and advocates for it. Expand to product, engineering, or growth. | "Your data team loves PostHog. Which other teams could benefit? Product? Engineering? Growth?" | | Warehouse + insights, hand-rolled internal APIs | Endpoints | They've built a backend service to serve saved queries to another app | "Who maintains the API that serves these numbers to your internal tool? Endpoints does that without the service." | | Warehouse sources connected | self-driving | Sources are already the hard part of setup, and failing syncs are a real recurring pain | "When a sync breaks, how long before someone notices? There's a scout that watches for exactly that and files it with the fix." |
| Archetype + Stage | Framing | Key Products | Buyer | |---|---|---|---| | AI Native — Early | "You don't need a data warehouse yet. PostHog connects to Stripe and your database, so you can query everything in one place without setting up Snowflake." Lightweight warehouse pitch. | Data Warehouse, Product Analytics (HogQL) | CTO, founding engineer, first data hire | | AI Native — Scaled | "You're scaling and your data team is building a proper stack. PostHog batch exports feed your warehouse, and Data Warehouse brings key business data in for product analytics." Complement, not replace. | Data Warehouse, Batch Exports, Pipelines | Data team lead, analytics engineer | | Cloud Native — Early | "Same as AI Native early. PostHog as the lightweight warehouse for teams that don't want a separate data stack yet." | Data Warehouse, Product Analytics (HogQL) | CTO, first data hire | | Cloud Native — Scaled | "Your data stack is mature. PostHog fits in as both a data source (batch exports to Snowflake) and an analytics destination (Data Warehouse pulls in Stripe/HubSpot). No custom ETL needed." | Batch Exports, Data Warehouse, Pipelines | Data engineering team, analytics engineering team | | Cloud Native — Enterprise | "Multiple teams, multiple data sources, complex pipeline requirements. PostHog integrates bidirectionally with your existing stack and gives product/growth teams self-serve analytics over unified data." Governance, reliability, and scale matter here. | Full Data Infrastructure stack + Enterprise package | Head of Data, Director of Analytics, Data Platform Lead |
Appendix: PostHog data maturity
| Stage | Primary Tool | Data Sources | Who Owns | PostHog Position | |---|---|---|---|---| | 1 | Point solutions (GA, prod DB) | Scattered | Nobody | Not yet adopted | | 2 | PostHog | Product events | Prod/Eng | Primary analytics | | 3 | PostHog + Data Pipelines | Product + Business | Cross-functional | Hub for analytics | | 4 | PostHog + Data Pipelines + Warehouse | Everything | Cross-functional | Source of truth | | 5 | PostHog + Batch Exports + External warehouse | Everything | Data Team | Source + destination |
"Help me understand what drives acquisition, conversion, and revenue, and automate actions based on user behavior."
Know which channels and campaigns actually drive signups and revenue, not just clicks
Build and optimize conversion funnels from first touch through activation and monetization
Attribute revenue back to marketing spend and understand true ROAS
Automate engagement based on user behavior: onboarding nudges, re-engagement, lifecycle campaigns
Get conversion and behavior data into ad platforms, CRMs, and marketing tools without building custom pipelines
Run experiments on landing pages, pricing, onboarding flows, and activation sequences
Collect on-site feedback (exit intent, NPS, CSAT) and tie it directly to user behavior
Let non-technical marketing users ask questions about their data without waiting for an analyst
Guidance: This is probably the most underserved use case in our current motion. We have the products – Web Analytics, Marketing Analytics, Workflows, Pipelines, Surveys – but we rarely lead with this story. Marketing teams are spending $10k+/month on Segment, Mixpanel, GA4, and various CDPs to do what PostHog can do in one place. Don't sell individual products here. Sell the consolidation of their marketing data stack.
What PostHog products are relevant?
Web Analytics (core) – Traffic, referrers, UTM tracking, page performance, bounce rates. The replacement for GA4 that doesn't require a PhD to configure. First-party data collection that actually works with ad blockers. (Dashboard overview)
Marketing Analyticsbeta – Ad campaign attribution, channel performance, ROAS tracking. Connect ad spend to actual product signups and revenue events. Multi-touch attribution across channels.
Product Analytics – Conversion funnels, retention curves, cohort analysis, activation metrics. The layer that connects "they visited the site" to "they became a paying customer." Lifecycle analysis to understand where users are in the journey.
Workflows – Automated engagement sequences triggered by user behavior. Lifecycle emails, re-engagement campaigns, onboarding drips, churn prevention. Act on what analytics reveals instead of just reporting on it. (Email drip campaign guide · Configure channels)
Data Pipelines – Push conversion events and user data to ad platforms (Google, Meta, LinkedIn), CRMs (HubSpot, Salesforce), and data warehouses. Close the loop on campaign optimization by feeding real conversion data back to where it's used. (Realtime destinations · Batch exports)
Surveys – On-site feedback, exit-intent surveys, NPS, CSAT, post-purchase surveys. Capture qualitative signal at key moments in the funnel and tie responses to user behavior data.
Experiments – A/B test landing pages, pricing pages, onboarding flows, checkout experiences, and activation sequences against real conversion and revenue metrics. This is a key stickiness driver: once a growth team is running experiments, they need engineering to implement the variants, which pulls engineering into PostHog and creates a cross-team dependency.
Feature Flags – The implementation layer for experiments. Growth/CRO defines the test; engineering implements it via feature flags. Also used for targeted rollouts to specific user segments, geo-targeting, and progressive delivery of growth initiatives. Feature Flags are the bridge product that connects the growth team's use case to the engineering team's workflow, and opens the door to the Release Engineering use case.
Heatmaps – Clickmaps, scrollmaps, and rageclick detection on any page. The CRO table stakes that marketing teams expect from Hotjar, included on every plan. Pair with Experiments to go from "nobody scrolls to the CTA" to a tested fix.
**Customer Analytics (beta, B2B mode requires Group Analytics add-on)** – Customer profiles, journeys, and usage metrics, with a B2B mode. Where Product Analytics answers "what did users do," this answers "how is this account doing" – the view a growth team at a B2B company actually needs for expansion and churn plays.
Web vitals – Core Web Vitals captured automatically. Page performance is an SEO and conversion input, and GA4's version of this is a separate tool.
PostHog AI – Natural language querying for non-technical marketing users. "Which campaign drove the most signups last month?" without needing HogQL or analyst support. (Example prompts)
self-driving – Web analytics, product analytics, and session replay all feed the self-driving loop, and there are scouts watching web analytics, web vitals, surveys, and customer analytics. For a growth team, the honest framing is conversion-path maintenance: broken funnels, dead links, regressed page performance. It will not write your positioning.
Adoption path and expansion path
Entry point
Usually Web Analytics, Product Analytics, or Experiments. Three common patterns:
Marketing-first: Marketing team wants to replace GA4 or understand channel attribution. They start with Web Analytics for traffic and referrer data, then quickly want to connect that to downstream conversion events (Product Analytics) and campaign spend (Marketing Analytics).
Growth-first: A growth engineer or product-led growth team is already using PostHog for product analytics – building funnels, tracking activation, measuring retention. They want to connect the top of funnel (how users found us) to the bottom (did they convert and retain). Web Analytics and Marketing Analytics extend their existing setup upstream.
CRO / Experimentation-first: A Growth PM or CRO specialist wants to run A/B tests on signup flows, pricing pages, or onboarding sequences. They come in through Experiments, which requires Feature Flags, and Feature Flags require engineering to implement. This is a natural multithreading play: the growth team defines the experiment, engineering implements the flag, and now both teams are in PostHog.
Web Analytics → Marketing Analytics: They can see traffic and referrers but want to connect that to actual ad spend and ROAS.
Marketing Analytics → Product Analytics: They know which channels bring users, now they need to know which channels bring users who convert and retain.
Product Analytics → Experiments + Feature Flags: They've identified drop-off points and want to test fixes. Experiments require Feature Flags, which require engineering to implement. This is the key multithreading moment: the growth team defines the hypothesis, engineering implements the flag, and both are now active in PostHog.
Experiments → Data Pipelines: They've validated what works, now they need to feed real conversion events back to ad platforms and push user data to their CRM.
Pipelines → Workflows: They've been reporting on drop-offs and now want to actually do something about them. Automated re-engagement when a user goes cold.
Workflows → Surveys: Engagement is automated, now they want to add a qualitative layer. "Why did you cancel?" exit surveys. Post-purchase NPS.
Alternate expansion paths
Starting from Product Analytics (growth engineering): A growth team already deep in PostHog funnels and experiments. They expand upstream into Web Analytics and Marketing Analytics for channel attribution, and downstream into Workflows for activation automation.
Starting from Surveys: A product or CX team is running NPS or CSAT surveys. They want to connect low scores to actual behavior (what happened right before someone gave a 3/10?), which pulls in Product Analytics and Session Replay. The growth team then sees the survey infrastructure and wants to use it for exit-intent and post-signup feedback.
Starting from Experiments (CRO / Growth PM entry – the engineering bridge): A CRO specialist or Growth PM wants to A/B test their signup flow. They come in through Experiments, which creates a Feature Flag under the hood. The flag needs to be implemented in code, so engineering gets pulled into PostHog. This is high-value for three reasons: (1) it makes the account sticky – once feature flags are in the codebase, they're not easy to rip out; (2) it creates a multithreading opportunity – you now have both the growth team and engineering as active users; and (3) it's a bridge to Release Engineering – once engineering is using flags for experiments, they often realize they can use the same infrastructure for progressive rollouts and kill switches.
Business impact of solving the problem
The buyer is different from other use cases. Growth and Marketing targets growth engineers, marketing leads, demand gen managers, CRO specialists, and GTM engineers. In most organizations, these are separate from the product analytics buyer (PM) and the engineering buyer (EM/platform). They often have their own budget and their own stack. Winning this buyer opens a parallel revenue stream within the same account.
Marketing stack consolidation cuts hard costs. Companies routinely spend $10k+/month across GA4, Segment, Mixpanel, Amplitude, CDPs, and various point solutions. Consolidating means fewer vendor contracts, fewer integrations to maintain, and one source of truth for conversion data.
This use case gives newer products a reason to exist. Workflows and Marketing Analytics are relatively new PostHog products with lower attach rates. Without a use case frame, they're standalone features looking for a buyer. Within Growth and Marketing, each one has a clear role and a natural "next step" in the conversation.
Growth and Marketing creates demand for other use cases. Once a marketing team is in PostHog and sees the depth of product analytics, they pull in the product team (Product Intelligence). Once the growth team is running experiments, engineering gets involved (Release Engineering). This use case is a wedge into broader platform adoption.
Experiments and Feature Flags are the stickiness and multithreading lever. When a CRO or Growth PM starts running A/B tests, feature flags get embedded in the codebase. That's a fundamentally different level of integration than a marketing team viewing dashboards. Flags are in production code, maintained by engineers, and not easy to remove. More importantly, it gives TAMs a natural path to multithread: you now have a growth/marketing champion and an engineering champion using the same platform.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | |---|---|---|---| | Growth Engineer | Growth Eng, PLG Engineer, GTM Engineer | Conversion funnels, activation metrics, experiment velocity, pipeline reliability | "Can I build a full-funnel view from ad click to paid conversion in one tool?" | | Marketing Lead | Head of Marketing, VP Demand Gen, Marketing Ops | Channel attribution, ROAS, campaign performance, cost per acquisition | "Can I see which campaigns actually drive revenue?" | | CRO / Growth PM | Growth PM, CRO Specialist, Head of Growth | Conversion rate optimization, experiment velocity, activation rates. Needs engineering to implement experiments, making this persona the key multithreading catalyst. | "Can I run experiments on our signup flow and measure revenue impact? How fast can engineering implement a test?" | | Founding Growth | Founder, first growth hire at early-stage startup | All of the above. Wearing all hats. Speed, simplicity, not paying for 5 tools | "How fast can I set this up and how many tools does it replace?" | | Marketing Analyst | Marketing Analyst, Data Analyst (Marketing) | Data accuracy, attribution modeling, cohort analysis, reporting | "Can I trust this data? Can I build reports without engineering help?" |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | |---|---|---| | Web Analytics is active but no other products adopted | Product usage data | They came in through the marketing door – there's a full expansion path waiting | | Customer mentions GA4, Segment, or CDP in notes | Vitally notes / conversations | They have marketing stack pain and may be open to consolidation | | Multiple marketing/growth team members invited | User list in Vitally | The growth team is in PostHog, not just engineering – this use case is live | | Low Pipelines / Workflows usage despite high analytics usage | Product spend breakdown | They're analyzing but not acting – Workflows and Pipelines are natural next steps | | Experiments or Feature Flags usage initiated by growth/marketing team (not engineering) | Product usage data + user roles | The CRO/Growth PM persona is active – this is the engineering bridge moment |
PostHog usage signals
| Signal | How to Check | What It Means | |---|---|---| | UTM parameters appearing in event properties | Event property explorer | They're tracking acquisition sources – Marketing Analytics is a natural add | | Funnels built around signup/checkout/activation | Saved insights | Growth team is active and measuring conversion – ripe for Experiments and Workflows | | Experiments created but low flag evaluation volume | Experiments list + flag usage | Growth team is trying to experiment but engineering hasn't implemented the flags yet – TAM opportunity to facilitate the handoff | | Feature flags being used primarily for experiments (not releases) | Flag list + experiment linkage | Growth-driven flag usage – explore whether they'd also use flags for progressive rollouts (Release Engineering cross-sell) | | Web Analytics pageview volume growing | Product usage metrics | Marketing is driving more traffic – they'll want attribution and ROAS soon | | Batch exports configured to ad platforms or CRM | Pipeline configuration | They're already trying to close the data loop – deeper Pipelines usage is the play |
Health score implications
Event volume: Growing web analytics and pageview volume means marketing is scaling. Flat or declining volume may mean they've stalled or are sending traffic data elsewhere.
User engagement: Watch for non-engineering users actively building dashboards and insights. If only engineers use PostHog, the marketing team hasn't been onboarded – that's both a risk and an opportunity.
Product count: Growth and Marketing touches the most products of any use case. Low product count with this persona is a sign there's major expansion headroom. If they're using analytics but not Experiments + Feature Flags, that's the next natural move.
Command of the Message
Discovery questions (current state)
How do you track which channels and campaigns drive signups today? Can you tie that all the way through to revenue?
What does your current marketing/growth tool stack look like? (GA4? Segment? CDP? How many vendors?)
When you run a paid campaign, how do you measure whether it actually worked? How long does it take to get that answer?
Do you send conversion events back to your ad platforms? How is that pipeline built and maintained?
How do you currently onboard new users? Is it automated or manual? What triggers the onboarding flow?
When someone drops off your signup or checkout funnel, can you see why? Do you have any automated re-engagement?
How does your growth team decide what to experiment on? How do you measure experiment results?
Are you running A/B tests on your signup flow, pricing page, or onboarding today? What tool are you using? Who implements the variants, the growth team or engineering?
When an experiment wins, how do you roll it out to 100% of users? Is that process smooth or does it require a separate deploy?
Can your marketing team answer their own questions about performance, or do they depend on engineering/data for every query?
How do you attribute revenue to specific campaigns, channels, or touchpoints?
What's your biggest frustration with your current analytics or attribution setup?
Negative consequences (of not solving this)
Marketing spend is optimized against proxy metrics (clicks, impressions) instead of actual conversions and revenue
Attribution is broken or incomplete – nobody trusts the numbers, so decisions are gut-driven
Conversion data doesn't flow back to ad platforms, so campaign optimization is flying blind
Growth team builds custom ETL pipelines to move data between tools – fragile, expensive to maintain
Onboarding and re-engagement are manual or time-based instead of behavior-driven
Marketing and product teams use different tools with different numbers, leading to misalignment
Growth team can't run experiments because they depend on engineering for every test, or they use a separate tool that isn't connected to their analytics
New users drop off and nobody acts on it because there's no automation layer
Desired state
One platform that tracks the full journey from ad click to paid conversion to revenue
Marketing team can self-serve answers about channel performance, ROAS, and conversion without waiting for analysts
Conversion events automatically flow to ad platforms and CRMs – no custom pipelines to maintain
Onboarding, re-engagement, and lifecycle campaigns fire automatically based on real user behavior
Behavior-triggered messaging re-engages users at exactly the right moment
Every experiment is measured against real business metrics, and the same feature flags used for experiments can be reused for progressive rollouts
Growth and engineering collaborate through a shared platform: growth defines the hypothesis, engineering implements the flag, both see the results
Revenue is attributable to specific channels, campaigns, and user cohorts
Positive outcomes
20-40% reduction in marketing tool spend through consolidation (GA4 + Segment + CDP + point solutions → PostHog)
Higher ROAS from feeding real conversion data back to ad platforms
Faster experiment velocity – growth team runs more tests because the tooling is integrated
Experiments + Feature Flags create a shared workflow between growth and engineering, reducing silos and making the account harder to churn
Increased activation and retention from behavior-driven onboarding (Workflows)
Marketing and product aligned on the same data, same source of truth
Non-technical marketing users can query data in natural language via PostHog AI
Growth team experiment velocity increases (more experiments shipped per quarter)
TAM-facing:
Customer expands from Web Analytics-only (or Product Analytics-only) to multi-product
Non-engineering users (marketing, growth) are active in PostHog
Engineering users are active alongside growth users (multithreaded account)
Feature Flags are embedded in the codebase (stickiness indicator)
Experiments velocity increases (more experiments created per quarter)
Pipeline volume grows (more data flowing out to ad platforms and CRMs)
Workflow usage grows (automation is active, not just analytics)
Competitive positioning
Our positioning
Full-funnel in one platform. No other tool connects web traffic → channel attribution → conversion funnels → user behavior → automated engagement in a single product. GA4 stops at the website. Segment stops at the pipe. Amplitude stops at the dashboard. PostHog goes from first click to lifetime engagement and lets you act on it.
First-party data collection that works. PostHog's first-party tracking isn't blocked by ad blockers the way GA4 and third-party pixels are. More accurate data, better attribution, higher match rates when syncing conversions to ad platforms.
Analytics + automation in the same tool. Most analytics platforms show you the drop-off. PostHog lets you fix it with Workflows to re-engage users. The insight-to-action loop is closed.
Marketing stack consolidation = real cost savings. Replace GA4 + Segment + CDP + survey tool + experimentation tool with one platform.
PostHog AI lowers the adoption bar for non-technical users. Marketing users who will never learn SQL or HogQL can ask questions in natural language.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | |---|---|---|---| | GA4 | Web analytics, basic attribution, Google Ads integration | Full-funnel beyond the website; first-party data; product analytics depth | Deepest Google Ads integration; free tier is very generous; universal adoption | | Segment | CDP – collects events and routes them to destinations | We're the analytics platform and the pipe; no need for a separate CDP layer | More destination integrations; more mature data governance | | Amplitude | Product analytics with some marketing analytics features | Broader product coverage (flags, replay, heatmaps, surveys, workflows); Customer Analytics for account-level views; better pricing | More mature marketing-specific features (audiences, campaign impact); larger enterprise motion | | Mixpanel | Product analytics focused on funnels and retention | Broader platform (web analytics, flags, replay, workflows); no sampling | Deeper mobile analytics; some marketing teams prefer the UX | | HubSpot Marketing Hub | Marketing automation, email, CRM, basic analytics | Engineering-grade analytics; deeper funnel analysis; experiments | Native CRM integration; better email deliverability; non-technical UX | | Heap | Auto-capture product analytics | We also auto-capture, plus flags, experiments, replay, surveys, workflows | Retroactive analytics (virtual events) is a strong pitch for non-technical teams | | Hotjar | Heatmaps, replay, on-site surveys | Full analytics platform underneath; experiments; we ship heatmaps and surveys too | Simpler, more opinionated UX for non-technical CRO teams |
Where PostHog stands: Our strongest position is against teams using 3+ tools to do what PostHog does in one. We're weaker against teams deeply embedded in the Google ecosystem (GA4 + Google Ads + Looker) where switching cost is high. We're also weaker against HubSpot where marketing automation is the primary need. Our sweet spot is technical growth teams and PLG companies where the growth engineer is the buyer.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | |---|---|---| | Marketing Analytics is beta – feature set is still maturing | Some customers may expect parity with GA4 or dedicated attribution tools | Set expectations during onboarding. Position as "growing fast" and highlight the advantage of attribution data living alongside product analytics. | | Workflows is new – not as feature-rich as mature marketing automation | Teams expecting advanced email sequencing, lead scoring, or complex branching may find gaps | Position as behavior-driven automation, not a full HubSpot replacement. For heavy email automation, PostHog complements an existing tool via Data Pipelines. | | No native in-app guides or tooltips | Teams with complex in-app onboarding needs may hit walls | For tooltip/modal UX, keep a dedicated tool (Appcues, Pendo) and use PostHog for analytics + experimentation. | | Pipeline destination coverage may not match Segment's breadth | Some niche destinations may not be supported | Check available destinations before promising. Data Warehouse + Batch Exports covers the most common needs. Webhook destination can bridge gaps. | | Non-technical marketing users may find the UI intimidating | Adoption risk: marketing team tries PostHog, finds it too "engineering-y," and reverts to GA4 | Lead with PostHog AI for querying. Build pre-configured dashboards during onboarding. Web Analytics UI is intentionally simpler – start them there. |
Exceptions / edge cases:
Enterprise demand gen teams with complex lead scoring and email nurture: If the primary need is marketing automation, PostHog is not the right primary tool. Recommend keeping HubSpot/Marketo and using PostHog for analytics, attribution, and experimentation. Data Pipelines bridges the two.
Teams deeply embedded in the Google ecosystem: If they run Google Ads, use GA4, and report in Looker, switching cost is very high. Position PostHog as a complement for product analytics and conversion funnel depth, not a full GA4 replacement. Over time, as Marketing Analytics matures, the replacement conversation becomes easier.
Getting a customer started
What does an evaluation look like?
Scope: Instrument their primary acquisition funnel: landing page → signup → activation event → first conversion/payment. Add UTM tracking and connect web analytics. If they have paid campaigns, set up Marketing Analytics.
Timeline: 2 to 4 weeks to see meaningful data. Channel attribution and funnel insights start showing value within the first week if traffic is decent. Experiments need enough traffic for statistical significance, so timeline varies.
Success criteria: Can you answer: "Which channel drives the most activated users?" Can you see the full funnel from first visit to conversion? Can you tell which campaigns are worth the spend?
PostHog investment: Web Analytics and Product Analytics free tiers cover a substantial evaluation. Marketing Analytics (beta) is included. Surveys and Experiments have generous free tiers.
Key requirement: They need to instrument key conversion events (signup, activation, purchase/upgrade) with proper UTM parameters. If they want Pipelines, they need API credentials for their ad platforms or CRM. See the performance marketing tutorial for a step-by-step walkthrough.
| Objection | Response | |---|---| | "We already use GA4 and it's free." | GA4 is great for basic web traffic. But can it show you which channels drive users who activate and pay, not just visit? Can it send real conversion events back to your ad platforms? PostHog starts free too, and it goes all the way to revenue. (Web Analytics · Funnels) | | "We need Segment for our data pipelines." | What destinations are you sending to? PostHog has built-in Data Pipelines for the most common ones. You may not need a separate CDP layer if PostHog is already collecting the events. Let's look at your current destinations and see what's covered. | | "Our marketing team isn't technical enough for PostHog." | That's exactly why we built PostHog AI – your marketing team can ask questions in plain English. Web Analytics is also designed to be simple and familiar. We'll set up dashboards during onboarding so they have value from day one. | | "Marketing Analytics is beta – can we trust it?" | Fair concern. The core data infrastructure is built on the same battle-tested PostHog platform that handles billions of events. The beta label means we're still adding features, not that the data is unreliable. And your feedback directly shapes the roadmap. | | "We'd need to rip out our whole marketing stack to use PostHog." | You don't have to rip out anything on day one. Start by adding PostHog alongside your existing tools. Once you see the value of having attribution, funnels, and automation in one place, the consolidation happens naturally. Data Pipelines keeps your existing tools fed. | | "Workflows seems basic compared to HubSpot/Braze." | It is newer. The trade-off is that PostHog Workflows is triggered by real product behavior data, not just email opens and form fills. If you need complex email nurture sequences, keep your email tool and use PostHog for behavior-driven automation. They complement each other via Data Pipelines. | | "Our growth team wants to experiment but engineering is too busy to implement flags." | That's actually a common starting point. The first experiment is the hardest because engineering needs to set up the Feature Flag SDK. But once the SDK is in place, subsequent experiments are much faster. Most teams find that after the first 2 to 3 experiments, the loop is smooth. And engineering now has flag infrastructure they can use for their own releases too. |
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | |---|---|---|---| | Web Analytics + Marketing Analytics | Product Analytics (funnels, retention) | They can see traffic and channels but need to connect it to actual user behavior and conversion | "You know which channels bring traffic – but do you know which channels bring users who retain?" | | Product Analytics (funnels) | Experiments + Feature Flags | They've identified drop-off points and want to test fixes | "You've found the drop-off. Want to test whether a new flow actually improves conversion?" | | Product Analytics + Experiments | Workflows | They know what works from experiments and want to operationalize it | "You proved the new onboarding works in an experiment. Now let's automatically nudge every new user toward it." | | Experiments + Feature Flags (growth-driven) | Release Engineering (for the eng team) | Engineering is already implementing flags for experiments – they can use those same flags for progressive rollouts | "Your engineering team is already using feature flags for growth experiments. Have they considered using the same infrastructure for all their releases?" | | Web Analytics + Product Analytics | Data Pipelines | They're analyzing conversion but not feeding it back to ad platforms or CRM | "You're measuring real conversions – are you sending those back to Meta and Google so their algorithms can optimize?" | | Any Growth & Marketing products | Session Replay | They see a funnel drop-off but don't know why | "Your checkout funnel drops 40% at step 3. Want to watch what users are actually doing at that step?" | | Growth & Marketing stack established | Product Intelligence (for the product team) | Marketing/growth is in PostHog – the product team should be too | "Your growth team already uses PostHog for funnels and experiments. Has the product team seen what they can do with cohorts and retention analysis?" |
Product team:To be added: Slack channels for Web Analytics, Marketing Analytics, Workflows, Pipelines teams
Appendix: Company archetype considerations
| Archetype + Stage | Framing | Key Products | Buyer | |---|---|---|---| | AI Native – Early | "You need to get users to your AI product, get them activated, and understand what channels work, all without hiring a data team." Speed matters. Experiments are high-value early. | Web Analytics, Product Analytics (funnels), Experiments, Feature Flags, PostHog AI | Founder, first growth hire, GTM engineer | | AI Native – Scaled | "You're scaling acquisition and need to optimize spend, automate onboarding, and connect marketing data to product engagement." | Web Analytics, Marketing Analytics, Product Analytics, Experiments, Feature Flags, Pipelines, Workflows | Head of Growth, Growth Engineering Lead | | Cloud Native – Early | "You're investing in growth for the first time and want to build it right. One tool for attribution, funnels, experiments, and engagement." | Web Analytics, Product Analytics, Experiments, Feature Flags, Surveys | Founder, first PM, growth engineer | | Cloud Native – Scaled | "Your marketing stack is fragmented and expensive. Consolidate attribution, conversion analytics, engagement automation, and experimentation into one platform." Experiments + Feature Flags are the multithreading lever. | Web Analytics, Marketing Analytics, Product Analytics, Experiments, Feature Flags, Pipelines, Workflows | VP Growth, Head of Growth, CRO, Marketing Ops | | Cloud Native – Enterprise | "Multiple teams, multiple products, multiple markets, and none of them agree on the numbers. PostHog gives you a single source of truth for acquisition, conversion, and engagement across all properties." | Full stack. Pipelines are especially important. | VP Marketing, CMO, Head of Growth, Marketing Ops |
"Help me know when things break, understand why, and fix them fast."
Catch exceptions and regressions before users report them
See the user's actual experience when an error occurred, not just a stack trace
Understand the business impact of incidents: which users were affected, what revenue was at risk
Centralize log collection and search alongside error data, and follow a slow request across services
Triage incidents faster with natural language queries
This is where a lot of our recent shipping has gone, and where significant market opportunity exists. The pitch is a stack that competes with Datadog and Sentry on their home turf, with two advantages neither has: our observability data is connected to product analytics data, and it feeds agents that can open the fix. No other vendor can tell you "this API endpoint is slow, here's the business impact in user drop-off and revenue, and here's the pull request."
Separating this from Release Engineering is important because the buyer is often different (SRE/platform team vs. product engineering), the competitive landscape is different (Datadog/Sentry vs. LaunchDarkly), and the expansion path is different.
What PostHog products are relevant?
Error Tracking (core) — Track exceptions, get alerts, resolve issues. Automatic grouping of similar errors, stack traces, affected user counts. The starting point for most Observability adoption.
Session Replay — User impact of errors, visual reproduction. When an error fires, click through to the user's session and see exactly what happened. This is the killer differentiation vs. Sentry: you don't just see the stack trace, you see the user's actual experience.
Product Analytics — Error correlation with user behavior and business impact. Answer "how many users hit this error?" and "did this error cause drop-off in our conversion funnel?" Connect technical incidents to business outcomes.
PostHog AI — Natural language incident triage. "What errors spiked in the last hour and which users were affected?" without writing a query. Faster mean time to understanding during incidents. (Example prompts)
Logs — Centralized log collection and search over OpenTelemetry (OTLP). Full-text search, severity and service filters, pattern mining that collapses millions of lines into templates, log alerts, and links from a log line to the session replay it came from. Billed per GB ingested with 10GB/month free and 14-day retention (a 30-day retention add-on is available). (Pricing · Best practices)
Distributed tracingalpha — Follow a request across services over OpenTelemetry (OTLP). Trace waterfalls, span search by service/status/duration/attribute, latency percentiles and error rates per operation, and correlated logs inside the span inspector. No proprietary SDK: point your existing OTel exporter at PostHog. Free during alpha. (Start here · Why you need it)
Metricsalpha — Application and infrastructure metrics (counters, gauges, histograms) over the same OTLP pipeline, or recorded directly with posthog.metrics if the PostHog SDK is already installed. The third OTel pillar alongside logs and traces.
Web vitals — Core Web Vitals (LCP, INP, CLS, FCP) captured automatically by the JS SDK. The frontend-performance half of the story, which the OTel pillars don't cover.
A naming note: "APM" is our internal team name, not a product. Customer-facing, the pillars are Logs, Distributed tracing, and Metrics, sitting alongside Error Tracking and Web vitals. Don't tell a customer "APM is coming" — tell them which pillar ships today and at what maturity.
Adoption path and expansion path
Entry point
Usually Error Tracking. Team wants to catch exceptions and regressions. Common entry scenarios:
Sentry replacement: They're paying for Sentry and want to consolidate into PostHog (which they're already using for analytics or flags). Error Tracking is the direct replacement.
First observability tool: Early-stage company that hasn't invested in error tracking yet. PostHog's free tier (100K exceptions/month) lets them start without a new vendor relationship.
Session Replay → Error Tracking: They're already using Session Replay for debugging and discover that errors surfaced in replays could be tracked systematically with Error Tracking.
Error Tracking → Session Replay: They can see the error and the stack trace. But they can't see what the user was doing when it happened. Session Replay lets them click from an error event directly to the user's session and watch the full context. This is the single most differentiated feature in our Observability story.
Session Replay → Logs: They're seeing errors and user sessions. They need the backend context: what was the server doing when this error fired? Centralized logs complete the debugging picture, and log lines link back to the session replay they came from.
Logs → Product Analytics: They're debugging individual errors. Now they want to understand the aggregate impact: how many users are hitting this error? Is it correlated with a specific funnel step? Did this bug cause a revenue drop? Product Analytics connects technical incidents to business outcomes.
Alternate expansion paths
Logs → Distributed tracing → Metrics (the OpenTelemetry path): Once a team is exporting logs over OTLP, traces and metrics are a config change, not a new integration. The same collector, the same project token, three different endpoints. This is the cheapest expansion in the whole playbook to describe — but be honest that traces and metrics are alpha, and check they're not depending on the gaps listed under pain points.
Observability → self-driving: This is the strongest expansion in the playbook. Error tracking, logs, and session replay are all signal sources for self-driving, and there are scouts watching traces, logs, error tracking, web vitals, and observability gaps. An SRE team that has already instrumented for observability has, without meaning to, done all the setup work self-driving needs. See how to pitch self-driving.
Business impact of solving the problem
Observability data connected to product analytics is a moat. Every other observability tool (Datadog, Sentry, New Relic) can tell you "this endpoint threw an error." Only PostHog can tell you "this error affected 500 users, 30 of whom were in the middle of checkout, resulting in an estimated $15k in lost revenue this week." That's a fundamentally different conversation with engineering leadership.
Session Replay as error context is a killer feature. Sentry shows you a stack trace. PostHog shows you the user's actual experience. For frontend and full-stack debugging, this is dramatically faster for reproduction and resolution.
Consolidation play for accounts already using PostHog. If they're already on PostHog for analytics or flags, adding Error Tracking and Logs means one fewer vendor (Sentry, Datadog) to manage. The consolidation saves money and reduces context-switching.
This use case has the highest growth ceiling. The observability market is enormous (Datadog alone is $25B+). Our story gets stronger with every product we ship in this space.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | |---|---|---|---| | SRE / Platform Engineer | SRE, Platform Eng, Infrastructure Eng | Reliability, alerting, mean time to resolution, not getting paged at 3am | "Will this catch issues before users report them? How fast can I triage?" | | Backend Engineer | Backend Eng, API Engineer, Server-side Eng | Stack traces, log correlation, reproducing bugs efficiently | "Can I see what happened on the server when this error fired?" | | Product Engineer | Full-stack Eng, Frontend Eng | User-facing bugs, reproduction, understanding the user impact of errors | "Can I see the user's session when this error happened?" | | Engineering Manager | EM, VP Eng, Director of Eng | Team velocity, incident metrics (MTTR, error rates), cost of observability tooling | "How does this reduce our incident response time? What does it cost vs. Sentry/Datadog?" | | Founder (early stage) | CTO, first engineer | Catching bugs before users complain, not paying Datadog prices | "Does this work out of the box and is it affordable?" |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | |---|---|---| | Error Tracking is active but low product count | Product spend breakdown | They've started with errors. Full Observability expansion path available. | | Customer mentions Sentry or Datadog in notes | Vitally notes / conversations | Competitive displacement opportunity. Consolidation pitch. | | High Session Replay usage with error-related viewing patterns | Product usage data | They're using replay for debugging already. Error Tracking formalizes this. | | Engineering-heavy user base, no PM users | User list in Vitally | Engineering-first account. Observability and Release Engineering are the primary use cases. |
PostHog usage signals
| Signal | How to Check | What It Means | |---|---|---| | Error tracking exceptions growing week over week | Product usage metrics | They're instrumenting more of their stack. Good adoption signal. | | Session Replay filtered by error events | Replay usage patterns | They're connecting replay to error debugging. The integration is clicking. | | High error volume but no alerting configured | Error tracking settings | They're collecting errors but not acting on them. Help them set up alerts. | | Product Analytics queries referencing error events | Saved insights | They're starting to connect errors to business impact. Encourage this. |
Command of the Message
Discovery questions
When something breaks in production, how long does it take your team to find out? From users? From monitoring?
How do you currently track and prioritize errors? Do you have a tool for this, or is it ad hoc?
When you see an error, how do you reproduce it? How long does reproduction typically take?
Can you tell which users were affected by a specific error? Do you know the business impact?
What does your current observability stack look like? (Sentry? Datadog? New Relic? How many tools?)
How much are you spending on observability tooling today?
When an incident happens, how many tools does your team switch between to understand what happened?
Do you have centralized logging? Where do your logs live today?
Negative consequences (of not solving this)
Errors are discovered through user complaints, not proactive monitoring
Stack traces exist but reproduction is guesswork because there's no user session context
Engineering can quantify "how many errors" but not "how many users affected" or "what revenue was lost"
Multiple observability tools (Sentry for errors, Datadog for APM, separate logging) with no connection between them
Incident triage is slow because context is spread across 3+ tools
Observability costs are high and growing (Datadog pricing, Sentry pricing) without clear ROI
Desired state
Errors are caught proactively with alerts before users report them
Every error links to the user's actual session, so reproduction takes seconds, not hours
Error impact is measured in business terms: affected users, affected revenue, affected funnels
Errors, logs, and user sessions live in one platform alongside product analytics
Incident triage is faster because all context is in one place
Positive outcomes
Reduced MTTR (mean time to resolution) from instant session replay access on errors
Better incident prioritization based on business impact
Observability cost reduction through consolidation (replace Sentry + separate logging)
Engineering leadership gets business-impact reporting on reliability, not just technical metrics
Success metrics
Customer-facing:
Mean time to resolution for user-facing bugs decreases
Percentage of errors caught proactively (via alerting) vs. user-reported increases
Error rate trends downward as bugs are prioritized by impact and fixed systematically
TAM-facing:
Error Tracking exception volume grows (instrumenting more of their stack)
Session Replay usage increases with error-filtered viewing (integration is working)
Logs adoption starts, then traces (filling out the observability stack over one OTel pipeline)
Product Analytics queries reference error data (connecting to business impact)
Competitive positioning
Our positioning
Errors + replay in one platform. See the stack trace and the user's actual session. No other error tracking tool offers this depth of user context. Sentry shows you the error. PostHog shows you the experience.
Errors tied to revenue and user behavior. Connect errors to user behavior and revenue with Product Analytics. "This error caused 200 users to abandon checkout" is a different conversation than "this error fired 500 times."
Consolidation for existing PostHog users. If they're already using PostHog for analytics or flags, adding Error Tracking means one fewer vendor. Same data platform, one less tool to manage.
Logs completes the picture. Errors, user sessions, and backend logs in one place. No switching between Sentry, Papertrail, and Amplitude to understand an incident.
OpenTelemetry-native, no proprietary SDK. Logs, traces, and metrics all ingest over standard OTLP. There's nothing to rip out if they leave, which matters to a platform team that's been locked into an agent-based vendor. One OTel setup covers all three pillars.
A signal doesn't stop at the alert. Every other tool on this list tells you something broke and hands you the triage. Errors, logs, and traces are all self-driving signal sources, so a regression can arrive as an investigated report with a pull request attached. Datadog's Bits AI and Sentry's Seer are the only competitors moving in this direction at all.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | |---|---|---|---| | Sentry | Error tracking, performance monitoring, session replay | Deeper product analytics integration; business impact context; flag/experiment connection; better pricing | More mature error tracking features; broader language support; larger install base; code-level profiling | | Datadog | Full observability: APM, logs, metrics, infrastructure | Product analytics integration; session replay depth; OTel-native with no agent; usage-based instead of per-host | Service maps, profiling, infra and k8s monitoring, synthetic monitoring; enterprise-grade; massive ecosystem | | New Relic | Full observability: APM, logs, errors, distributed tracing | Product analytics integration; session replay; simpler pricing | Far more mature APM; complete infra coverage | | Better Stack | OTel-native logs, traces, uptime | Product analytics and session replay alongside; self-driving loop | Service map; more mature tracing; uptime/status pages | | Grafana (Loki/Tempo) | Open-source logs and traces you run yourself | Managed, no infra to operate; user context and business impact | Self-hostable at any scale; huge dashboarding ecosystem |
Where PostHog stands: Our Observability story is narrower than Datadog's. Error Tracking, Logs, and Web vitals are production-ready; Distributed tracing and Metrics are alpha; there's no service map, no profiling, no infrastructure or Kubernetes monitoring, and no synthetic monitoring. So we are not a Datadog replacement for a team whose job is infrastructure. We are a credible replacement for Sentry, and increasingly for a logs vendor, and the honest frame is: "we cover the application and the user; we don't cover your hosts." Where we're differentiated rather than just cheaper is the two ends nobody else joins up — the business impact of an incident on one side, and an agent that opens the fix on the other.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | |---|---|---| | Tracing and Metrics are alpha | Setup details, including the ingestion endpoint, may change before GA. Don't build a migration plan around them yet. | Be honest that these are alpha and free during alpha. They're usable today and a real reason to start exporting OTel to PostHog, but a team mid-migration off Datadog should keep their existing tool running. | | No service map | Platform teams evaluating against Datadog or Better Stack will ask for this by name | We expose call-tree aggregates per parent/child edge, which answers "what calls what and how often" for a known path, but there's no rendered topology view. Say so plainly — it's on our own public comparison table as a gap. | | No code-level profiling or flame graphs | Teams chasing CPU/memory hotspots inside a process won't find it | Tracing localizes the slow span; profiling localizes the slow line. We do the first, not the second. Datadog and Sentry both do profiling. | | No infrastructure, container, or Kubernetes monitoring | This is the single biggest gap vs Datadog and the fastest way to lose an SRE-led deal | Don't fight it. PostHog is application and user observability. If their primary pain is host and cluster health, we're complementary, not a replacement. | | No alerting on spans | Alerts cover insights (trends, funnels, SQL) and logs, but not trace data | Route around it: alert on an error-tracking issue or a log pattern that correlates with the latency you care about. The APM scout also watches p95 and error rate per service on a schedule and files a report — that's proactive coverage, just not a pager. | | Sampling control is limited | No server-side tail sampling; you sample head-side in your own OTel exporter | Set the expectation during setup. Log retention is 14 days by default, with custom retention billed per month and set per service or per source. | | Tracing SDK coverage is backend-only | Node, Python, Go, Java, .NET, PHP, Ruby. No browser or mobile tracing. | Frontend performance is covered by Web vitals and Session Replay instead — a different shape of answer, but not a gap in coverage of the user experience. | | Error Tracking language/framework support may lag Sentry | Sentry supports a very wide range of languages and frameworks | Check Error Tracking docs for current support. For unsupported frameworks, generic exception capture via the API may work. | | No built-in on-call/incident management | Teams wanting PagerDuty-style incident workflows won't find it here | PostHog alerts can trigger webhooks to PagerDuty, Slack, etc. Error Tracking is about detection and context, not incident management workflows. |
Getting a customer started
What does an evaluation look like?
Scope: Enable Error Tracking on their primary application. Connect Session Replay to error events. Set up alerts for critical error spikes.
Timeline: 1 to 3 days to start capturing errors. 1 week to have meaningful error data and session replay context.
Success criteria: Can you see errors grouped by type with affected user counts? Can you click from an error to the user's session replay? Can you get alerted when a new error type spikes?
Key requirement: They need to integrate the PostHog SDK or connect their existing error capture to PostHog's Error Tracking. If they're already using PostHog's SDK, Error Tracking may just need to be enabled.
Onboarding checklist
[ ] Enable Error Tracking in the PostHog SDK configuration
[ ] Verify errors are being captured and grouped correctly
[ ] Connect Session Replay to error events (verify you can click from error → replay)
[ ] Set up alerts for critical error types or spike detection
[ ] Build an "Error Health" dashboard: error trends, top errors by affected users, error rate by release
[ ] Review the top 5 errors with the team, using session replay context to prioritize fixes
[ ] Enable Logs for backend context, and link a log line back to its session replay
[ ] If they already run OpenTelemetry, point a trace exporter at PostHog (alpha, free during alpha)
[ ] Create a Product Analytics query that correlates errors with funnel drop-off or business metrics
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | |---|---|---|---| | Error Tracking only | Session Replay | They see stack traces but can't reproduce the user experience | "You can see the error. Want to see exactly what the user was doing when it happened?" | | Error Tracking + Session Replay | Logs | They have frontend error context but need backend logs | "You can see the user's session. But what was happening on the server at the same time?" | | Logs over OpenTelemetry | Distributed tracing + Metrics alpha | The hard part (an OTel pipeline) is already done; the other two pillars are a config change | "You're already exporting OTel to us. Traces and metrics are the same collector and a different endpoint — and they're free while they're in alpha." | | Error Tracking or Logs active | self-driving | Both of these are already a signal source; the account has done the setup without meaning to | "You've got the signals. Want an agent to investigate them and open the PR, instead of you triaging every alert?" | | Error Tracking + analytics correlation | Product Intelligence (for the product team) | They're connecting errors to user impact. The product team would benefit from the same analytics. | "You're measuring error impact on users. Has your product team seen what they can do with funnels and retention in the same platform?" | | Error Tracking (engineering in PostHog) | Release Engineering (same engineering team) | Engineering is in PostHog for errors. Feature flags for safe releases is a natural add. | "You're tracking errors after releases. What if you could gate features behind flags and roll back without a deploy?" | | Error Tracking for AI features | AI/LLM Observability | Traditional error tracking misses AI quality regressions | "You're catching exceptions, but are you catching when your model starts giving worse answers? That's a different kind of 'error.'" |
Competitive battlecard:To be added: Sentry / Datadog competitive positioning
Appendix: Company archetype considerations
| Archetype + Stage | Framing | Key Products | Buyer | |---|---|---|---| | AI Native — Early | "You're shipping fast and breaking things. PostHog catches errors and shows you the user's experience when they hit a bug. No Sentry bill required." Error Tracking + Session Replay is the sweet spot. | Error Tracking, Session Replay | CTO, founding engineer | | AI Native — Scaled | "Your AI features have failure modes that traditional error tracking misses: hallucinations, slow responses, quality regressions. PostHog catches the technical errors AND lets you evaluate output quality." Bridge to AI/LLM Observability. | Error Tracking, Session Replay, Logs, AI Evals | VP Eng, Platform Lead, SRE | | Cloud Native — Early | "Stop finding bugs from user complaints. Error Tracking catches exceptions automatically, and Session Replay lets you see exactly what happened. 100K exceptions/month free." | Error Tracking, Session Replay | CTO, founding engineer | | Cloud Native — Scaled | "Your team is juggling Sentry, Papertrail, and Datadog. PostHog consolidates error tracking, logs, and user context into the platform you already use for analytics." Consolidation pitch. | Error Tracking, Session Replay, Logs, Product Analytics | VP Eng, SRE Lead, Platform team | | Cloud Native — Enterprise | "Multiple teams, multiple services, and incident context spread across 5 tools. PostHog gives you errors + logs + user sessions + business impact in one platform. No more switching between Sentry, Datadog, and Amplitude during an incident." | Full Observability stack + Enterprise package | VP Eng, Director of SRE, Platform leadership |
"Help me understand what users do, why they do it, and what to build next."
Understand how users navigate your product and where they get stuck
Identify which features drive retention and which are ignored
Get qualitative context for quantitative patterns (the "why" behind the numbers)
Validate product hypotheses with experiments before committing engineering resources
Collect direct user feedback at key moments in the product experience
Track business outcomes (revenue, expansion) tied to product usage
Act on insights by automating onboarding and feature adoption messaging based on user behavior
This is our bread and butter. Most accounts start here. The risk is they stay here as a single product analytics customer and never expand. The opportunity is that Product Intelligence naturally creates demand for the other use cases once teams start acting on what they learn.
Session Replay — The qualitative layer. Watch what users actually do when the numbers say they're dropping off. Bridges the gap between "40% drop at step 3" and "oh, the button doesn't render on mobile Safari."
Surveys — Direct feedback loop at key moments. NPS after onboarding, CSAT after support, "why did you cancel?" on churn. Ties qualitative signal to quantitative behavior data.
Experiments — Validate hypotheses with statistical rigor before committing to a full build. A/B test changes against real metrics, not gut feel. Requires Feature Flags for implementation.
Workflows — Onboarding sequences, activation nudges, lifecycle engagement. The action layer: once you've identified a drop-off in analytics, Workflows lets you do something about it automatically. (Email drip campaigns)
AI Evals — For products with AI features: proactively surface where users are struggling based on AI output quality. This is product intelligence driven by AI observability. A bridge product to the AI/LLM Observability use case.
PostHog AI — Natural language querying and insight discovery. Lowers the bar for non-technical product stakeholders to self-serve. A PM asks "why did retention drop last week?" instead of building a custom query. (Example prompts)
Replay Vision — AI scanners that watch session recordings for you and turn what they see into queryable events. Point a scanner at a set of recordings and it flags dead ends, scores frustration, tags intent, or summarizes what happened — with citations that jump to the exact moment. The output lands as a $recording_observed event, so a finding becomes a funnel breakdown or a cohort, not a note in a vendor's AI panel. See the caveats under pain points before promising it. (Scanner types · Observations)
Heatmaps — Clickmaps, scrollmaps, and rageclick detection via the toolbar. Available on every plan. The thing UX teams ask for by name when comparing us to Hotjar.
self-driving — Session replay and product analytics are signal sources for the self-driving loop, so a friction pattern can arrive as an investigated report with a pull request attached rather than a ticket for someone to write. Be careful how you frame this one for a product audience — see the self-driving section below.
A note on self-driving for this use case
self-driving cuts across all seven use cases, but it lands differently here than it does in Observability or Release Engineering. An error has an obvious right answer, so it converts into a merged pull request quickly. A product-intelligence finding — "users hesitate on the plan picker" — usually needs a human judgment call about what the product should do, so it more often arrives as a needs input report than as code.
That's not a weakness, and reports are free (you're only billed $15 per pull request, first three each month free). To a PM, self-driving's value here is a prioritized queue of investigated problems with the evidence attached, not an agent that redesigns your onboarding. Full guidance in how to pitch self-driving.
Write it lowercase and hyphenated, and keep the customer's product as the subject — we make their product self-driving. It's a capability, not a SKU you can add to an order form.
Adoption path and expansion path
Entry point
Usually Product Analytics. Customer starts tracking events, builds dashboards, creates their first funnel. Then they hit the ceiling of quantitative data alone: "I can see that users drop off, but not why."
Product Analytics → Session Replay: They know what is happening (40% drop at step 3). They need to see why. Session Replay gives them the qualitative context that numbers can't.
Session Replay → Surveys: They're watching replays and forming hypotheses about why users struggle. Surveys let them ask users directly at the moment of friction, then tie responses back to behavior data.
Surveys → Experiments: They've identified the problem through analytics, replay, and feedback. Now they want to test a fix. Experiments require Feature Flags, which gets engineering involved (multithreading moment).
Experiments → Workflows: They've validated what drives value. Now they want to guide users toward those high-value behaviors automatically, through behavior-triggered engagement sequences.
Alternate expansion paths
B2B accounts with Group Analytics: B2B SaaS companies almost always need company-level analytics alongside user-level. If they're B2B and not using Group Analytics, that's a significant upsell opportunity. Group Analytics lets them answer "which companies are most engaged" not just "which users."
Starting from Session Replay: Some accounts come in through Session Replay first (debugging, QA, customer support use cases). They realize they need Product Analytics to quantify what they're seeing qualitatively. The expansion path reverses: Replay → Analytics → Surveys → Experiments.
Product teams that ship AI features: If the product has AI components, AI Evals can proactively surface where users are struggling based on output quality. This bridges Product Intelligence into AI/LLM Observability.
Business impact of solving the problem
This is the use case with the largest existing install base. Most PostHog accounts start with Product Analytics. The expansion opportunity isn't convincing them to adopt PostHog. It's convincing them to go beyond a single product and use the full Product Intelligence stack.
Workflows close the loop from insight to action. You identify a drop-off point (analytics), you understand why users leave (session replay, surveys), and now you can re-engage users when they disengage (workflows). That's a complete insight-to-action cycle that no competitor offers in one platform.
Product Intelligence creates demand for other use cases. Once the product team is deep in PostHog, they pull in the growth team (Growth & Marketing use case) for acquisition and activation. Once they're running experiments, engineering gets involved in rollouts (Release Engineering). This is the gateway use case.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | |---|---|---|---| | Product Manager | PM, Senior PM, Head of Product | Feature adoption, retention, user journeys, proving impact to leadership | "Can I see which features drive retention and prove ROI to my VP?" | | Product Engineer | Full-stack eng on a product team | Fast instrumentation, reliable data, not maintaining a data pipeline | "How fast can I instrument this and how reliable is the data?" | | UX Researcher | UX Researcher, Design Lead | User behavior patterns, qualitative + quantitative, session-level detail | "Can I watch real user sessions filtered by the cohort I'm studying?" | | Designer | Product Designer, UX Designer | How users interact with new designs, A/B testing UI changes | "Can I see the before/after impact of my design changes?" | | Founder (early stage) | Founder, CTO at seed/Series A | All of the above. Finding product-market fit. Speed. | "Does this help me figure out what to build next?" |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | |---|---|---| | Product Analytics is the only paid product | Product spend breakdown | Classic single-product account. Full expansion path available. | | High insight/dashboard creation per active user | Engagement metrics | Product team is actively using PostHog for analysis. They're ready for deeper tools. | | Session Replay is free-tier only or not used | Product usage data | They're doing quantitative analysis without qualitative context. Session Replay is the obvious next step. | | B2B company without Group Analytics | Company type + product spend | Major upsell opportunity. B2B companies need company-level analytics. | | Multiple PM or design roles in the user list | User list in Vitally | Product team is in PostHog, not just engineering. This use case is live. |
PostHog usage signals
| Signal | How to Check | What It Means | |---|---|---| | Funnels and retention insights being created regularly | Saved insights | Product team is actively measuring conversion and retention. Ripe for Experiments. | | Session Replay enabled but low viewing rate | Replay settings vs. replay views | They've turned it on but aren't using it. Needs onboarding or a nudge to connect it to their analytics workflow. | | No experiments running despite active analytics | Experiments list | They're identifying problems but not testing solutions. Experiments is the next conversation. | | Dashboards shared across multiple users | Dashboard sharing settings | They're collaborating on insights. Good health signal and potential for team expansion. | | High event volume, low survey usage | Product usage metrics | They have the traffic to run surveys but haven't started. Low-hanging cross-sell. |
Command of the Message
Discovery questions
How does your product team decide what to build next? What data informs that decision?
When you see a drop-off in a funnel, how do you figure out why users are leaving?
How do you measure whether a new feature is successful after launch?
Do you collect direct user feedback inside the product? How is that connected to your analytics?
When you have a hypothesis about user behavior, how do you validate it? Do you run experiments?
How do you prove to leadership that a product investment drove business results (revenue, retention)?
How many tools does your product team use to understand users? (Analytics, replay, surveys, experiments — how many vendors?)
Can your PMs answer their own questions, or do they depend on data/engineering for every query?
Negative consequences (of not solving this)
Product decisions are based on gut feel or incomplete data because the team can't connect behavior to outcomes
PMs can see that users drop off but not why, leading to guesswork about what to fix
Experiments are rare or nonexistent because the tooling is disconnected from analytics, so every test requires a separate setup
User feedback (surveys) lives in a separate tool, disconnected from behavior data, so you can't answer "what happened right before this user gave us a 3/10?"
Product team can't prove business impact, making it hard to justify investment or prioritize
Insights are identified but never acted on because there's no automation layer to guide users or re-engage them
Desired state
One platform for the full cycle: measure behavior → watch sessions → collect feedback → test changes → measure revenue impact → act on insights
PMs can self-serve answers without waiting for a data team
Every product change is measured against real retention and revenue metrics
Onboarding and feature adoption are guided automatically based on user behavior
Product team and engineering share the same platform, reducing tool fragmentation
Positive outcomes
Faster product decisions: cycle time from "we see a problem" to "we've validated a fix" drops significantly
Higher retention from catching and addressing drop-off points systematically
Better resource allocation: experiments prove what works before engineering commits to a full build
Product team can demonstrate revenue impact to leadership, strengthening their influence
Tool consolidation: replace separate analytics + replay + survey + experimentation vendors with one platform
Success metrics
Customer-facing:
Feature adoption rates improve for targeted features
Retention curves flatten or improve for key cohorts
Experiment velocity increases (more hypotheses tested per quarter)
Time from insight to action decreases
TAM-facing:
Customer expands from Product Analytics-only to multi-product (Session Replay, Surveys, Experiments)
Multiple product team members (PMs, designers) are active
Experiment usage grows (indicates the product team is using PostHog for decisions, not just reporting)
Workflow usage starts (they're closing the insight-to-action loop)
Competitive positioning
Our positioning
Quantitative + qualitative in one platform. Product Analytics and Session Replay together. No switching between Amplitude and Hotjar. Filter replays by funnel drop-off, cohort, or event.
Insight you can act on. Most analytics tools stop at the dashboard. PostHog lets you act on what you find with Workflows and Experiments.
Experiments built into the analytics workflow. See a drop-off in a funnel, right-click to create an experiment, measure the result in the same tool. No separate experimentation platform.
PostHog AI makes analytics accessible. PMs who aren't comfortable with SQL can ask questions in plain English.
AI on replay that produces queryable data. Most competitors now ship some flavor of AI-over-session-replay. The differentiator is that Replay Vision emits a normal PostHog event, so "sessions where the user hit a dead end" becomes a funnel breakdown, a cohort you can survey, or an experiment exclusion. Everyone else's AI findings stay inside their AI panel.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | |---|---|---|---| | Amplitude | Product analytics, cohorts, experiments | Broader platform (replay, flags, surveys, workflows); better pricing; open source | More mature ML features (predictions, audiences); larger enterprise install base | | Mixpanel | Product analytics, funnels, retention | Broader platform; no sampling; replay + surveys + flags included | Some teams prefer the UX; strong mobile analytics | | Hotjar | Session replay, heatmaps, basic surveys | Engineering-grade analytics alongside replay; experiments; flags; we ship heatmaps too | Simpler UX for non-technical users; purpose-built for UX research | | Heap | Auto-capture product analytics, session replay | Also auto-capture, plus flags, experiments, surveys, workflows | Retroactive analytics (virtual events) is a strong pitch | | Pendo | Product analytics + in-app guides | Deeper analytics; experiments; open source; better pricing | More mature in-app guides; stronger enterprise PM workflow features | | Fullstory | Autocapture, replay, StoryAI (session summaries, friction "Opportunities") | AI findings become queryable events, not panel-only insights; flags and experiments in the same tool | More mature enterprise DXA motion; StoryAI has been GA longer and is more established in enterprise deals | | Contentsquare / Heap | Behavioral analytics, Sense Analyst (autonomous analysis agent) | One platform through to shipping the fix; better pricing | Sense Analyst is further along than our replay AI; deep enterprise CX tooling | | LogRocket | Replay, product analytics, Galileo AI (issue severity, Ask Galileo) | Broader platform; our signals feed an agent that opens PRs in your repo | Galileo is GA and dispatches Cursor agents today; strong frontend debugging |
Where PostHog stands: Our strongest position is the breadth of the platform. No competitor offers analytics + replay + heatmaps + surveys + experiments + workflows in one tool. We're weaker against Amplitude in very large enterprises where their ML features and enterprise sales motion are more mature. We're weaker against Hotjar/Pendo for non-technical product teams who want a simpler, more opinionated UX.
On AI specifically, be careful not to oversell: nearly every competitor shipped an AI analyst in the last year, several of them GA for longer than Replay Vision, and a customer who has seen Fullstory's or LogRocket's demo will not be impressed by "we have AI too." The defensible claims are narrower and better: the AI output is a first-class event you can join to the rest of your data, and the loop doesn't stop at an insight — it continues into a pull request. Our sweet spot is technical product teams at companies with engineers who value depth, flexibility, and not paying for 5 separate tools.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | |---|---|---| | No native in-app guides or tooltips | Teams with complex in-app onboarding needs may hit walls | For tooltip/modal UX, keep a dedicated tool (Appcues, Pendo) and use PostHog for analytics + experimentation. | | Workflows is new, less mature than dedicated engagement tools | Teams expecting Braze-level email sequencing will find gaps | Position as behavior-driven automation, not a full lifecycle marketing replacement. Complement with existing tools via Data Pipelines. | | Replay Vision is quota-limited | A broad scanner can burn the monthly credit budget fast | Usage is metered in credits against a monthly budget per organization, scanners sample by default, and it's Gemini-only. Scope scanners narrowly to one flow while tuning — see quota and limits. | | Replay Vision output is a model's judgment, not ground truth | A PM who treats one observation as fact will get burned | Every observation carries a confidence score and citations that link to the exact moment — coach customers to spot-check before acting, and to look for a pattern across sessions rather than trusting a single scan. | | Learning curve for non-technical PMs | PMs used to Amplitude's guided UX may find PostHog's flexibility overwhelming initially | Lead with PostHog AI for querying. Build pre-configured dashboards during onboarding. Start with simple funnels and retention, not HogQL. |
Getting a customer started
What does an evaluation look like?
Scope: Instrument their core product flow: signup → key activation event → retention-defining action → conversion/upgrade. Build the primary funnel and retention analysis. Enable Session Replay on key flows.
Timeline: 1 to 2 weeks to see value from analytics and replay. Experiments need enough traffic for statistical significance, so timeline varies.
Success criteria: Can you answer: "Where do users drop off in our core flow, and why?" Can you see the full retention curve by cohort? Can you watch a replay of a user who dropped off?
[ ] If they're a fit for Replay Vision, get a first scanner running on a flow they care about
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | |---|---|---|---| | Product Analytics only | Session Replay | They see the numbers but not the why | "You can see 40% drop off at step 3. Want to watch what's actually happening?" | | Product Analytics + Session Replay | Surveys | They're forming hypotheses from replays and want direct user input | "You're watching sessions and seeing confusion. Want to ask users directly what's tripping them up?" | | High Session Replay volume, low viewing rate | Replay Vision | They're paying to record sessions nobody has time to watch | "You recorded 40,000 sessions last month. How many did anyone actually watch? What if a scanner read all of them and tagged the ones where people got stuck?" | | Watching replays and filing tickets manually | self-driving | The triage between "we saw the problem" and "someone fixed it" is all manual | "You've found the friction. Who writes the fix, and how long does it sit in the backlog first?" | | Product Analytics + Surveys | Experiments | They've identified problems and want to validate fixes | "You know the problem. Let's test whether your proposed fix actually works before building it fully." | | Analytics + Experiments mature | Workflows | They know what works and want to operationalize it | "You proved the new onboarding flow works. Now let's automatically nudge every new user toward it." | | Product team in PostHog | Growth & Marketing (for the growth team) | Product team is in PostHog. Growth team should be too. | "Your PMs are using PostHog for product decisions. Has the growth team seen what they can do with funnels and experiments for conversion optimization?" | | B2B account, no Group Analytics | Group Analytics add-on | B2B companies need company-level analytics | "You're tracking individual users. But do you know which companies are most engaged and which are at risk?" | | Product team using flags for experiments | Release Engineering (for the eng team) | Engineering is implementing flags for experiments. They can use them for releases too. | "Your engineers are already deploying feature flags for experiments. Have they considered using the same infrastructure for all their releases?" |
| Archetype + Stage | Framing | Key Products | Buyer | |---|---|---|---| | AI Native — Early | Product Intelligence looks different here. There's no UX researcher. A GTM engineer or founding PM is looking at funnels, activation rates, and conversion. Frame it as "understand what makes users stick" not "deep behavioral research." | Product Analytics (funnels, retention), Session Replay, Experiments, PostHog AI | Founder, founding PM, GTM engineer | | AI Native — Scaled | Starting to formalize the product function. May have a dedicated PM. AI Evals becomes relevant as a bridge: evaluating AI output quality is product intelligence for AI products. | Product Analytics, Session Replay, Surveys, Experiments, AI Evals | PM, Head of Product, AI Product Lead | | Cloud Native — Early | First real analytics investment. They need to find product-market fit. Speed matters. Don't overwhelm with features. Start with funnels and retention, add replay and surveys as they mature. | Product Analytics, Session Replay, PostHog AI | Founder, first PM, product engineer | | Cloud Native — Scaled | Dedicated product team with PMs, designers, maybe UX researchers. They want depth: cohort analysis, retention by feature, experiment velocity. Workflows becomes relevant for operationalizing insights. | Full Product Intelligence stack. Group Analytics if B2B. | Head of Product, VP Product, UX Research Lead | | Cloud Native — Enterprise | Multiple product teams, multiple workloads. The play is expanding PostHog from one team to many. Standardization and governance matter. RBAC (Enterprise package) becomes relevant. | Full stack + Group Analytics + Enterprise package | VP Product, CPO, product ops |
"Help me ship faster without breaking things, control who sees what, and validate that changes actually work."
Safely roll out features to specific users or groups before a full release
Instantly kill a bad deploy without a rollback or hotfix
Measure the actual impact of a release on key metrics, not just "it didn't crash"
Reproduce user-reported bugs from the user's actual perspective during a rollout
Run A/B tests tied to releases so every ship is a learning opportunity
Detect quality regressions in AI features after prompt or model changes
What PostHog products are relevant?
Feature Flags (core) — Controlled rollouts, percentage-based releases, targeted delivery to specific users/groups, kill switches. The foundation of safe shipping. Engineering teams use flags to decouple deployment from release: code ships to production but features are gated behind flags. (Getting started · Multivariate flags)
Experiments — A/B testing tied directly to releases. "We shipped a new checkout flow behind a flag. Did it actually improve conversion, or just look better in the demo?" Experiments are billed with Feature Flags, so customers with flags already have access. (Creating experiments)
Session Replay — Reproduce bugs from the user's actual perspective during rollout. When a user reports "the new feature is broken," you don't need to guess. Filter replays by feature flag variant and watch exactly what happened. Also useful for rollout validation: watch how real users interact with the new feature before expanding the rollout.
AI Evals — For products with AI features: detect quality regressions after prompt or model changes. Traditional error tracking won't catch a model that starts producing lower-quality output. Evals compare output quality before and after a change, catching regressions that look "fine" from an error rate perspective but degrade user experience.
self-driving — Release engineering is where self-driving converts best, because the work is mostly maintenance: a regression after a deploy has a right answer, so an agent can investigate it and open a pull request. Scouts watch feature flags (including stale ones), experiments, error tracking, and CI. Billed at $15 per pull request, first three each month free; reports are always free. (How to pitch it)
PostHog Desktopbeta — Where engineers review and merge the work self-driving proposes. Its enricher parses the local codebase and annotates PostHog SDK calls inline with live data: what percentage a flag is rolled out to, whether it's stale, whether the experiment behind it is still running. For a team drowning in flags, that's the flag-hygiene feature LaunchDarkly charges for. (Positioning)
Adoption path and expansion path
Entry point
Usually Feature Flags. Engineering team wants controlled rollouts. Common entry scenarios:
Progressive rollout: Team wants to ship a risky change to 5% of users, monitor, then expand gradually. Feature flags give them the gate; they quickly want metrics to know when it's safe to expand (Experiments).
Kill switch: After a bad deploy that took hours to roll back, engineering wants instant off-switches for new features. Feature flags are the answer.
Growth team bridge: The growth team wants to run an A/B test on the signup flow. Experiments requires Feature Flags, which requires engineering to implement. Engineering gets pulled into PostHog through the growth team's request. (See the Growth & Marketing playbook for this entry path.)
Feature Flags → Experiments: They're rolling out features behind flags but only monitoring for crashes, not measuring business impact. Experiments lets them answer "did this change actually improve the metric we care about?" Since Experiments is billed with Feature Flags, the barrier is adoption, not cost.
Experiments → Session Replay: They're measuring impact quantitatively but can't debug issues qualitatively. When an experiment shows the control is outperforming the variant, they need to see why. Filter replays by flag variant, watch what's going wrong.
Alternate expansion paths
Starting from Experiments (growth-driven): The growth team wants to A/B test, which requires engineering to implement flags. Engineering discovers they can use the same flag infrastructure for all their releases. This is the reverse entry: growth team is the catalyst, engineering becomes the power user. The growth team stays in Growth & Marketing; engineering lands in Release Engineering.
AI product teams: After a prompt or model change, engineering wants to verify quality hasn't regressed. AI Evals catches regressions that traditional error tracking misses. This bridges into AI/LLM Observability.
Business impact of solving the problem
This is a different buyer than Product Intelligence. Release Engineering targets engineering managers, platform teams, and individual developers. In most organizations, these are separate from the product analytics buyer (PM). Selling to engineering unlocks a parallel revenue stream from the same account. Two budget holders, two champions, much stickier account.
Feature Flags in the codebase are sticky. Once feature flags are integrated into the release workflow and embedded in production code, they're very hard to rip out. This isn't a dashboard someone stops logging into. It's infrastructure that engineering depends on for every deploy. This makes Release Engineering accounts among the most defensible in our book.
Flags and experiments are tightly integrated. LaunchDarkly has flags but weak experimentation. Standalone experimentation tools (Statsig, Eppo) have experiments but aren't integrated with the broader analytics platform. PostHog connects flags → experiments → product analytics → session replay in one tool.
Experiments + Feature Flags create the multithreading bridge. When growth wants to experiment and engineering implements the flags, both teams are in PostHog. This is one of the best ways to get multithreaded in an account if you aren't already.
Personas to target
| Persona | Role Examples | What They Care About | How They Evaluate | |---|---|---|---| | Engineering Manager | EM, VP Eng, Director of Eng | Release velocity, incident rate, rollback time, team productivity | "Will this make my team ship faster with fewer incidents?" | | Platform Engineer | Platform Eng, DevEx, Infrastructure | Developer experience, flag management at scale, API reliability | "How does this scale to thousands of flags? What's the API latency?" | | Individual Developer | Senior Eng, Staff Eng, Product Engineer | Fast to implement, doesn't slow down CI/CD, good SDK quality | "How many lines of code to add a flag? Does the SDK suck?" | | Founding Engineer | CTO, first engineers at early-stage startup | Speed, simplicity, not paying for LaunchDarkly's enterprise pricing | "How fast can I set this up and how much does it cost?" |
Signals in Vitally & PostHog
Vitally indicators this use case is relevant
| Signal | Where to Find It | What It Means | |---|---|---| | Feature Flags is the primary or only paid product | Product spend breakdown | Engineering-first account. Full Release Engineering expansion path available. | | High flag evaluation volume, low experiment count | Product usage data | They're using flags for rollouts but not measuring impact. Experiments is the next conversation. | | Customer mentions LaunchDarkly in notes | Vitally notes / conversations | Competitive displacement opportunity. They may be paying LaunchDarkly prices for flags alone. | | Engineering-only users (no PMs or marketing) | User list in Vitally | Engineering-first adoption. Release Engineering is the primary use case. Product Intelligence is the cross-sell. |
PostHog usage signals
| Signal | How to Check | What It Means | |---|---|---| | Feature flags created frequently but no experiments | Flag list vs. experiments list | They're using flags for rollouts but not measuring impact. Low-hanging Experiments adoption. | | Flags with high evaluation volume | Flag usage metrics | Flags are in production, integrated into the codebase. High stickiness. | | Session Replay enabled but not filtered by flag variant | Replay usage | They're recording sessions but not connecting them to rollout debugging. Onboarding opportunity. | | Multiple flags per user/team | Flag list + creators | Multiple engineers are using flags. Good health signal and potential for team-wide adoption. |
Command of the Message
Discovery questions
How do you currently roll out new features? All at once, or gradually?
When a deploy goes wrong, how long does it take to roll back? What's that process look like?
After you ship a feature, how do you know it's working? What metrics do you check?
Do you run A/B tests on product changes? How is that connected to your release process?
When a user reports a bug in a new feature, how do you reproduce it?
How many deploys per day/week does your team ship? What slows that down?
Are you using a feature flag tool today? What do you like and dislike about it?
How does your growth team run experiments? Does engineering implement those, or is it separate?
Negative consequences (of not solving this)
Risky deploys require full rollbacks, costing hours of engineering time and user trust
No way to gradually roll out to a subset of users, so every release is all-or-nothing
Features ship without measuring impact, so the team doesn't know if changes actually helped
Bug reproduction is guesswork because there's no way to see the user's actual experience during a rollout
Engineering and growth/product teams use separate tools, so experiment results don't connect to release decisions
High LaunchDarkly costs for feature flagging alone, without experiments or analytics integration
Desired state
Every feature ships behind a flag with gradual rollout and instant kill switch capability
Every release is measured against real business metrics
When a user reports a bug in a new feature, engineers can watch their exact session filtered by flag variant
Growth team experiments and engineering rollouts use the same infrastructure
Flag, experiment, and analytics data live in one platform, so the full picture is visible without switching tools
Positive outcomes
Faster release cycles: engineers ship with confidence because they can roll back instantly
Fewer incidents: gradual rollouts catch issues at 5% instead of 100%
Better product decisions: every release is also a measurement opportunity
Reduced tooling cost: replace LaunchDarkly + separate experimentation tool with one platform
Multithreaded account: growth and engineering share the same platform for experiments and rollouts
Success metrics
Customer-facing:
Release velocity increases (more deploys per week)
Mean time to recovery from bad deploys decreases
Percentage of releases measured with experiments increases
Bug reproduction time decreases (engineers can watch filtered replays)
TAM-facing:
Feature Flag evaluation volume grows (flags are being used more broadly)
Experiment count increases (moving from "just flags" to "flags + measurement")
Session Replay adoption grows alongside flag usage (debugging workflow)
Flags + experiments + analytics in one platform. The only tool where you can create a flag, run an experiment, measure the result in Product Analytics, and watch user sessions filtered by variant. No stitching together LaunchDarkly + Statsig + a replay tool.
Experiments included with Feature Flags. Experiments are billed as part of Feature Flags. Customers using flags already have experimentation. The barrier is awareness and adoption, not cost.
Session Replay filtered by flag variant. When an experiment shows the control winning, filter replays by the losing variant and watch what went wrong. No other flag tool offers this.
Better pricing than LaunchDarkly. LaunchDarkly is expensive and charges separately for experimentation. PostHog bundles it and prices on requests, not seats.
Competitor quick reference
| Competitor | What They Do | Our Advantage | Their Advantage | |---|---|---|---| | LaunchDarkly | Feature flags, targeting, enterprise flag management | Experiments included; analytics integration; session replay; far better pricing | More mature enterprise flag management; larger feature set for complex targeting rules; bigger enterprise install base | | Statsig | Feature flags + experimentation + analytics | Broader platform (replay, surveys, workflows); open source; we also ship frequentist, CUPED, and holdouts | Purpose-built for experimentation; deeper warehouse-native motion. Note their team went to OpenAI in 2025 and Amplitude took on the brand and customers in 2026 — worth raising as a continuity risk if a prospect is mid-evaluation | | Eppo | Warehouse-native experimentation | Broader platform; doesn't require a data warehouse; integrated replay; we support warehouse-backed experiment metrics too | Purpose-built for warehouse-native teams with an established dbt/Snowflake practice | | Split.io | Feature flags + experimentation | Broader platform; better pricing; integrated analytics | More mature enterprise integrations |
Where PostHog stands: Our strongest position is against teams paying LaunchDarkly prices for flags alone and not getting experiments included. The "flags + experiments + analytics in one platform" pitch saves them money. We're weaker against teams that need very complex flag management at enterprise scale (LaunchDarkly's core strength). Our sweet spot is engineering teams that want the full loop: flag a feature, measure its impact, debug issues with replay, and increasingly have an agent open the follow-up fix — all in one tool.
Pain points & known limitations
| Pain Point | Impact | Workaround / Solution | |---|---|---| | Flag management UX is simpler than LaunchDarkly's | Enterprise teams with hundreds of flags may want more organizational features | PostHog flags work well at scale. For very complex targeting, review the multivariate flags and payloads documentation. | | No built-in flag approval workflows | Some enterprise teams want PR-style review before a flag goes live | Use existing code review processes (flags are in code). PostHog activity logs track changes. | | Choosing between Bayesian and frequentist | Teams arrive with a strong preference and expect you to have picked wrong | Not a limitation any more — we ship both, selectable per experiment, alongside CUPED variance reduction and holdouts. Ask which they use and match it. | | Stale flags accumulate in the codebase | Every flag-heavy team ends up with dead flags nobody dares delete | Stale flag cleanup plus the PostHog Desktop enricher, which annotates flag calls in the editor with live rollout and staleness. There's also a scout that watches for them. |
Getting a customer started
What does an evaluation look like?
Scope: Implement feature flags on one upcoming release. Ship behind a flag with gradual rollout. Optionally set up an experiment to measure impact.
Timeline: 1 to 2 days to implement first flag. 1 to 2 weeks to see experiment results (depends on traffic).
Success criteria: Can you gate a feature behind a flag and roll it out gradually? Can you instantly kill a flag if something goes wrong? Can you measure the impact of the change with an experiment?
Key requirement: Engineering needs to integrate the PostHog SDK into their codebase. This is the implementation step. Once the SDK is in, adding new flags is trivial.
[ ] For flag-heavy teams, install PostHog Desktop and show the enricher annotating their own flag calls with live rollout data
Cross-sell pathways from this use case
| If Using... | They Might Need... | Why | Conversation Starter | |---|---|---|---| | Feature Flags only | Experiments | They're gating features but not measuring impact | "You're rolling out features safely. But do you know if they're actually working? Experiments are included with your flags." | | Feature Flags + Experiments | Session Replay | They're measuring impact but can't debug qualitative issues | "Your experiment shows the control winning. Want to watch what users in the losing variant are actually experiencing?" | | Feature Flags (engineering-driven) | Product Intelligence (for the product team) | Engineering is in PostHog. Product team should be too. | "Your engineers use PostHog for releases. Has your product team seen the analytics? They could track feature adoption and retention without a separate tool." | | Feature Flags (for growth experiments) | Growth & Marketing (for the growth team) | Growth team initiated the experiments, engineering implemented the flags. Expand the growth side. | "Your growth team started the experiments. Have they explored Web Analytics and Marketing Analytics for attribution?" | | Feature Flags + Experiments | Error Tracking / Observability | They're catching issues via experiments but want proactive error detection | "You're catching regressions through experiments. Error Tracking would catch exceptions before they show up in your metrics." | | AI product releasing prompt/model changes | AI/LLM Observability | They need to detect quality regressions that error tracking won't catch | "After your last prompt change, did output quality hold up? AI Evals would tell you automatically." | | Flags + Experiments + Error Tracking all active | self-driving | They have every signal source the loop needs and are still triaging by hand | "You're already catching regressions after a rollout. Want the agent to investigate and open the PR while you sleep?" | | Hundreds of flags, unclear which are dead | PostHog Desktop | Flag debt is invisible in the editor, which is where engineers actually live | "Your engineers can't tell which flags are still doing anything without leaving their editor. The enricher annotates every flag call with its live rollout inline." |
Competitive battlecard:To be added: LaunchDarkly competitive positioning
Appendix: Company archetype considerations
| Archetype + Stage | Framing | Key Products | Buyer | |---|---|---|---| | AI Native — Early | "Ship fast, break nothing. Feature flags let you deploy AI features to a subset of users and measure quality before going wide." AI Evals is especially relevant here. | Feature Flags, Experiments, AI Evals | CTO, founding engineer | | AI Native — Scaled | "Your engineering team is growing and releases are getting riskier. Feature flags give everyone a safety net, and experiments make sure every change is measured." | Feature Flags, Experiments, Session Replay | VP Eng, Platform Lead | | Cloud Native — Early | "Stop doing all-or-nothing deploys. Ship behind a flag, measure the impact, roll back in one click if something breaks." Speed and simplicity matter. | Feature Flags, Experiments | CTO, founding engineer | | Cloud Native — Scaled | "Multiple teams shipping to the same product. Feature flags give each team independent release control. Experiments ensure changes are measured, not just shipped." | Feature Flags, Experiments, Session Replay | VP Eng, EM, Platform team | | Cloud Native — Enterprise | "Standardize your release process across teams and BUs. Feature flags + experiments give you a consistent framework for safe, measured releases at scale." Governance (audit logs, RBAC) matters here. | Feature Flags, Experiments, Session Replay + Enterprise package | VP Eng, Director of Platform, DevEx Lead |
When we pitch "add Surveys," it sounds like we're trying to increase their bill. When we pitch "here's how to close the loop on why users drop off," it sounds like we're solving their problem. Same product. Different framing. Very different conversion rate.
Use cases are how we sell. Products are how we bill. A use case is a discrete problem a team is trying to solve, supported by a combination of PostHog products. Billing, metering, and packaging don't change. What changes is how we talk about it, how we organize around it, and how we measure adoption.
Each use case has a full playbook with discovery questions, competitive positioning, expansion paths, objection handling, and onboarding checklists.
The seven use cases
| Use case | Job to be done | Core buyer | |---|---|---| | Product Intelligence | "Help me understand what users do, why they do it, and what to build next." | PMs, designers, product engineers, founders | | Release Engineering | "Help me ship faster without breaking things." | Engineering managers, platform teams, developers | | Observability | "Help me know when things break, understand why, and fix them fast." | SREs, platform engineers, DevOps | | Growth & Marketing | "Help me understand what drives acquisition, conversion, and revenue." | Growth engineers, marketing leads, CRO, GTM engineers | | AI/LLM Observability | "Help me understand how my AI features perform, what they cost, and how users interact with them." | AI/ML engineers, AI PMs, AI founders | | Data Infrastructure | "Help me unify product data with business data and get it where it needs to go." | Data engineers, analytics engineers, product ops | | Customer Experience | "Help me handle customer conversations in one place, understand what happened, and ship the fix." | Support leaders, engineering leads, CS leaders |
Maturity matters when you're pitching. Anything marked alpha or beta above needs a caveat in the room, and each playbook carries the specific one. Two are worth knowing before any call:
Replay Vision is generally available — no waitlist, but usage is metered in credits against a monthly budget, so scope scanners narrowly. See quota and limits.
self-driving is a capability, not a SKU. Write it lowercase and hyphenated, and keep the customer's product as the subject: we make their product self-driving. Never "PostHog is a self-driving product." See brand foundations and how to pitch self-driving.
Products vs tools. In brand terms, most rows above are tools — the capabilities you access through the five products (PostHog Web, Slack, MCP, CLI, and Desktop). That distinction doesn't change how you sell a use case, but it does change the words: don't call PostHog Desktop a tool, and don't call product analytics a product.
Playbook structure
Every use case playbook follows the same sections, so TAMs know where to find what they need:
Job to be done
What PostHog products are relevant (with doc links)
Adoption and expansion paths
Business impact
Personas to target
Signals in Vitally & PostHog
Command of the Message (discovery, negative consequences, desired state, outcomes, metrics)
Competitive positioning
Pain points & known limitations
Getting a customer started (evaluation scope, onboarding checklist)
We don't optimize for short-run revenue growth, but we do make sure we have enough money to never feel dependent on future fundraising.
If we average 5% MoM growth, we are default alive (i.e. we'll become profitable before we run out of capital). If we average 7.5% we'll hit $100m by the end of 2026.
Maintaining a strong financial position helps us optimize for long-term revenue growth. For example, we've removed products and revenue for long-term gains.
Fundraising principles
Rule #1: Never have to fundraise – and only fundraise if all the following are true:
It will speed us up.
We can use the money effectively.
The partner would improve our board.
The increased chance of success offsets dilution.
It reduces stress.
How do we spend it
PostHog grows by shipping, whereas most software companies grow linearly with the number of salespeople they hire.
The advantage of our approach is that it's more efficient – $1 spent on product will _forever_ improve things, unlike investing $1 in cold calls. We can easily choose to be profitable if we just sit default alive and let revenue grow "automatically" based on the product we have already shipped.
The disadvantage is that scaling an engineering team is, in our opinion, harder than scaling a sales team. Since engineers' work very heavily overlaps, there is more complexity to getting this right. We may not be able to grow beyond a certain rate, no matter how much we spend.
The final disadvantage is that it's harder to predict how fast we'll grow compared to a company that grows by hiring salespeople with targets, so it takes more thought and often requires more faith!
The metrics we track and how to read our financials
We group them into monthly financials (the basics — what we made, what we spent) and quarterly SaaS metrics (the efficiency lens to determine if we're growing well).
Financial reports
Revenue, COGS, gross profit — the money we made, the cost of delivering it, and what's left. Everyone has a stake, especially product and engineering — they influence both halves of this, what we charge for and what it costs to run. We want revenue and gross profit to grow; COGS grows too (more customers), but ideally, slower than revenue.
Gross margin — gross profit as a % of revenue, i.e. what we keep from each revenue dollar after the cost of delivering the product. The cleanest read on whether the product itself is profitable, before any other spend. Most relevant to engineering and FinOps, because COGS is mostly infra, hosting and costs of direct labour. Higher is better; a great SaaS business sits at 75%. Below that, we're pricing too low or our infra is too expensive.
Bad debt as a % of revenue — the share of billed revenue we never collect. Tells us about who we're selling to and how tight our billing and collections are. Most relevant to billing, finance, and sales. Lower is better — under 2% is our limit, under 1% is great.
Operating expenses (S&M, R&D, G&A) — the three big spend buckets: sales & marketing, R&D (mostly engineering), and general & admin. Where the money goes to run the business. Direction isn't as simple as "lower is better" — absolute dollars grow as we scale, and that's expected. What we want falling over time is OpEx as a % of revenue — that's operating leverage. R&D staying strong is a feature for a product-led company.
Quarterly SaaS metrics
ARR per employee — annual recurring revenue ÷ headcount. Tells us whether we're scaling efficiently or just adding people. Higher is better; IPO-stage SaaS sits around $580k.
Burn multiple — cash burned per $1 of new ARR. Tells us whether our growth is worth what it costs. Lower is better — under 1x is good, under 0.3x is top quartile.
SaaS magic number — new ARR earned per $1 of sales & marketing spend. A test of whether our go-to-market spend is paying off. Higher is better — above 1x means we're earning more in new ARR than we're spending to get it.
Rule of 40 — revenue growth % + profit margin %. Forces the trade-off question: are we growing fast at the expense of profit, or profitable at the expense of growth? Above 40% is the bar.
Cash balance — cash on hand at the end of the quarter. The most concrete measure of staying default alive. Everyone has a stake. Higher is better, obviously — but the goal isn't to not raise more; it's to not need to.
Cash runway (quarters) — how many quarters our cash lasts at our current burn. The cash balance question, framed against how fast we're spending. Relevant to everyone, especially anyone making hiring or major spend decisions. Longer is better. Default alive means we reach profitability before this hits zero.
TL;DR: Mid term, it's $100 million ARR by 2026, working backwards from there. Longer term, outcompete top-down competitors worth $50 billion. If we get that far, we'll have helped _tens of millions_ of engineers build better products.
Will PostHog sell?
What motivates us is building an epic product and company.
We're excited by:
Figuring out how far we can go
Helping engineers build products - reduce the need for product and data teams
Beating all the point solution competitors
Having customers buy _from_ us instead of us selling _to_ them
We're not excited by:
Selling the company for $1 billion – we think we can build a much bigger company by staying independent
$100M by 2026
We want to hit $100 million in annual revenue by the end of 2026.
We've set this since it's ambitious and keeps us accountable for some kind of financial output, but working backwards we can do it. We need around 7% monthly revenue growth to hit this.
Secondaries over selling
Everyone at PostHog has options in the company – that means they can be a shareholder. This keeps everyone focused on our long-term interests.
However, at different stages of the company's life, the value of each person's stock may be hundreds of thousands, millions, or even tens of millions of dollars. If someone doesn't have much capital but has $10 million in stock options, they'll start wanting us to sell.
As a result, we aim to let people sell some of their stock when we fundraise and once their stock has very significantly increased in value. This helps keep everyone focused on building something bigger and longer term. What we can offer will depend on what we can negotiate every time we fundraise, but this is our general philosophy.
People who work at PostHog have come from all sorts of different backgrounds – large companies, small companies, agencies, single-founder startups, and so on.
Their modes of working necessarily differ from each other and from PostHog, but we expect you to work in some fairly specific ways.
Being the transparent company that we are, we want to let you know about those expectations, because you can only meet expectations when you are aware of them!
Generally, our values are a great place to start, as is as the handbook page on culture, but here are a few specific ways to apply those values, and reinforce our culture as we grow:
Getting yourself up and running quickly
If you're new, the default goal is to be able to get work done autonomously.
This will require:
You know how to ship things in our environment and with your equipment
You get to know your team and have a sense of who can review your work
You get what the company, your customers, and your small team care about and needs to get done, so you can prioritize appropriately
Everything else is a means to this end! We often do onboarding in person to accelerate all the above. This usually takes around a week.
Ask for help, but only after you've tried first
If you've just joined us, there's a lot you probably don't know. That's okay! However, we _do_ expect that you try to help yourself. Here's a framework to use as a guide:
If it's one of our own products that we build and sell:
If it's in beta, it might be buggy or missing features. Definitely request/report them, but also figure out how to do your job with plan B and plan C if it won't be fixed quickly - this is what we generally call grit.
For engineers: try to figure something out by yourself for at least 1 hour, but don't remain totally stuck on something for more than 2 hours before asking for help. This time window should increase over time as you run into more questions that likely no one has the answer to, at which point it's time to dig in and figure it out.
If it's an external product:
We expect you to read the docs.
If it takes you more than 10 mins to figure it out, then ask someone internally.
You can also try self-serving an answer in our #ask-max Slack channel. It's trained on our handbook and documentation, so it's capable of answering both questions about internal processes and procedures, as well as product-related questions.
If you don't get the context you're looking for, try #ask-posthog-anything where team members are willing to point you in the right direction. Take a moment to explain how you've tried to help yourself and linking to resources. That saves others valuable time searching the docs again, or typing up a suggestion to do just that.
Don't expect perfection
PostHog is a startup. As solid as our stack / product / CI / dev experience is for a company of our size (super solid, tbh), it might not be the extremely-well-oiled machine you had at BigCo. If something doesn't Just Work, follow the framework above to get help.
We're all human – you shouldn't expect perfection for adhering to our culture, either. But you should help others learn how to stick to our culture, especially new joiners. We're all prone to occasional lapses, and it takes everyone on the team nudging each other in the right direction to keep us all on track. If you notice something happening all the time, take it upon yourself to make it better - see the next section!
Make it better
If you run into something you found that is confusing or needs fixing, we expect you to update the docs or handbook at minimum, and if you're keen then definitely improve the experience yourself. For example, CI is _everyone's_ job. If it sucks, fix it.
That being said, there is often a _reason_ why things are the way they are. That reason might be "because no one wanted to fix it," but it also might be "because it broke yesterday and we're on it" or "we've carefully considered this before and decided to make it this way."
We encourage you to step on toes, but don't be a bull in a china shop. Context is oftentimes your best friend – gather it up and keep it close.
Don't wait for someone else
We expect you to be proactive about answering questions in your domain, even very early on after you are hired – e.g., after the first week. Look in the code. Read the docs. Find the answer.
Being wrong is way better than being silent – if you are wrong, someone will correct you. If you are silent, you're not doing your job.
Similarly, if you need something to get done, you are responsible for making _sure_ it gets done. This is not your team lead's job or some other team's job – if you need it, you own it. _Most_ of the time this means doing it yourself (see section on helping yourself above); other times it means getting the right people together to understand the urgency and do it with you. But at the end of the day, the responsibility rests on you.
Have an opinion
You definitely don't need to have opinions on everything, but you should absolutely have opinions on your area of expertise.
If you don't have opinions on your area, you are realistically then just waiting for someone to tell you what to do, which is very much at odds with our autonomous way of working.
Opinions can take a bit to form, and that's okay – you don't need to have them on day one. But we expect you to start forming them rather early on, even if it's just on little things.
Look around corners
We expect you to be thinking through not only the one change you're making right now, but also how that change plays out down the road. What might happen with this code / process / thing in 6 months? Where will that leave my change today?
We do have more senior people on the team (both in industry experience and in their tenure at PostHog), but they shouldn't be the only ones looking ahead – you should be the primary one looking ahead for _your_ changes.
Don't assign issues to people
You can list and categorize issues. If you want someone to see an issue, @mention them and/or Slack them the link.
Don't yolo merge
Do not "yolo merge" – e.g., force a change to our website or platform without someone else checking it. This should _only_ happen in emergencies, _even_ for simple changes. It is _so_ frequent that we find issues. If you have _any_ doubt, get someone else to look at it first.
PRs > issues > Slack
Bias for action. If you can just pick up the work, do so. We want a culture of individual contribution _not_ of delegation.
It is fine (and encouraged) to pick-up side quests, or to deviate from your goals if you think you should. Especially if something is a quick fix, do it yourself as part of our value that _You're the driver_.
If you aren't able to make a change yourself, create an issue in GitHub. Avoid simply relaying to-dos in Slack as a means of getting someone to pick up a task. It's hard to track and easy to forget.
Do things as publicly as possible by default
For discussions, public repos are the best place. Then private ones, then Slack public channels, then Slack private channels or DMs. This is part of our _"Make it public"_ value, and helps with general context setting for the wider team, which means everyone can work more autonomously.
There are only a few exceptions to what we can't share publicly, for example if you are discussing security concerns, specific customers (for privacy reasons), revenue, or growth numbers (since these cause signalling issues with investors or competitors).
Internally, _everything_ can be shared apart from people issues – such as HR / personal (i.e., recruitment or health data).
Be proactive with community questions
Don't _only_ help the community when you're the person on support hero in your small team. No matter what your goals may be, if you can quickly ship fixes to real life user problems, then you are going to build goodwill, word-of-mouth growth, and a better product all in one swoop.
Most companies build their product with a particular user in mind. We build _everything_ around our ideal customer profile.
So when it comes to marketing and sales, we are optimizing for developer experience.
Why we're like this
We've met a lot of successful founders in our space who are full of regret, despite leading companies with well over $100m in annual revenue! The one regret they _all_ had in common was letting go of their growth engine (people recommending their product to each other) and getting focused on sales. They all wound up exiting. That's why they told us this stuff.
The way this pans out? As they got bigger, they gradually shifted from building for users toward building for buyers, hoping to optimize for revenue growth. Over time, that killed their word-of-mouth growth, which caused them to have to work harder for each sale. So they got more salesy, and so on. They became companies that focused on making a bunch of money _by_ building a product, instead of being companies focused on building a great product.
We won't make this mistake.
For us, marketing is creating useful content
Our is small. Way, _way_ smaller than our competitors'. Winning on volume of content is out of the question. So we'd better win on quality.
This constraint has worked out pretty well for us. Distribution is pretty easy when the thing you're working on is good enough to generate word-of-mouth growth – and this helps build an enduring developer brand.
We even hire full-stack developers into our marketing team to make sure we can cover the full depth needed in a lot of our tutorials, docs, and posts.
Things you won't find our marketing team doing: removing information from our website to increase conversion, focusing on paid ads, or letting colleagues ship content they aren't proud of.
We happily spend lots of money on our website
Most companies call it their "marketing website". You already know it's going to be crappy.
We treat our website as a product. With real investment. When we were just a couple of people, we realized that our website _is_ our sales team – since our users would want to self-serve as much as possible.
When we started out, we also realized that all our competitors had crappy marketing websites.
And, as with so much that we do, we get an _increasing return_ on quality. If we do things noticeably better than everyone else, then we're remarkable. That results in word-of-mouth growth.
We make it extremely easy for you to buy PostHog
Most sales teams do a bunch of low-quality cold outbound that harm their company's reputation and 99.999% of the time is ignored. And then once they've got you on a call, they pepper you with MEDDPICC questions before actually letting you see the product. Who knows, maybe 3 meetings later they'll share some pricing too!
We do things a little bit differently. Customers _buy_ from us, we don't _sell_ to them. It means we can instead invest our money in shipping more (and better) products, at lower prices than our competitors, to provide a sustainable advantage.
Fun fact: the total spend we have on marketing and sales per customer we acquire pays itself off within 3 months of them signing up for a paid plan. "Best in class" is considered to be one year...!
We make money from those that have it and like our products. We don't make money from those that don't.
How we do sales is based on the best experience for our Ideal Customer Profile
I cannot think of any harder group than developers to convince, via a cold-call or email, to buy software. We should focus on inbound.
All the other rules here are based on what we felt would be the best experience for an engineering customer, whilst allowing us to grow revenue in the long run.
Don't let pricing get in the way
Before a user has decided to buy the product, we should let them try it for free. Not only does this mean they can immediately self-serve without having to get budget internally, it also reduces the need for a large sales team to convince them otherwise. When someone is looking for a solution, they are ready to install it – but only if we can get out of the way commercially.
Once a user likes the product, we don't want to create a big decision around continuing to expand their usage with us. (For example, if we suddenly charged a large recurring price per month.) Instead, we charge a tiny fraction of a cent for each extra event they send.
Charge based on what people use, and give users control
Some users want to start with just a little usage of one product. Others replace five products with us. We should price to reflect this. We believe it's better to have a little extra pricing complexity to provide a much better value option, than an "all-in-one" price.
We charge by product _and_ by usage of those products that people need.
Beyond which products we use, we look for other ways to give users control, such as spending limits on session recordings.
These principles mean that they will spend less than they otherwise would have, _but_ it means they'll stick around. We don't want users to churn if they are unhappy with what they're spending; we want them to better manage how they use the platform.
Match the cheapest for each individual product
We can make it up by selling other products to the customer over time. This way, it's always a no-brainer to pick PostHog, we get as much word-of-mouth growth as possible, _and_ our single product competitors can't compete since they have nowhere to go.
Principles for dealing with big customers
The most important thing here is to remain focused on building the best product, not on what a single big customer needs.
We don’t care about losing deals. If we have to walk away from a deal because we'd have to compromise on these principles, we will. We can do this because we have a really strong growth engine with our ICP customers.
We don't contract deliverables, and we especially don't contract to provide deliverables by a certain date. This is because, on principle, a single customer is forcing us to build something.
We will build things for a big customer, as long as we are confident they won’t be the only user of that thing. Re-shuffling the roadmap a bit could make sense - but adding new things that others wouldn't use, doesn't.
Customers need to try PostHog before they expect us to change things. We love feedback from customers. We don't love big requirement documents from people that haven't used our product before.
We want our customers to spend their money on their engineering team, not on buying ten software products.
Here is the list of advantages we have and why they matter.
We can sell multiple products to the same people
So, do you want to buy ten products for $1k each or all ten for $5k? Or, better yet, each one separately?
We can pull this off because we're focused on getting in first – we don't follow the whims of whatever an enterprise may have.
No sales needed
Our competitors spend more on sales and marketing than product development. Nearly all our sales are self-serve _and_ 70% of our customers find us through word-of-mouth growth.
Multiple products, one dataset
We aim to be the source of truth for customer and product data. The products we build all work from this same dataset, instead of ten different vendors all paying to store the same data as each other – each with their own platform teams.
A technical audience who need _docs_, not technical support
Many of our products are traditionally sold to non-technical people. They need more help setting up SDKs or snippets. We work with engineers who simply need good docs. Writing and maintaining those (and an open-source codebase that people can inspect or even fix bugs in themselves) saves thousands of support questions each year.
Using open-source technology
We've often had second-mover advantages.
One of these is that we could use the latest open-source technologies, like ClickHouse. Many of our competitors have had to build their own databases. You can guess which is more efficient for storing tens of billions of events and serving millions of analytics queries. Better them than us!
User happiness is fundamentally important. How do we achieve this?
Building products that people want
First, someone internally will suggest an idea. Sometimes this will come from James and Tim, but it has, just as frequently, come from anyone else on the team.
If it requires a new team to build it – which it usually will – we'll start by hiring an ex-founder who is technical. We'll onboard them into the existing team that has the most overlap. This helps get them used to working with our codebase, as well as with the culture we look for from each team.
That person builds the MVP, and the only goal is to figure out if anyone will use it. With some products, the MVP may have more scope if we feel especially confident. Once the new product is in a non-embarrassing state (that won't harm our brand), we add pricing to it and put it on our website. This drives more demand. At this stage, the goal is to get the product to product-market fit in PostHog's platform, which means working with customers until we have five delighted, paying customers.
Once all this is done – which we'd expect to take a few months – we can start to innovate. This usually means some kind of platform play, such as extending the product to enhance everything else we're working on, or shipping another new product that would work well with it.
Engineers talk to users and provide support
You should be _as close as possible_ to your users, feeling whatever they feel, so you have as much information as possible to make the product great.
For established products with a lot of usage questions (how do I create an insight that does X, for example), Customer Success helps with support.
Before a new product is even made, we'll add it to our public roadmap. Once it ships, we'll use our own tools to get customer interviews, feedback, and data, and we'll always aim to "close the loop" with users - coming back with: a pull request, a GitHub issue they can follow in the open, or an explanation of why we can't make a feature they've asked for.
This means the product improves, users are impressed and recommend us to others, _and_ we show users that we listen, encouraging them to keep going through this loop with us, faster and faster.
Atlassian – multi product, inbound, dev centric company, totally dominant in their categories, scaled way beyond $1bn
AWS – multi product, pricing model, UX (!)
Pager Duty – pricing model, product led growth
Hubspot – built a $25bn company despite competing with Salesforce
GitLab – while we run _very_ differently and have a different business model, we were inspired by their transparency
Sentry – branding and bottom-up approach
Algolia – developers doing marketing
GitHub – enterprise go-to-market is 200 developers forcing their company to buy us
Handbook
Like many things at PostHog, this handbook has scrappy origins.
Tim and James were planning on launching on Hacker News, and wanted to look as mature as possible. We felt that few people would want to use a flaky new startup's product seriously. So we asked ourselves: how do we signal that we're mature?
We looked around at some big, boring companies and realized they all had huge footer sections on their websites with lots of links! How do we produce a lot of content to add to our footer when the product, at that time, was so simple? The answer: we should write up how we want to work.
Once we started writing the handbook, we realized it would transform our company. Every team member, and even strangers on the internet, could suggest changes. If you're doing something in public, you're going to think it through better. Ultimately, it made us treat the company as our product.
It's a classic example of getting information by doing, rather than by planning too carefully.
Timeline
January 2020: The start
PostHog was founded by James and Tim on January 23, 2020.
We started working together on a startup in August 2019. Our first idea was to help engineers manage technical debt. It didn't work out, but we realized the power of treating growth as an engineering problem. We also knew that many engineers struggle to understand the impact they have on the people who use what they build.
There are plenty of product analytics tools out there, but all the alternatives are SaaS-based. While they're powerful, they can be frustrating for developers. From our perspective, these tools can be problematic because:
We don't want to send all our user data to third parties
We want full underlying data access
They don't give you choice and control over pricing
February 2020: Launch
We got into Y Combinator's W20 batch, and, just a couple of weeks after starting, realized that we needed to build PostHog.
We launched on Hacker News with our MVP, just four weeks after we started writing code. PostHog was our sixth idea – we had been pivoting almost once a month for half a year. Boy were we relieved!
The response was overwhelmingly positive. We had over 300 deployments in a couple of days. Two weeks later, we'd gone past 1,500 stars on GitHub.
Since then, we've realized we weren't just onto a cool side project, we were onto what could be a huge company. It turned out there were a lot of developers who liked us who wanted a better choice, built for them.
April 2020: $3m seed round
After we finished Y Combinator, we raised a $3.025m seed round. This was from Y Combinator's Continuity Fund, 1984 Ventures.
This was a major update – PostHog started providing ClickHouse support. Whilst we launched based on PostgreSQL, as it was the easiest option to ship quickly, this enabled us to scale to billions of events.
November 2020: Building a platform
We realized that our users, whether startups, scale ups or enterprises, have simple needs across a broad range of use cases in understanding user behavior.
We're now focused on achieving strong product-market fit with our target segment in 2021.
Our team had grown to 25 people in 10 countries.
September 2021: Product-market fit achieved for PostHog Scale
We achieved product-market fit for our open-source product and PostHog Scale.
Our revenue quickly rose as a result. Now we needed to optimize it.
We were 30 people in 12 countries.
January 2022: Sales comes from our team, not our founders
We hired two Customer Success experts dealing with all inbound requests. We hired two more engineers, since most questions customers have are technical.
December 2022: 6x revenue growth
We had a fantastic year. While the tech market crashed, we grew 6x and reached millions in revenue, with a sub-two-month CAC payback period. We set $10m ARR as our next goal, with a gross margin of 70% – both of which should mean we've got all the metrics needed for the next fundraise.
We optimized revenue growth by implementing a product-led CRM for our customer success team, adding to our content team size, and creating a two-person growth engineering team. These teams all make a big difference!
We deepened all of our product areas significantly – we frequently win deals as a standalone session recording, feature flagging or experimentation tool. Session recording usage started to match product analytics usage.
Our infrastructure is far more stable and scalable – much more of it runs as code. We can now offer EU- or US-based hosting for our customers' data.
We're now 38 people in lots of countries. We're not adding lots of headcount over the next 12 months, though. We're staying lean and letting revenue continue to rise rapidly.
February 2023: Focus on mass adoption
We're doing well at monetizing high-growth startups due to our optimization work, averaging over 15% MoM for the last six months.
We've decided to double down on mass adoption of the platform in high potential startups instead of focusing on enterprise. Simply, this will better help us increase the number of successful products in the world. As a result, we've removed support for paid self-hosted deployment and are doubling down on our open source and cloud projects. We have released a free tier of PostHog.
We went from "product analytics with some extra stuff thrown in" to "Product OS" and started charging for session replay separately.
In the product, we're working on making the experience slicker, and we have plans for a standalone quality CDP in Q2.
March 2023: Decided to ship a warehouse
For a long time, we were happy competing with lots of $1-2 billion companies, each providing point solutions. We felt our market was just the sum of all of theirs.
But we kept seeing companies streaming their PostHog data to a warehouse - such as BigQuery. We even lost our then-largest customer for this reason - where their source of truth became their warehouse instead of PostHog.
So we decided we would ship our own warehouse, enabling us to remain the source of truth for customer and product data. This would let us offer a better integrated service to our customers, and meant we could work on a bigger challenge.
August 2023: Growth continues
We've doubled revenue so far this year without any increase in headcount. We've hit 15.7% MoM for the last 12 months. Our CAC payback is now just five days. Our numbers are exceptional. We even discounted several of our products. We've added ten extra roles and will be profitable in around a year.
We have user surveys and the data warehouse in private beta. Other products are being positioned as first-class products of their own (AKA "The Great Unbundling"). This means we can make it clearer for new folk to get what we do, give more ownership (which means more speed) to our own teams, and we can compete on commercials more effectively.
Our infrastructure has become pleasingly stable. The biggest challenge is scaling our data pipeline, and making sure we give as much responsibility as we can to each small team owning each product for their own pipelines, where rational to do so.
October 2023: Winning the internet
We are often mentioned as an alternative to product analytics tools.
We are winning the internet when we get more of this for our _other_ products. We don’t have to win everything, but we need to get into the comparison each time. This is _starting_ to happen, but to win the Internet, we need to see this happening daily.
Multiple products are early like the warehouse, ETL, surveys (used a lot but not paid), feature flags and experimentation (first revenue), CDP (pipelines being rebuilt, webhooks next), notebooks, and web analytics.
There is a lot of supporting work needing to be done. This includes:
Helping teams with their per-product onboarding and growth experiments, infra, ingestion, dev tooling, sales, support, and marketing.
Promoting each product in its own right (i.e. through what we cover in marketing).
Keep nurturing the content / community growth, i.e. newsletter, and the /posts concept.
January 2024: Well, that was good
That was quite the year.
We wound up quadrupling our revenue, but only increasing our net headcount by three people in 2023. Last year, we validated that we could get multiple products to product-market fit (like feature flags and experimentation).
We built more integrations between our products like HogQL, notebooks, CDP, and the data warehouse.
Now, we are doubling down. We shipped a lot in Q4 2023, but every product could be improved a lot. We're caring about the craft of our products:
Major missing features vs competitors
Scalability/stability
Developer UX
Talking to users and incorporating their feedback
Nailing support for your product - fixing things
Products are not limited to engineers working on the app. It includes what customer success, marketing, and ops are working on. Everything can be considered a product.
Each team should be aiming to feel proud of what they've built by the end of the quarter.
April 2024: We're now the default for startups
54% of the first Y Combinator batch this year adopted PostHog.
Tim and James turned up to talk at batch events and we were surprised at the number of groupies wearing PostHog merch – our merch is really cool now, we've gone way beyond the logo-on-a-black-t-shirt standard.
As far as we can tell, we're in the top three products used by YC companies.
We've started doing growth reviews for almost every product we have. We run through each product's metrics (revenue/usage/support/performance) and feedback / reasons for any churn that has happened, so we can truly treat each small team like a startup. This session is designed so the engineering team leads may choose to reprioritize work, or not.
October 2024: 100,000 customers, and speeding up – more products and more people
We hit 100,000 customers either paying or free, and over a quarter of a million users. We've started hiring a lot faster as growth has continued this year. We're now 65 ish people with ~9 products.
We've added some people in sales, but it is strictly (i) sales assist, talking to people that have asked to speak to us, and (ii) cross sell to existing customers.
We've hired a sales engineer super early (Mine, she's awesome) and we're really working on the culture in this team proactively.
Strategy-wise, we're just leaning into our basic three principles, which we're seeing more and more evidence are working well:
All the tools in one – We want to go wider still. We think we can provide _every_ piece of SaaS that startups use, starting with those closest to customer data. We want to expand to a customer support product, the marketing and sales stack of tools too.
Get in first – Don't go upmarket. We're closing enterprises regularly, but we're not trying that hard here. We're trying to stay away from complex migrations for users who use many products already.
Be the source of truth – Our own data warehouse is now available and very popular.
Revenue is in the low $10s of millions of ARR. We're very strongly default alive and will struggle to not end up profitable next year. Every time we get close to being profitable, we start speeding up hiring.
Revenue growth is fast enough and we're getting so many unprompted offers for investment (that we aren't taking) that money isn't really a meaningful constraint anymore. Whilst we have a great grip on each product's individual performance, our understanding of cross sell is a little weak, so we're working on that now.
Our marketing is getting weirder. It's more and more fun. We've commissioned a puppet, coming in January. Watch this space. Our newsletter, Product for Engineers, now has 20,000 subscribers and it's growing fast.
We're realizing that the more ambitious we are, the easier it gets – customers get excited, investors get excited, employees get excited. We can now see a real path to being a $100bn+ company and changing how software teams work industry-wide.
December 2024: Cashflow positive
We ended the year cashflow positive, which we mostly didn't plan for. The all-in-one thing just kept compounding – people show up for one product and end up using four. ~80 people, ~12 products, and still no real desire to hire our way out of problems. Still default alive by a comfortable margin.
February 2025: PostHog AI, and AI observability is born
PostHog AI went from a thing we'd been tinkering with to a thing customers actually use every day. We were the first heavy users ourselves, which is also why we built AI observability – we needed to watch what PostHog AI was costing and how people were using it, and we realized every other AI team had the same problem, so we shipped it as a product!
June 2025: $70m Series D, led by Stripe
$70m Series D, led by Stripe. It started with a tweet – Patrick Collison said our website was "very well done" and ~18 months later that turned into a round at a ~$920m valuation, with YC, GV and Formus joining. This raise roughly doubles both our valuation and money raised.
Around here we stopped calling ourselves an analytics company. We're (almost) everything you need to build a successful product, with a plan to automate the whole stack with AI.
October 2025: $75m Series E
We raised again – a $75m Series E led by Peak XV at a ~$1.4bn valuation. That technically makes us a unicorn. Total raised since 2020 is ~$194m, and we're ~140 people now. We also offered employees secondary, which we wrote about.
Early 2026: PostHog Desktop
~200 people and a product list too long to keep reciting! PostHog Desktop was probably our biggest launch yet.
Our vision is now to make your product self-driving.
_You're the driver_ is one of our values. 90% of a startup's problems are solved by just having the right group of people in ~~the building~~ Slack.
Personality traits that cause people to be successful here
Genuine builders. Some people do jobs for the money. Those that have truly found their passion are _far_ stronger.
Easy to work with. People who are low ego, flexible, energetic, and upbeat will raise those around them. We often, but don't exclusively, hire those with more experience since it's easier for them to contribute meaningfully. Things can and do get _very_ hard here – whether it's scaling, shipping complex products, handling a stream of support requests, or trying to ship something that touches multiple teams. We need those who won't get disheartened, and will collaborate, iterate, and ship their way out of anything. We proactively reward those that do these things, not those that self-promote.
Will join us on the journey. Some people are inspirational to work with – they lift others up. We have a _huge_ opportunity at PostHog, and it often feels like we've caught lightning in a bottle. Anyone joining the company at this stage could make this the last job we all ever need. We want people that will push to get this done, for each other's sake. We don't hire mercenaries. We need to feel people here are producing the best work of their lives.
Drivers not passengers. Proactive people that can fully own projects and get them done (or make sure they get help) are what we need. For many of our roles, while it isn't a common job title, internally we have the concept of product engineers – people who can take high-level requirements, decide what to build, do so with customers, and keep iterating.
Great (and terrible) reasons to join us
Let's start with why you _should_ join:
You want to ship an epic product with incredible people.
You want impact and autonomy, and work well with uncertainty.
Why you _should not_ join:
Getting our brand on your resumé. If you join for self-promotion, you (ironically) won't do well! Apply to a bigger company who can give you a clearer career ladder.
Getting a pay rise. We pay generously, but you'll need to _love_ building to be happy here. You'll need to be here a long time to get the real upside from options.
Mainly wanting to lead others. Reluctant managers are often the best. We don't pay more if you manage others. We want people to lead by example by doing an exceptional job of individual work.
A small group of stronger people and compensation
When we raised our Series A, one of the first things we did was to make sure we didn't lose our existing team (at least for pay reasons!) _before_ we added more people to it. This is still true today – we proactively review everyone's pay three to four times a year and increase it if people have leveled up.
When it comes to churn due to pay, fairness is just as important as the absolute level. We do this in line with a transparent pay system that we even make public. We aim to pay generously and fairly between people.
For options, we offer the most generous terms possible as it feels like the right thing to do. We think this makes it as likely as possible people can see huge upside if we are successful (making it easier to raise _and_ more realistic that people will actually get money from them). That motivates everybody.
One of the hardest parts about building a high performance team, is letting people go when they aren't performing. We are decisive and do this faster than many others would. We offer four months severance when we let people go for performance reasons to give people more time to move on – and so it's easier for us to make a change if we need to.
While we will give direct feedback, if we don't see this being responded to quickly ahead of letting someone go, we will part ways, so people can find a job they are better suited to, and so we can find a team member better suited to the job. The end result is that everyone on the team is contributing meaningfully.
Growing the team beyond hiring
We hire insanely talented people to build products ourselves, but sometimes acquihires or acquisitions help us move faster by adding engineering capacity and expertise. These situations are rare so we’re often reactive with these - but we’ve set clear principles to make sure we handle them consistently.
Acquihiring
This is an efficient way to onboard great engineers without all the complexity of an acquisition. For us, an acquihire means closing down your old company as you and your team join PostHog purely as talent, which we will match up with our product teams where it makes sense.
Everyone goes through our standard interview process. There are no exceptions, even if you join as a group. Coua Phang will organize each interview stage with your team members individually so everyone goes through the process in the same timeframe.
We do not pay for acquihires - we just hire the people. Sometimes we’ll pay a premium if it makes hiring multiple people easier.
For YC founders, we may sometimes pay a premium. This is treated like additional compensation that vests over the standard PostHog equity schedule (not a lump sum upfront).
For engineers, we pay our normal salary with the possibility of a discretionary bonus after probation.
If you quit PostHog to start your own company, we won't acquire or acquihire you back (though former employees-turned-founders are welcome to apply and join again under normal hiring processes).
We never acquire companies bigger than one small team.
Acquiring products
IP inside PostHog
By default, we are not interested in acquiring IP. If we can build something ourselves, we will. The only exception is IP with deep technical value we don’t believe we can replicate internally.
If we want a product inside PostHog but lack the domain expertise, we might acquire the team behind it - with the expectation your team rebuilds the product natively into our platform and migrates users. This would be the case where, without domain knowledge, projects might take us an unreasonable amount of time to ship or get deprioritized. Even then, we will only do this if the price is right. We generally won’t pay a premium as the value comes from the team’s expertise, not the legacy product.
IP outside PostHog
We do not acquire products that sit completely outside our platform (e.g. an IDE). Our strategy changes often, and owning something disconnected would create pressure to keep it alive.
The exception would be if the product technically lives outside the platform but directly enhances PostHog’s value (e.g. a new way to use PostHog data inside a terminal), where we may consider an acquihire or paying a premium.
Existing customers
We generally do not want to convert any existing customers you have into PostHog customers directly. They may be different from our ICP and put pressure on the team to build something different than what we would otherwise plan to offer.
Your customers are of course welcome to sign up for PostHog and use our existing products and new ones once they are launched, but we don't make promises to these customers about features or support for their existing workflows.
Acquisitions for marketing
We are not interested in acquiring companies just for their audience or marketing. That’s a distraction, and we’re confident in the strength of our own marketing team. If we want more marketing, we’ll invest in it directly.
These are the principles for the behavior we care about.
You're the driver
We hire people that are really great at their jobs, and get out of their way. There are no deadlines, very minimal coordination and you won't have us breathing down your neck.
In return, we ask for extraordinarily high ownership. To succeed you need to be intrinsically motivated.
Great people at PostHog can take very high level direction, and ship quickly to find out as quickly as possible if our plans can survive contact with customers!
Being the driver means getting stuff done _yourself_. We've had non technical people create hardware products, coding in C++, we've got designers that will write Tailwind and React - rather than just create the file in Figma. Our salespeople answer technical questions without engineers as backup - and if they don't know the answer, they educate themselves more deeply for next time. We like people to go full stack instead to reduce the number of dependencies.
Building a company isn't a solo sport. We're Ted Lasso (although I've not watched to the end, I hope they win) not Wolf of Wall Street). We expect you to take high ownership of the _company_ and _your team_ being successful. This means when you see something wrong, you fix it or give direct feedback - it's not ok to watch your colleagues fail.
Internally, a culture of transparency looks like managers telling you to raise feedback directly with the person it concerns instead of solving problems for you, it means changing teams around in public Slack channels, it means detailed financial information, live updates on fundraising and board slide access.
Being transparent externally helps us achieve our mission - we write about what we're working on so the world can take advantage of the lessons we're learning, and so they know how to work with us better. Knowing that thousands of people will read our handbook pages forces clearer thinking. And, for free, we can build trust in a way other vendors just choose not to.
There are a few things that we are internally transparent about, but that should not be shared publicly. Anything related to our company financials is strictly confidential and should not be shared externally, including our current revenue numbers, ACV, burn rate, etc. Anything in a public press release is fine to share!
Do more weird
So much about how we work is different.
Weirdness can just be the absurd lengths we are willing to go to. It can mean redesigning an already world-class website, for the 5th time. It can mean shipping _literally_ every product that relates to customer data, with teams of just one to five people competing with $200bn+ companies, successfully.
We aren't weird for the sake of it. We want the company perfectly optimized for our strategy. We have small teams when very few others do, because we are going to build 50+ products. We post billboards of our founders' faces because no one else is brave enough thus it stands out. Even the little things - like having _pricing_ on our pricing page!
_Why not now?_ means getting things done _proactively_, _today_. You do not need consensus to do things – focus your energy on shipping what's most valuable for our customers and the company, then take ownership of making it happen, not on getting buy in from others. You certainly shouldn't wait until next quarter if your new idea makes more sense to work on than your previous goal.
We have learned the clearest lessons at PostHog by doing things, not from hypothesizing about them. If we're debating doing something, just trying it is the best way to learn. Doing more planning is rarely the right way to figure out if something will work, doing the thing is the answer by default here.
Sometimes this approach might mean you ship something that others don't agree with. You will need to be willing to throw away work sometimes, because the upside – not needing to get lots of approval to do stuff and being able to take more bets – means we all move so much faster that mistakes are a lot less costly.
_Why not now?_ doesn't just mean shipping huge product features. It may mean diving into a small customer support issue quickly to delight them – this is one of the main reasons people recommend us to others.
Optimistic by default
We have a lot of control over our direction, and we've been very well served by shooting for the best case scenario every time we make a decision. You'll hear us say things like "play offense, not defense", "how do we 10x this", "how do we win in 10 years' time". Aiming for the best possible upside and sometimes missing is much better than never trying.
This is especially true when we think of new ideas - any big new thing can sound pretty silly at first, almost by definition. You'll hear PostHog war cries like "we haven't built our defining feature yet, maybe this". It never is, but that's _exactly_ the point. What we've already done is less important than what we do next. If we make new ideas painful to share with others, they'll eventually stop coming.
At a simple level, we want to be surrounded by people that are enthusiastic, passionate and happy. PostHog is a group of people working together with a shared goal. A positive, encouraging atmosphere simply means everyone is going to have a lot more fun and will be able to stick around for the full adventure here.
Put more grandiosely, PostHog is wildly ambitious, and with that, a level of optimism is _required_. You cannot change the world without first _believing_ you can change the world. People not believing is probably a bigger deal than people not being able to.
Providing all the tools in one is a core part of our strategy.
Shipping them in the right order is key to a fast return on investment from every new product.
How we pick new products
Until products are built and launched, it's hard to predict which ones will do well. Because of this, we want to be working on a mix of new products at any given time. Some we're very sure will do well, others might be more of a bet with a potentially big outcome. This guidance is therefore less prescriptive that it could otherwise be.
Products we know will work well if we ship them:
Products engineers use at all company stages
Think error tracking or feature flags. The persona doesn't change as the company gets bigger.
Especially true if it works for a 2 person startup, because that means we get in first
Products that are in extremely fast growing markets
Think AI Observability, MCP
Products that are very easy to integrate for our existing customers.
For example, users can enable the product in PostHog without needing to make a code change, or products that built on top of data that people are already collecting in PostHog
Products that _you_ are excited to build.
People pursuing their interests get more done, go much further, and execute to a better standard.
Products that our customers are asking for
Products we're less excited about building:
Products where the ICP quickly changes to someone outside the product team, especially teams far removed from engineering
For example, a CRM. We'd be more excited about building a customer support tool, as support often is a task that involves engineering.
Products that lean into 2020 style products, not 2030 style products
Think lots of UX for humans to use
How new products get built
Sometimes the Blitzscale team will decide a new product needs to be built. They'll find someone internally to run it, ideally someone who's been at PostHog for at least 6 months (we tried getting new people to ship new products, but they often struggled to ship quickly).
Other times you might have an idea for a great product we should build. In that case, use the New Product RFC template. You might choose to hack together a prototype of the product to demo and show off, which you should do! Blitzscale only needs to get involved if you want to start working on this product full time. At that point, we are choosing whether to invest a pretty serious amount of money into launching it, so we want to get that right.
The best products are often ones that not everyone thinks is a good idea before launch. For example, Tim was against building Session Replay, and it's one of our most popular products. To make sure we take big bets, _any_ Blitzscale team member can OK a new product being built, even if other Blitzscale members disagree. That Blitzscale person will be the one who the new team reports to. This way we avoid consensus stopping us from making big bets.
See our roadmap for what we're currently working on.
How to pick which feature within an existing product to build
In the early days, you'll be shipping the main few features that your category of product has as standard. In product analytics, this would be something like (1) capturing events, (2) trends, (3) funnels, (4) retention, and (5) person views.
Once this is done, you'll get a stream of feature requests and bug reports from users. You can't go too wrong if you listen to these and, by default, prioritize those that help us get in first, first. For example, with our data warehouse, we picked multi-tenant architecture because we wanted startups to be able to get started for free or very little initial cost - even though a single tenant approach would have given us an MVP faster. Sometimes, if sales are asking, you may choose to prioritize a feature for a big customer earlier, but you should never do this when you wouldn't have shipped it at some stage anyway. However, be cognizant of how often you do this, and whether now is the right time to be shifting your persona focus.
Later on, you can then _innovate_ several ways:
unpeel your product - you start with the software, then offer API access, then offer better API access, then infrastructure (if you are feeling brave) - by default, start with this reminder: charge for API access appropriately, speak to Annika for help figuring this out. Doing this increases our luck surface area (it means your users will find new use cases).
features more specific to our ICP (make it more engineering-y, more customization, more power)
integrate it with our other products (either feature them _in_ the product you just built, or feature your product in _theirs_)
We build for the people building products in AI-pilled software teams at any scale.
We want to be the first tool that technical founders go to when they start building their product.
| | AI-pilled software teams | | --- | --- | | Description | Ambitious (i.e., they want to grow a lot) software teams that are either just getting started or already have product-market fit and are quickly scaling up with new customers, hiring, and adding more revenue. They believe in an AI-first approach to building and are already familiar with the standard AI tools. | | Criteria | - They have 1 to 500 potential PostHog users, but the company itself could be anything from one employee to thousands<br />- Has lots of revenue or aims to raise or has raised from leading investors<br />- Not hobbyists or cost-conscious bootstrappers, basically| | Why they matter? | - We believe AI-pilled companies will outperform non-AI-pilled companies <br />- We're able to efficiently monetize them<br />- Very quick sales cycle<br />- They act as key opinion leaders for earlier-stage startups and slower-moving companies<br />- They have strong opinions on what they need, which helps us build a better product | | Examples | PostHog any time from during YC to IPO, Supabase, ElevenLabs |
Our current Persona
Persona is the job title or role of the person actually using a product in PostHog.
PostHog's initial adoption inside an ICP should come from an _engineering_ persona most of the time, simply because engineers exist first in startups. This persona can include technical founders. The more we appeal to engineers at the earliest stages of their startup's life, the more overall growth we will have.
We should in general go _very_ hard on making sure we have excellent coverage of any needs an engineer has in trying to build a product first.
Once we're in with engineering, we spread to multiple personas. AI tools have led to the emergence of non-engineer builders inside software teams. These are product, support, or marketing people who have realized they _can_ now code. They are unlikely to ever be as technical as an engineer, but the tools and problems they can tackle now overlap. Some light touch work can dramatically improve PostHog's usefulness for these other teams and we should be willing to do that when its obvious. For example, PostHog AI is used by 25% engineers, 25% founders (often technical), and 50% across other roles. An anti-goal is to completely ignore the 50% of other roles.
The anti persona: we are unlikely to build products for people furthest from product, such as those in finance, ops, or recruitment. There simply is much less need for customer data in those teams, we don't have any natural advantage here.
Equip every developer to build successful products.
Why is that our mission?
Since the beginning, we've believed that engineers should be way more involved in making product decisions than they've been historically. In order to help them do that, we've built a collection of products for engineers.
Similar tools to the ones we've built have existed for a long time, but they were always built with other users in mind. By building things like product analytics, session replays, feature flags and a data warehouse for engineers first, we give engineers the ability to make product decisions themselves. This massively increases the speed at which engineers can make good decisions.
The other way PostHog helps engineers is by combining _all_ the tools they need into one product. This avoids a ton of work integrating and linking up various products, both when integrating and ongoingly.
We try to help engineers from the very beginning, when their product is just being built. We do that by having generous free tiers, and no need to talk to sales to get started.
Our strategy
1. Be the source of truth for all product context
Building a successful product is hard; doing so when you don't understand your customers is even harder. It's wild that no one has already provided a complete record of everything engineers need to ship products. This has happened because the entire industry has focused on integration instead of consolidation.
Traditionally, as companies scale, their data warehouse becomes the source of truth, and non-warehouse native tools (like product analytics) become less relevant as engineers lose trust in the data they collect, simply because they are misused and divorced from the source of truth. Every company winds up with a huge mess of data spaghetti, with their business logic still spread across dozens or hundreds of tools.
We provide developer infrastructure - by providing _every_ tool engineers need in one place, we can:
Enhance the utility of all the products when used together by engineering teams
Increase trust in data by eliminating complex data stacks that engineers have to navigate
Automate everything better than anyone else can, by using AI across this wider context
Continue to provide all the products engineering teams need as they grow
2. Provide every tool engineers need to build successful products
We aim to offer every tool engineering teams need to debug, understand, and improve their products. From session replay for debugging to feature flags for safe deployments, we help engineers ship better code faster.
We can then get our AI to work across all of them together, whilst making every individual product cheaper than the rest of the market - since we provide so many we can charge less. This means engineers get better products at a fraction of the cost of piecing together solutions from multiple vendors.
3. Get in first
Since developers exist first in a startup, by getting in with them early, we are naturally upstream of every other tool they might have considered using. Although anyone can pick up our products (and lots of mature companies certainly do), this means we can best deliver developer infrastructure to early stage companies, and so should focus there by default.
_Once_ we land a customer, we then let them pull _us_ upmarket as they grow. But not before. We don't want to hire a big enterprise sales team and go upmarket before our existing customers are there. This keeps us efficient and able to stay focused on building products that engineers actually want to use.
4. Automate the iteration process
Because we have all the context on both users and the product, we can automate large chunks of the cycle of shipping -> observing -> iterating.
Secret master plan
Ship every tool and all the data that engineering teams need to understand their product and users
Use that to speed up the cycle of shipping -> observing -> iterating
Part of our strategy is to provide all the tools in one for evaluating feature success.
Speed
This means we need to ship a _lot_ of products into one platform. We can see a need for at least 20. That's a lot of engineering work.
After we'd started hiring, we asked ourselves a question – how could we structure the company to optimize for speed above everything else?
I happened to go to an excellent talk by Jeff Lawson, the CEO of Twilio. It made me realize I should be asking, "Who ships more per person, a startup or an enterprise?" Clearly the former. So we structured PostHog like a series of startups.
Small teams
We decided that we should split PostHog into a series of small teams, each working like its own startup, fully owning at least one of our products.
As with any startup, the principles that govern these small teams are:
Can decide what to build within their own products
Can ship without outside interference as far as possible
Should work directly with its own users (until it has hit product-market fit within PostHog's platform)
Should be small
Minimal hierarchy
We deliberately keep the number of levels and people managers at PostHog to the absolute minimum we can get away with. This maximizes team member autononomy _and_ increases shipping speed, as you don't need to run things past a manager or wait to get something signed off the vast majority of the time.
This means that, if you need something or need to flag an issue, you are strongly encouraged to communicate _directly_ with the person or team working on the thing you care about. We want to avoid people going up and down the org chart via managers as much as possible. 90% of the time, this approach means you'll get what you need faster. 10% of the time, this might cause a tiny bit of confusion if what you are asking for doesn't beautifully align with that team's objectives. We believe that trade-off is ok - we'll figure it out.
We have a tiny exec team - this is what they are responsible for:
Set the overall direction and strategy for PostHog
Decide which products to build
Make key people decisions (e.g. who to hire, pay, disciplinary issues)
Ensure complicated cross-team initiatives run smoothly (e.g. pricing)
For _everything else_, you and/or your small team should be able to decide this or talk directly to the teams involved. This includes deciding which feature to build next within a particular product. We trust you to bring in the right people as you feel appropriate, relative to the scale of what you're doing.
PostHog is _not_ a good place for managers who are territorial and prefer for all communication to go through them for 'efficiency'. Over time, doing this would undermine autonomy and cause our best people to quit!
Titles based on what you do
Companies give out titles to people that primarily show how senior they are.
This means titles, as adopted by the wider world, imply that _seniority_ is more important than what people do. We do not believe that seniority should determine how decisions get made - people should own decisions in their area of the business. We trust every employee to fully own their area of the business.
When you are prompted to put your title somewhere like LinkedIn, please just say as clearly as you can what you are focused on. Please do not focus on how senior you are. Feel free to be weird with it.
In other words, instead of your title being "Senior Engineer at PostHog" (which is not a title that exists at PostHog anyway), it's actually "Product Analytics Engineer at PostHog."
Goal setting
When you build a startup from scratch, you are in an existential crisis. One day you might be building a gym, the next day a software product for accountants. The problem changes. At PostHog, we give each small team a product to build. (James and Tim focus on _which_ products we should build, as they often need sequencing.)
Once we had product-market fit, and we had reached 15 people or so, we realized we needed to set some kind of goals. We started by using OKRs as they're pretty standard.
However, one of our engineers one day told me, "I realized I needed to change my objective. Then I started rewriting my OKRs into the handbook. I realized I was spending time stressing about the wording of it, which was going to have zero impact on what I knew I had to build." That seemed silly, so instead we make a point of calling them just "goals". We intentionally don't sweat the wording.
Another best practice we choose to ignore is "goals should be output driven". It sounds great in principle, but what is going to happen after a product team, which is nearly every team here, sets an output driven goal like "improve activation by 20%"?
Either the team will decide on some things it should build, or they won't manage to figure out what to build to do this. In either case, if a team knows what it should achieve, it should then figure out which things it needs to ship, and write those things down instead. It's clearer, and clearer is faster.
And if that list turns out not to be helping our metrics? Switch the goal to a new thing.
We know we've got to be quick to build all the tools in one. So we better have a world-class engineering environment that lets us build everything. How do we do that?
No product management by default
Engineers decide what to build. If you need help, our product managers (we have four today) will give you coaching.
If an engineer at PostHog believes they should work on X, they can build X. We'd prefer you ship ten things quickly (and make a couple of mistakes) than plan too much. You will tend to gather more information by _doing_ rather than _planning_.
There are _some_ exceptions - for example, where we need to work on architecture, but we leave it down to you to decide when you should plan more or just get started.
Transparency is fuel for autonomy
In nearly any company, having each engineer decide what to work on would fail. Why? They simply would lack enough context over what the company is aiming for, or what everyone else is up to.
PostHog is exceptionally transparent. You're reading our public handbook after all.
It starts with hiring
Finally, we hire people we think will flourish in an autonomous environment. We often hire people with broader rather than narrower skill sets, who are more flexible. They've often started (and often failed) their own startups. They're low ego and flexible. They're builders at heart who love innovating and working like this.
One of the things we've learned is the very strongest engineers are usually those who want autonomy the most, and so freedom is a great way to attract and retain world-class talent. Now that we're lucky enough to have people like this already here, people see PostHog as a destination company, accelerating further our access to some of the best people in the world at what they do.
A high percentage of our employees are engineers
If we want to ship a lot, we need to figure out how we can have most of capital go into engineering.
We have zero outbound sales, and a hyperefficient go-to-market, largely driven by self-serve. Since we focus on engineers, we have less customer support and set-up handholding than all our competitors.
80% of the company are shipping product.
Deep work
When you're doing engineering, you're in the business of building up large, abstracted models in your head of how the code works. That takes time and requires focus. Doing a ton of meetings is a great way to screw this up.
We therefore have meeting-free days every Tuesday and Thursday. We encourage you to call it out if things are going into your calendar on these days. Since we also are all remote, these usually give you lengths of uninterrupted time to get your work done.
The only exceptions to this rule are for customer success and recruitment, who may need to have external meetings with users or candidates on these days in order to do their jobs.
We run promotional campaigns with partners (e.g., newsletters, influencers) that offer exclusive benefits to their audiences via coupon codes.
How it works
Campaign setup: Campaigns are created in Billing Admin with a strategy defining what benefits are granted (e.g., free addons, increased limits, credits)
Code distribution: Coupon codes are exported as CSV and shared with the partner for distribution to their audience
Redemption: Users visit /coupons/{campaign-slug} to redeem their code (requires paid PostHog subscription)
Expiration: Benefits can automatically expire after the campaign period (e.g., 12 months)
Onboarding flow integration
When new users sign up via a campaign link (e.g., posthog.com/signup?next=/coupons/lenny), they're shown the coupon redemption page early in onboarding:
User signs up with ?next=/coupons/lenny query param
After signup, they're redirected to /onboarding/coupons/lenny instead of directly to /coupons/lenny
They can claim the coupon or skip and continue to product setup
After claiming/skipping, they proceed to the normal onboarding flow (use-case selection or products page)
This ensures new users see the coupon offer before diving into product configuration.
Note: Existing (already onboarded) users bypass this and go directly to /coupons/:campaign.
Example: Lenny's Newsletter
When launched, our partnership with Lenny's Newsletter offered their annual subscribers:
Free Scale package
2x free tier limits on all usage-based tools
Valid for 12 months from redemption
Only for organizations with no paid invoices before December 1st 2025
Redemption page: /coupons/lenny
When a campaign customer wants an annual contract
Campaign benefits reduce a customer's bill, they don't zero it, so these customer are paying customers who can convert to an annual contract at any point during the campaign period. When they do, the campaign offer continues to run to its original expiry and expires automatically, and the contract is sized to account for the step-up when it does. We don't extend, swap, or cancel campaign benefits to win a deal.
PostHog complements a lot of other software companies. Since we’re active in the startup ecosystem and built around integrations, co-marketing opportunities come up naturally.
Who takes the lead with co-marketing?
Sales, engineering, or support will sometimes tag marketing into customer Slack channels where someone mentions co-marketing. There’s no obligation to say yes just because a partner is enthusiastic. If you’re unsure whether something is worth pursuing, ask in the #team-marketing Slack channel.
The list of partners we are currently doing or planning co-marketing partnerships with is maintained in this canvas.
If it does seem promising, a product marketer will take the lead and loop in events or other teams as needed.
We have a CDP with 50+ destinations and a data warehouse that connects to tools like databases, Stripe, and HubSpot. Any time we ship an integration, there’s a baseline level of co-marketing we should do:
Make sure docs are solid on both sides
Add it to the changelog (and changelog email if it’s really good)
If you have a new integration which deserves marketing support, the best way to get it is to ask in the #team-marketing Slack channel. The team will discuss and specific product marketer will take responsibility for running co-marketing.
When to level up: Most integrations stop here. But if there's genuine opportunity, then it's worth doing more:
Typically whenever we are pursuing work like this with a partner, we work with them to reciprocate to their audience through their channels.
In some cases where there's big partnership potential, the partnership is of a strategic significance, and the ICP is the same, feel free to explore a joint in-person event that will gather the community of both partners and deliver value from both sides.
Like all PostHog marketing, co-marketing should be useful to the reader. A super simple way to signal compatibility without being promotional is to casually reference partner companies in docs and editorial. However, we avoid case studies where there isn't an interesting story, guest posts, and other marketing 'fluff' content.
For example, PostHog docs might say "If you're routing LLMs (e.g. via OpenRouter)..." while OpenRouter docs say "Track downstream behavior in PostHog..."
We do this out of goodwill anyway in blog posts like this. It helps readers and costs us nothing.
Enterprise integrations
We haven't done much co-marketing with enterprises like Slack or HubSpot because big companies typically move slowly, and we haven't prioritized it.
If you find yourself working with an enterprise integration partner that's actually responsive and interested in co-marketing, go for it. Just don’t let their timeline block other work.
PostHog customers
If a customer is a logo we’d proudly show on the site, represents who we build for, and is getting real value from PostHog, then a case study usually makes sense.
Social media co-marketing for case studies naturally follows since most companies are excited to have their story featured. It's usually worth raising an art request for these opportunities.
We also will typically thank customers who participate in case studies and collab content by sending them a merch voucher. We're nice like that.
Startup and ecosystem partnerships
We already run a strong startup program. Accepted companies get $50K in PostHog credits plus access to partner benefits. This is one of the best types of co-marketing because it’s a simple value exchange: we help their users, they help ours.
However, we are very selective about which teams we partner with here because these partnerships usually offer outsized benefits to them. As a rule, we want to have no more than three such partners at once - and it's one-in, one-out.
Examples:
Easier incidents with Incident.io ($1,500 off a teams plan)
If we're signing anything with legal commitments, that needs to go via #legal. If it's an informal exchange of perks, you can usually just coordinate directly with the partner company.
If you’re giving PostHog credits, check with the to explore the options. See the campaigns and coupons handbook entry for more detail.
Add the offer to relevant emails and onboarding flows (the startup program has dedicated flows)
As a rule we don't commit to reporting sign-up performance to startup partners, as it just adds overhead and they should have their own methods of tracking. We also don't typically agree to rev share deals as part of this program, as it's a long tail activity.
More questions about startup program partnerships? Head to the project Slack channel.
Other ecosystem partners
Co-marketing goes both ways! PostHog’s startup program is promoted through partner channels like Stripe Atlas perks and the Fin Startup Pack.
We maintain a spreadsheet with most of our current partnerships. This also includes partnerships with VCs and PE firms. For the most part we do no co-marketing with these partners, though this may change. This spreadsheet doesn't list all VC partnerships via GetProven, as these are best tracked directly through that tool.
Co-sponsored events
Events are a great place to co-market and vary from intimate gatherings to large scale meetups. These are higher effort and don’t usually sit under product marketing alone. Tag Daniel early – he’s the best judge of what events and co-sponsorships will actually land.
Virtual events can also work for co-marketing, we just try to avoid boring ones. For example, we participated in ElevenLab’s Worldwide Hackathon, which was rad.
Co-branded merch
Merch collaborations are cool, but should be rare. They require real work from the design team and need a clear purpose beyond “we’re partners now.”
A good example is the limited edition t-shirts we did with Supabase, which was way more fun than a press release.
If you think a merch collab makes sense for a co-sponsored event, use the art request template. Please give thought to distribution and lead-times and add this to the request.
What if the partner wants more?
Not every co-marketing play warrants maximum effort. If someone's pushing for more but the product overlap is thin, it's okay to suggest starting smaller. A changelog mention and social post can always expand into more later if there's real traction.
PostHog's culture leans heavily on independence, but launching and growing a product is one area where product marketers (PMMs) and product managers (PMs) genuinely need to work together. Here are the most important things a PMM can do to build that relationship:
Make first contact. Don't wait for your PM to come to you. Reach out early to learn the team's revenue goals, activation and retention gaps, what marketing has been tried before, where users come from, and any quick opportunities. Ask for customer interviews and competitive research too.
Live in your team's channel. Monitor the team Slack daily for feature updates, sales notes, and customer feedback. PMMs often spot marketable features that PMs and engineers overlook.
Show up in person and in meetings. Use rare in-person gatherings for growth reviews and planning, and join sprint meetings to stay informed and show genuine interest in the team's work.
Loop your PM into marketing. Share quarterly plans, campaigns, and creative directions. Core assets like the product page, launch email, and launch blog should always get PM review.
Use AI to stay informed. Lean on tools like the PostHog Slack app and scheduled tasks (e.g. a weekly product digest) to surface product status automatically instead of manually scrolling.
Know who owns what
Most confusion between PMs and PMMs comes from the word "launch" being used to mean several different things. We split shipping something new into two moments with two different owners:
A release makes a product or feature available to existing users. It's owned by the product team – the PM or team lead drives it from their own release checklist.
A launch gets a product in front of existing and new people. It's owned by marketing, with the PMM working from the launch checklist.
Releases and launches can happen together or separately, so the clearer you are on this split, the less you'll step on each other's toes. Read the full breakdown of releases vs. launches and who's responsible for what.
Use activation criteria to shape your GTM plan
Every product should have activation criteria – the qualifying events that tell us a user has actually got value from a product. Setting these is the PM's job, working with the product team, but they're just as useful to you.
Currently, activation criteria must occur at the _person_ level, not the _org_ level. This is due to limitations in how we map profiles in Customer.io.
Because activation criteria define what "success" looks like for a product, they're the natural foundation for your go-to-market plan and campaign goals. When you set the "now what?" goal metric for a launch in Customer.io, tie it to the product's activation criteria rather than a vanity metric like clicks. Ask your PM what the activation criteria are early – if they aren't defined yet, that's a signal worth flagging, because a launch that drives signups but not activation isn't really working.
Tap into growth reviews, not just launches
Per-product growth reviews are run monthly by PMs, and they're full of exactly the context a PMM needs – acquisition sources, drop-off points, retention curves, and open-ended user feedback. As a general habit, PMMs don't read these, which is a shame: there's a lot of good marketing insight buried in them.
Make a point of following the growth reviews for your products. Join them where you can, or read the write-ups async. This matters most for mature products. Early on, marketing's job is often awareness (getting people to notice a launch). Once a product has product-market fit, the bigger levers are usually engagement and retention, and growth reviews are where those gaps surface first. A dip in retention or a stuck activation step is often something marketing can help with (lifecycle emails, in-app nudges, best-practice content). Treat the growth review as your standing input for that work.
that someone else might benefit from reading their story
Case studies are typically owned by the . They live in /contents/customers/ and appear on posthog.com/customers. If you have a suggestion for who we should interview, let us know in the marketing channel.
Creating a case study
1. Identify the right customer
Start by asking the PM for that product. PMs do lots of user interviews and can suggest warm leads. You can also post in company Slack channels, but give some context for what you're looking for.
2. Make contact
Got a lead? Before reaching out, search for the company in Vitally. If they already have an assigned Account Executive or CSM, give that person a heads-up — they might already be working on something with the customer or have extra context on what to ask them about.
If there’s no one assigned in Vitally, you’re clear to go ahead and reach out directly.
Some customers have a dedicated Slack channel. If they do, that’s usually the fastest way to coordinate. Otherwise, send an email.
3. Lay the groundwork
Someone agreed to chat? Hooray! Make a GitHub issue to draft some questions, tag any relevant sales/CS people, and note if you’ll need artwork later.
4. Schedule the interview
Who you talk to for interviews doesn’t really matter. Speak to engineers, founders, PMs, or anyone who seems keen to chat. If you’re unsure who to interview, email a few people at the company and see who bites.
We use Calendly for scheduling external meetings, such as demos or product feedback calls. If you need an account, ask Charles to invite you to the PostHog team account.
How to be a good interviewer:
Do some preliminary fact-finding (don't waste time asking general info about the interviewee's company and role)
Trust your gut — if it feels like a good story, it probably is. Worst case, it’s still user feedback to pass on to other small teams.
If it is worth turning into a case study, draft a PR right away while it's still fresh. Ask at least one teammate to review it to catch any grammar mistakes (or really bad jokes).
Best practices:
Be specific - Use real numbers and measurable outcomes where possible
Use quotes - Let the customer's voice come through
Keep it concise - Aim for between 700-1400 words including quotes
6. Review and approval
PR looking good? Tag the customer in Github for review. You're not asking for copy edits – just a quick fact check. Legal and PR teams will sometimes want to be looped in for approval as well. They might also request using Google Docs instead of GitHub.
Do what you need to do. The goal is to get the rubber stamp.
If your draft might include anything private such as screenshots of customer dashboards, keep it in an internal repo like requests-for-comments-internal just to be safe.
7. Publish!
Most people are excited to be featured and will sign off quickly. If you need artwork to go with the case study, use the art or brand request template
Once the case study is merged and live on the website, the last step is to send a merch credit to the participants as thank you.
Our email communications can be broadly divided into broadcasts (one-off emails to specific lists, like a newsletter), campaigns (repeatable workflows which users move through dynamically), and API triggered emails (self-explanatory).
This page doesn't deal with our build mode newsletter, which is sent through Substack and managed by the Content & Docs team.
Linking to the PostHog app or PostHog AI
To point users at a page in the PostHog app via email, use this format: https://app.posthog.com/ and do not include the project path.
For example: https://app.posthog.com/endpoints instead of https://app.posthog.com/project/2/endpoints.
The app.posthog.com prefix works for both US and EU instances, and the project path resolves itself for the recipient.
To preload a prompt for PostHog AI, use this format: https://app.posthog.com/#panel=max:!Your%20question%20here
For example: https://app.posthog.com/#panel=max:!What's%20my%20churn%20rate?
Email broadcasts
We regularly send three types of email broadcasts.
Changelog, a product announcement email sent bi-weekly via Customer.io.
PostHog for Startups, an email to users of our startup program. Sent monthly, via Customer.io.
Launch emails, which are 'random acts of marketing', but fairly consistent with every product team shipping alpha, beta and GA features each quarter.
Occasionally we send other ad-hoc email broadcasts for specific activities such as outages, reminders, announcements, or deprecations.
Every month, we use Customer.io to share a broadcast which summarizes the highlights from the weekly changelog over the last month. We use our discretion to choose which updates to highlight, usually showcasing three or four of the most impactful changes. We usually reserve the top spot for making users aware of new beta features. A test is shared with the team before we send to users.
We tag these emails as Product updates in Customer.io, so users can manage their subscriptions. In order to maintain high deliverability, we target users in the Recently Engaged (4 months) segment which includes everyone who has logged in the last quarter.
PostHog for Startups
Each month, we send an email to users in our PostHog for Startup program. A test is shared with the team before we send to users. This email is targeted to users in the following segments, all at once: PostHog for Startups (Old), Users in the YC program, old and new, Old startup teams (Backfill only), and PostHog for Startups and YC (new).
The email is usually comprised of three sections, which inform users of new guides which are relevant to startup use-cases, new betas which are available for them to try, and a spotlight written about a new org in the program. We end by asking for feedback.
We categorize these emails as Actually useful marketing emails in Customer.io, so users can unsubscribe if they wish. This email usually comes directly from Joe.
Launch emails
Most product and feature launch emails come from the Product Marketer who sent them – but sometimes campaigns trigger from others, such as billing@posthog.com.
The exceptions and other solutions are:
Sending emails from hey@posthog.com – this is what we usually do for BIG sends, because it would overwhelm the sender's inbox with 'out-of-office' auto-replies.
Sending emails from beta-feedback@posthog.com – this is a Google group tied to the automation in #posthog-feedback by a Slack bot. Any responses to this address get posted in that channel and anyone can reply to them using the info in there.
Sending emails from a specific person, but setting the reply-to address as one of the above. This is not common, but it's there if you want to use it.
We specifically do not want emails we think people will reply to going into hey@posthog.com because it is sporadically monitored at best, and hard to collaborate through.
If you're sending a launch email (alpha, beta, GA), it's helpful to add an annotation in our PostHog project on the send date, so we can see its impact on our metrics later.
When we ask users to share feedback through email, it should either link to beta-feedback@posthog.com, the support modal, or to ourselves personally. Never hey@posthog.com.
Doing this lets us filter out the noise for everyone else while still giving good visibility on meaningful feedback internally. If a user sends you feedback, you should share that with the relevant product team or in https://posthog.slack.com/archives/C011L071P8U
When adding yourself as a send-from address in Customer.io, be sure to edit the display name to '[your name] from PostHog'.
Other broadcasts
Any ad-hoc customer email broadcasts are owned by the , and are usually sent via Customer.io. These can include product updates, outage alerts, or other PostHog news if needed.
These emails are usually tagged as Service updates in Customer.io when they include important account or product information. These emails are given a dedicated unsubscribe option in the footer, making it clear that we do not recommend users unsubscribe to these emails.
Important service updates are the _only_ type of email we may send to unsubscribed users, and only if we feel it is warranted to do so.
Service updates emails are often part of an engineering incident. We handle comms for those too.
Whenever we need to send an email broadcast like this we begin by creating an issue using the messaging template in the marketing repo, unless it involves discussion of personal information - in which case it is discussed in Company Internal. This enables us to summarize information and seek approval from teams while also keeping our work open source, and without requiring everyone to log in to Customer.io. Issues are closed when an email is sent.
If you'd like to work with Marketing on an email activity, please begin by opening an issue with the messaging template.
Email campaigns
We maintain many email campaigns to help users get the most out of the product. The most developed and documented of these are our four onboarding campaigns.
Onboarding emails
Generally, when we talk about onboarding emails we refer specifically to the flow for PostHog Cloud sign-ups, but there are also other flows in use for other occasions.
The onboarding flow regularly changes as we test new ideas. Any changes to it are, as with all other email campaigns, documented in the marketing repo.
We aim for all content in this flow to be relevant and helpful to users, without being salesy. All emails come directly from Joe and he triages replies on a daily basis, answering or redirecting as needed. The campaign is triggered when a user signs up for the first time and has a goal of users achieving billing product activated within 7 days of opening any email in the flow.
We tag all these email flows as onboarding in Customer.io and categorize them as Welcome emails so that users can easily manage their preferences.
Self-hosted and open source onboarding emails
We sunset our paid self-hosted product a long time ago, but some users still try to use the legacy version. For this reason we run a dedicated self-hosted onboarding campaign which includes three emails sent over a course of six weeks. These emails come from the hey@posthog.com email address.
The goal of this flow is to set expectations for what the self-hosted experience is like and to encourage users to move to the PostHog Cloud product for a better experience.
Our open source onboarding email is essentially identical to the self-hosted onboarding flow, but excludes information about the sunsetting of the self-hosted product.
Waitlist, alpha, and beta onboarding emails
When a user joins a waitlist or opts in to a feature preview — via the feature preview menu or a waitlist form on either a product or the roadmap page — a $feature_enrollment_update event is sent to Customer.io through a data pipeline and enters them into the Waitlist, Alpha, Beta onboarding flow. The flow immediately segments on the $feature_enrollment_stage property:
Concept: an immediate, simple confirmation that they're on the waitlist.
Alpha: an immediate email warning of rough edges and asking for feedback.
Beta: a 5-day wait, then an email asking for feedback on the beta.
When a feature moves from concept to alpha or beta, users who registered interest are automatically opted in to the new stage and a user moved feature preview stage event fires — we then email them to let them know the feature is enabled and now available, and ask for feedback.
Launching a beta? It helps to let the Brand team know in the team Slack. The team can then add your beta to the beta onboarding flow, and plan ahead for marketing announcements as needed.
Onboarding - new hires
This is an internal email flow for new hires, which triggers whenever a new user signs up with a PostHog email address. We currently exclude most old-time hires from this flow, to avoid blocking their inboxes.
This campaign runs for a new hire's first 30 days and sends them 7 emails with information to help them get set up at PostHog.
There's no way to unsubscribe from these emails, but if you're triggering them with test accounts then let the Brand team know and they can exclude you from the campaign.
Other email campaigns
We run a series of other small campaigns with smaller volumes. These include:
The replay recommender is a campaign which encourages users who have ingested a large number of unwatched replays to watch some of the recordings.
Teams upsells & cancellations are two separate campaigns. The first triggers when a team invites their sixth and ninth team member, suggesting the Teams package to boost collaboration. The second triggers when the package is disabled, comes from Zach, and requests feedback.
Startup & YC updates is a series of campaigns for the startups and YC programs. These broadly notify users when they join the program, and use 50%, 75% and 100% of their available credit.
API triggered emails
We maintain a series of API triggered emails by working with the . These are found in Customer.io's transactional tool and broadly encompass billing and security updates, such as an upcoming bill or a change to 2FA settings. These emails are triggered by API in order to keep them highly relevant and with high deliverability.
Transactional emails feature Liquid code to help personalize their content. All transactional emails should contain Liquid in the main body content to clearly indicate to the user which project or organization the email is regarding, with suitable fallbacks. For example:
We turned the free allowance for {{ trigger.product_name | default: "a product" }} on {% if trigger.team_name %}{{ trigger.team_name }}{% else %}your account{% endif %} off and on again, giving you another month of free usage.
Adding a new event property to Customer.io
We use Customer.io to target broadcasts and campaigns — for example, the onboarding flow targets users based on their events, as well as segments which define product intent and activation. PostHog sends this information to Customer.io through a data pipeline, so a new event or property has to flow through that pipeline before you can build a segment on it.
To add a new event or property:
Confirm the data is tracked in PostHog. Product intent and activation criteria (such as a product's product_key value) are usually set up by the product manager for the relevant product. If the event or property you need isn't being tracked yet, ask the PM to create it in PostHog before going any further.
Add the event or property to the Customer.io pipeline. Any action or property we send to Customer.io must be added to the Customer.io destination in PostHog. If you try to build a segment on something that isn't in the pipeline, the segment won't populate.
Create the segment in Customer.io. A newly added property won't appear in Customer.io's autocomplete when you start typing it. Instead, copy and paste the exact property name, save, and the segment will populate when the data arrives (but this is always worth testing or checking later).
Want PostHog to partner, sponsor, or speak at your event? Submit the form below. Want to start a builder collective? Check out our Builder collectives program and submit the form.
We did 45 events in real life (IRL) in 2025 and we're just getting started. While we’re 100% remote and set up to work asynchronously–we've found real benefits in getting together with users in real life. All our public events are showcased on the events page.
Events have to be focused on and valuable to our ICP. We prefer not to be a small fish in a big pond, hence we mostly pass on big conferences. And we prefer pull over push, so we gravitate towards content and formats that educate and activate while avoiding booths, badge-scanning, buying attendee lists, paying to speak, and webinars.
The event formats we prefer (and organize ourselves) fall into one of these:
Hands-on gatherings that enable our users to build better products for their customers
Experiences that allow engineers and founders to walk away with unique product engineering insights
Getting product engineers together to identify problems and build solutions for users
AFK time that we ourselves enjoy like hiking, gaming, cycling, cooking classes, etc.
All plans come together – from conception through to final delivery – on our event management tool which centralizes owners, logstics and feedback in one place.
Community incubator
We connect builders around the world by helping them start IRL micro-communities that gather for recurring co-working sessions. As we know from our own sprints, offsites, and hackathons, we can build a whole lot when we gather in person with other people who have a bias for action.
We have already seen how this format makes a higher impact on communities because of the velocity built over weeks and months of communal work, collaboration, and creativity.
Image: Philadelphia incubator
Taj leading his builder group in Philadelphia
Geographies
The pilot program started in tech hubs mostly in North America, UK, and EU. We now have communities in Austin, Philadelphia, Singapore, New York, Barcelona, and Lahore. At this time, we're open to groups starting in any city with a population of more than half of a million people.
Co-working structure
The focus is on weekly, bi-weekly, or monthly gatherings with small groups of ~10 people. Gatherings typically take place during weekday evenings or weekends and go for about 3 hours.
Discuss → Build → Demo
We suggest starting with a roundtable discussion of the latest dev news and trends, then each builder can set their own goals for the session. Allow at least 2 hours for building, and then close out the session with demos to show off what you built. Outside of co-working, the group is encouraged to get together to connect for an AFK activity such as a walk, bike ride, hike, or local sightseeing.
Venues
The ideal venues for the community incubator are free-to-use spaces conducive to a group comfortably working (accessible, quiet, Wi-Fi-enabled.) They are typically held in tech or VC offices that have an available room, libraries, and co-working spaces. If you have a venue and want to host a builder group, reach out to Daniel directly.
Community events
Community events are in real life (IRL) manifestations of our mission organized by enthusiastic partners and customers. They usually originate when someone has identified an interesting topic or problem set for an event and want to help people move faster, smarter, and more together.
These are some of the event formats we're most actively pursuing:
Builder Breakfasts: bringing together 35 engineers for unconference-style discussions of hyperspecific software problem sets they are encountering. Breakfast served.
AI Talks with Demos: technical meetups for 75 people with live demos, where startups and scaleups demonstrate how they're deploying AI native tools to solve various problems.
Founder Fireside deep dives with one of our co-founders (Tim Glaser and James Hawkins) for 100 founders and product engineers.
What community events are not for:
Forcing PostHog or any other product into conversations with people
Watching or planning things rather than doing them
Just networking for the sake of chit chat
Formulating a purpose and structure
All impactful event follow the principles of user-driven development which stem from the user problem or requests. Who is the ideal attendee profile for your event? They might be your customers, fellow founders, local engineers or any other collection(s) of people. Talk to them first to validate if the event is worth your time.
Put real effort into this first step. Defining the "what, why and how" of an event beforehand will pay off on event day. Let our shared values guide you. Don’t submit your event for support until your answer to “Would I attend this?” is a clear “YES!”
Getting support
Financial support: We are happy to support the growing ecosystem of PostHog users and product engineers more broadly through financial sponsorship. We do this often for events that align with everything outlined on this page. Budgetary support typically falls in the range from $500 to $3,500. When we support monetarily, it almost always involves some added level of engagement.
Speakers: Want a speaker in our ecosystem (team PostHog, customers, partners)? We’ll try our best. When considering speakers for your events try to avoid:
People LARPing (live action role-playing) as executives
Loudest person pretending to know more than they do
Content: If your speaker(s) are unsure of what to talk about, consider going back to the purpose of the event. Otherwise, wehaveplentyofmaterialforyourinspiration.
Merch: We use the store merch processes to handle distribution of PostHog-branded merch. We tend to be generous with merch for community events. Outline what you had in mind in the issue.
Co-promotion: Most of the time the help requested is in the form of promotion. As a general rule, we don't promote events we aren't supporting or co-hosting ourselves. We decide when to repost community events on our social media channels and email on a case by case basis.
Venue and catering: Identify the vendors and costs and include them in the GitHub issue. If the event will not be possible without monetary support, make that clear. We may support the cost of venue, food, or beverages but require the paper napkin math.
Feedback: You’ll learn more by doing than planning so don’t worry about having every detail complete before submitting for feedback from our team.
Words: Naming products is hard. Same goes for naming events and writing their descriptions. As a prerequisite, read our primer on writing for developers. Try your best to come up with event names that communicate the 'what?' and will attract the 'who?' And then again ask yourself, "would I attend this?"
Pictures: Every event is improved with a flyer or poster that showcases the essence of the experience. We keep a comprehensive list of brand assets and guidelines on the brand assets page. Share your assets and we’ll give feedback. Depending on the scale and timing of the event, our team may be able to help with branding as well.
Event recaps
Community events are better when organizers share what happened, what you learned, and any follow-up actions. We value feedback and expect the same from event organizers. In addition to what you learned and feedback from attendees, we ask that you share any photos, videos, quotes, data points with our team.
PostHog team members who attended or presented at an event can share their feedback directly through our event feedback form.
Sponsoring external events
We often get invited to sponsor events - these range in size, location, and audience. We rarely say yes. For these to be a worthwhile endeavor, the sponsorship should be a win-win primarily for the end user and secondarily for us. Hence, it's important that the audience, content, format, and ethos to all align. Even if we don't sponsor financially, we encourage team members to speak at events and we can support with merch. Ask in the #team-builder-relations channel.
Speaking at events
If you're interested in attending or speaking at a developer conference, consider submitting a CFP (Call for Papers) to one of these events taking place in 2026. If you don't see an event you're interested in, please add it directly in the reference sheet.
For first-time yappers, reference the speaker's guide. If you need inspiration for a talk, pretty much any practice we use for actual production code is fair game. This includes integrations and implementations with other products. And at this point people are interested in not just what we build but how we did it.
Sponsoring student organizations
Sometimes students at varying universities ask us if we are interested in sponsoring their career fairs, hackathons, or other student-led initiatives. We don't currently participate in these. Although we don't use specific years of experience as a qualifier for hiring, we rarely hire students straight out of school. If there is a custom partnership you have in mind or it involves an existing employee's alma-mater, ask in the #team-builder-relations channel.
Event submission form
Want us to partner, sponsor, or speak at your event? Fill out the form below and we'll be in touch.
Blog post images are created in Figma. The image appears at the top of each blog post, above the headline. It's also used as the Open Graph image.
Dimensions
Open Graph images are 1200x630, so we stick with those dimensions to keep this simple. (This is approximately double the size they'll be displayed at, making them look nice and crisp on HiDPI screens.)
Rename the frame of the image to closely match the blog post title in a slug format. (Ex: writing-for-developers, where we remove capital letters and punctuation, and replace spaces with hyphens. This will become the filename that is uploaded to the server.) It's best to omit articles (a, and, the).
Export the image as a PNG (at 1x).
Save the image and add it to the issue.
The image should be uploaded by the person creating the blog post.
Adding to a blog post
Upload the file to /contents/images/blog.
Make sure the filename matches the reference to the image in the .md file.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Error Tracking captures unhandled exceptions from web, mobile, and backend code, groups them into issues, and surfaces them alongside session replays, logs, feature flags, and product analytics in the same platform. Source maps, auto-assignment, spike detection, "Fix with AI" prompts, and Slack / Linear / Jira / GitHub alerts all come built-in. Generous free tier, then usage-priced per exception.
Sentry has deeper error tracking features, more battle-tested SDKs, and more granular grouping. PostHog wins on context: every exception ties to the user who hit it, the session replay of the moment it broke, and the feature flag they were on. Customers pick PostHog when they want errors linked to product behavior, not when they want pure error-tracking depth.
The unique belief
PostHog's vision is a self-driving product: software that watches itself for bugs, ships the fixes, and prioritizes work by user impact, not error volume. That loop needs every error to know which user hit it.
Most error tracking tools give you a stack trace, a frequency count, and a release tag. They don't tell you which user hit the error, what they were trying to do, or whether it matters to the business. So engineers triage by error count instead of by user impact, and waste cycles on noisy errors that don't affect anyone real.
Every PostHog exception is a product event with the user attached. Click an error to watch the user's session replay. Filter exceptions by feature flag variant, plan tier, or revenue cohort. See the business impact next to the stack trace. PostHog Error Tracking is the only place where every error already knows who hit it, what they were doing, and whether it matters.
Who this is for
Teams already on PostHog who pay separately for Sentry, Bugsnag, or Rollbar. They're paying twice and stitching user identity by hand.
Customers on Sentry today who want errors connected to product behavior. We'll cover up to 6 months of free PostHog usage during the overlap when you commit to a $20k+/year annual contract.
Engineering teams who want to triage by user impact, not error volume. "This exception is breaking checkout for your top-paying customers" beats "this exception happened 200 times in 5 minutes."
Multi-language stacks running web + mobile + backend. Native SDKs for Node, Python, Go, Ruby, Rails, Elixir, NestJS; iOS, Android, React Native, Flutter; plus every major frontend framework.
Founders and small engineering teams shipping production code. Generous free tier; no contract negotiation to start.
Who this isn't for
Teams that need full feature parity with Sentry – Sentry has deeper SDK coverage, more mature grouping, and a longer track record.
Teams whose primary need is iOS error tracking at full fidelity – the iOS implementation doesn't symbolicate system frames yet
Compliance-driven teams needing on-prem deployment, SOC 2 audit trails on every exception, or SIEM-grade indexing – Sentry's enterprise tier and dedicated SIEM tools are more mature here.
Messaging
Message 1: Every error already knows the user
Problem: Most error tracking tools give you a stack trace, a frequency count, and a release tag. They don't tell you which user hit the error, what they were trying to do, or whether it matters to the business. Engineers end up triaging by error volume instead of user impact.
Solution: Every PostHog exception is a product event with the user attached. Click an error to watch the user's session replay. Filter exceptions by feature flag variant, plan tier, or revenue cohort. See the business impact next to the stack trace.
Supporting features:
Shared distinct_id and session_id with the rest of your product data
Click any error to open the user's session replay
Filter exceptions by feature flag variant, cohort, or plan tier
"Fix with AI" prompts; MCP server lets agents query exceptions from Claude Code, Cursor
Source maps, auto-assignment, suppression rules, spike detection all built-in
Message 2: Drop Sentry, Bugsnag, or Rollbar
Problem: Most teams pay for a standalone error tracker (Sentry, Bugsnag, Rollbar) and separate tools for everything else – analytics, replays, feature flags, logs. The error tracker sees the stack trace; the other tools have the user context. Engineers stitch them by hand every time something breaks.
Solution: PostHog Error Tracking replaces standalone error trackers – same SDK coverage on the languages that matter, with the user, session, replay, and flag context already attached. No CDP middleware, no identity stitching.
Supporting features:
Native SDKs for Node, Python, PHP, Go, Ruby, Rails, Elixir, NestJS; iOS, Android, React Native, Flutter; plus every major frontend framework
Source map upload via posthog-cli or bundlers plugin (support for nextjs, vite, rollup, webpack) and @posthog/nextjs-config
Contract buyout for Sentry, Bugsnag, or Rollbar on annual commit
Alerts route to Slack, Discord, Linear, Jira, or GitHub with the user context attached
Issue management with auto-assignment, suppression rules, and burst protection
Message 3: Triage errors by who they hit
Problem: Every error tracking tool surfaces errors by volume – the loudest exception wins the engineer's attention. But the loudest isn't always the most important. A high-volume bug in a free trial flow might matter less than a single exception breaking checkout for your top-paying customer.
Solution: Filter exceptions by user cohort, revenue, plan, or feature flag. See which issues are hitting your most valuable customers and fix those first. Roll back the flag that caused the spike from the same view.
Supporting features:
Filter exceptions by any user property, cohort, or feature flag variant
See the customer behind every issue – plan tier, lifetime value, journey
Spike detection with rolling baselines (5-minute buckets, configurable thresholds)
Roll back a feature flag affecting a user cohort from the same dashboard
Issue assignment and suppression rules to manage signal-to-noise
Battle cards
vs Sentry
Their approach: The 800-pound gorilla. Sentry is no longer just an error tracker; it now ships Error Monitoring, Logs, Session Replay, Metrics, Tracing, Profiling, Uptime Monitoring, and Cron Monitoring on one platform. AI suite "Seer": debugging agent, Autofix, AI Code Review, plus a Sentry MCP server. Event-based pricing with steep volume discounts – errors drop from $0.000363 to $0.000150 per event at 20M+. Free Developer plan (5K errors, 50 replays); Team starts at $26/mo + pay-as-you-go.
Where PostHog wins:
Customer wants errors connected to product analytics, feature flags, and experiments. Sentry has none of these, despite their platform expansion into logs, replay, and tracing (which we also have).
Customer triages by user value, not error volume – PostHog filters by cohort, plan tier, revenue. Sentry's user context is thinner.
Customer is product-led, not infra/SRE-led. Sentry's expansion is toward Application Observability and Real User Monitoring; PostHog's is toward product engineering and growth.
Customer wants feature flag rollback workflows from the error view – Sentry doesn't have feature flags.
Honest concession: Sentry has deeper SDK coverage, more mature grouping, a longer mobile track record, and steep volume discounts that make them cheaper at 10M+ errors. We win on context, not coverage or cost-at-scale.
Their approach: Mid-market error tracking specialists. Rollbar positions as "code-first observability that connects errors, replays, and releases in one place" – session replay shipped, MCP integration, RQL query language, Root Cause Analysis AI shipped, Rollbar Resolve AI agent (opens PRs with fixes) coming soon. Free tier: 5K occurrences + 1K replays. SOC2 + ISO27001 certified. Bugsnag (SmartBear-owned) follows a similar mid-market specialist playbook, historically strong on mobile crash reporting.
Where PostHog wins:
Customer wants errors connected to the full product behavior stack – funnels, retention, cohorts, experiments, surveys. Rollbar and Bugsnag are error trackers plus replay, not product platforms.
Customer is consolidating multiple tools (error tracking + analytics + flags + experiments) into one platform – Bugsnag/Rollbar are one-or-two-product solutions.
Customer wants feature flags as a first-class capability for rollback workflows – neither has flags.
Customer values published, transparent pricing without quote-locked enterprise contracts.
vs Datadog
Their approach: Part of the broader Datadog observability platform – auto-grouping, real-time alerts, AI-powered insights, suspect commits. Session Replay (15 seconds before/after frontend errors) and Exception Replay (local variable capture on backend exceptions). Jira integration, Datadog On-Call. Built for SRE and platform engineering teams already invested in Datadog APM. Scales with Datadog's per-host platform pricing.
Where PostHog wins:
Customer is product-led, not infra-led. Datadog Error Tracking sits inside a stack built for SREs; PostHog sits inside a stack built for product engineers.
Customer wants errors connected to product analytics (funnels, retention, experiments) – Datadog has RUM and Session Replay but no product analytics layer.
Customer can't justify the broader Datadog bill at their scale – PostHog Error Tracking ships standalone with a generous free tier.
Customer wants feature flag rollback workflows in the same dashboard – Datadog doesn't have feature flags.
Objections
"Sentry has deeper SDK coverage, more mature grouping, and now ships session replay, logs, tracing, AI, and MCP too. What's actually different?"
Follow-up: Who would own this – platform/SRE engineering or product engineering? And is the use case pure error-tracking depth, or errors tied to user behavior?
Answer: Sentry has expanded dramatically beyond pure error tracking – replay, logs, metrics, tracing, profiling, AI/MCP. They've moved into Application Observability territory. If the team is platform-led and the use case is full-stack engineering observability with deep error coverage as the anchor, Sentry is the more direct fit and we should say so. PostHog's wedge is different: we don't try to win on observability features. We win on product analytics depth – funnels, retention, cohorts, paths, experiments, feature flags. Sentry has none of these despite their expansion. The comparison isn't "PostHog vs Sentry on error tracking" – it's "errors connected to engineering telemetry (Sentry's path) vs errors connected to product behavior (PostHog's)."
"We're a mobile-first app. PostHog's iOS error tracking has documented gaps."
Follow-up: What's the mobile breakdown – pure iOS, pure Android, or both? Which mobile crash features are non-negotiable?
Answer: Our iOS implementation has documented gaps. System frames aren't symbolicated, and Swift crashes appear as SIGTRAP without messages. The PostHog product page acknowledges it directly: "Even our team thinks Sentry is better if you need mobile support. For now!" Active development. If mobile crash reporting is the primary need, Sentry is the right tool today. Worth flagging: if the customer also needs product analytics on the same mobile app (session replay, feature flags, experiments, cohorts), PostHog still wins on that side – many teams run PostHog for product behavior and Sentry for mobile crashes today, then consolidate as our iOS support matures.
"Sentry is cheaper than PostHog at high volume – their volume discounts drop errors to $0.000150 each at 20M+."
Follow-up: What's your projected error volume next quarter and next year? Is error volume the primary cost driver, or do you need replay, analytics, and flags too?
Answer: True at very high volumes – Sentry's volume discounts are aggressive past 10M errors per month. If error volume is the primary cost concern and the customer doesn't care about the cross-product context, Sentry wins on price at scale. PostHog's value strengthens as the customer uses more of the platform. A useful reframe in the room: PostHog Error Tracking standalone vs Sentry standalone – Sentry wins on price at scale. PostHog Error Tracking bundled with replay + analytics + flags vs Sentry + LogRocket + Mixpanel + LaunchDarkly – PostHog wins on total stack cost easily.
"Customers say PostHog has noisy errors and false captures. Sentry's grouping is cleaner out of the box."
Follow-up: Is the concern signal quality (too many duplicates) or quantity (too many low-priority events)?
Answer: Honest: this came up in our customer research. PostHog's autocapture is broader than Sentry's, which gives more raw data but more noise. The grouping algorithm is still being improved, and the docs say so. Mitigations available today: custom fingerprinting rules, ingestion-time grouping rules, suppression rules, burst protection, before_send hooks for filtering, and spike detection with rolling baselines to separate real spikes from noise. If the team needs zero-tuning-required out-of-the-box quality, Sentry's grouping is more mature. If they want broader capture with manual tuning to get to signal, PostHog gets there with some setup work.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Logs is a centralized log search built on OpenTelemetry. Send logs from any OTLP-compatible source (including your existing Datadog Agent) and they're searchable inside the same platform that runs your analytics, session replays, errors, and feature flags. Generous free tier, usage-priced per GB, no per-host or per-user fees.
Datadog and New Relic are mature but expensive and built for infrastructure teams. Grafana Loki is open source but logs sit apart from your product data. PostHog Logs is OpenTelemetry-native, predictably priced at a fraction of Datadog's per-GB cost, and the only one where every log already knows who hit it.
The unique belief
PostHog's vision is a self-driving product: software that watches itself for bugs and conversion drops, then ships the fix while you sleep. Most observability tools generate a lot of data (events, errors, latency, logs) without the product context that makes them actionable.
Every PostHog log already knows the user. Click any log to jump to the user who hit it – their session replay, their plan, their journey. From there, filter on any attribute you attached at ingest. See which logs hit your top 1% of customers and which hit anonymous bots.
Who this is for
Teams already on PostHog who pay separately for Datadog, Splunk, or Loki. They're paying twice for storage and stitching identity by hand.
Customers on Datadog, Splunk, or Elastic today. Cost is the most cited switching reason. We'll buy out the contract on an annual commit.
Teams standardized on OpenTelemetry. Ingest via OTLP-HTTP from any OTel source, no proprietary agent required.
Engineers (or product-led teams) who want logs linked to user behavior. Backend errors become useful when they're tied to the user who hit them.
Startups consolidating their observability stack. $50k credits via the startup program.
Teams using the Datadog Agent for log forwarding. Point it at PostHog with one env variable. No log pipeline rewrite.
Who this isn't for
Teams with massive log volumes needing enterprise-grade indexing, ML-driven log clustering, or year-plus retention. Datadog, Splunk, and Elastic are more mature here.
Teams whose primary problem is Kubernetes-level infrastructure observability – PostHog is built for product-led engineering, not infra-first teams.
Messaging
Message 1: Logs that already know your user
Problem: Backend errors, slow requests, and rate-limited calls only become useful when you know who hit them and what they were trying to do. Most observability tools store logs in their own identity layer, so you stitch user data across Datadog, Sentry, and your analytics tool to figure out what actually broke for whom.
Solution: Every PostHog log ingests with the same user, session, and event identity as the rest of your product data. Click a log to open the user's session replay. Filter by feature flag variant, plan tier, or revenue cohort. Surface related errors from the same session.
Supporting features:
Shared distinct_id and session_id across logs, errors, replays, and analytics
Click any log to open the user's session replay
"Related errors" tab in log details surfaces issues from the same session within ±6 hours (when sessionId is attached)
Filter logs by any user property, cohort, or feature flag variant
PostHog AI summaries highlight patterns across logs and recommend next steps
Message 2: One tool for your entire debugging flow
Problem: When something breaks in production, the investigation usually spans five separate tools: Datadog for logs, Sentry for errors, FullStory for replays, LaunchDarkly for flag context, an analytics tool for user history. None of them know each other. Engineers correlate identity by hand every time something breaks.
Solution: PostHog Logs lives in the same platform as your error tracking, session replays, feature flags, and product analytics. Logs auto-link to the session they came from, the errors they triggered, and the flags the user was on. The side tools you kept only for connecting these dots can go.
Supporting features:
Logs + Session Replay: click any log to watch the user's session
Logs + Error Tracking: "Related errors" tab in log details surfaces issues from the same session (when sessionId is attached)
Logs + Feature Flags: filter logs by flag variant the user was on
Browser console logs auto-captured by PostHog JS, no extra SDK to install
Message 3: Pay for what you ingest, not per host
Problem: Datadog, New Relic, and Splunk price logs by host, GB, retention tier, and indexing rate. Bills are unpredictable and grow faster than usage. Customers in our research consistently cite cost as the sharpest switching reason: Datadog's "sudden cost increases" and "commit to events, pay on demand if you don't hit the mark" framing keeps coming up in user interviews.
Solution: PostHog Logs is per-GB only. 10 GB free per month, $0.25/GB after, with volume discounts. No per-host fees. No per-retention-tier surcharges. No per-user pricing. And because ingest runs on OpenTelemetry, your setup stays portable if you ever decide to leave.
Supporting features:
10 GB/month free across log ingest; $0.25/GB after with volume discounts
No per-host, per-user, or per-retention-tier surcharges
Hard billing limits per product
OpenTelemetry-native ingest – migrate in and out without proprietary lock-in
Datadog Agent drop-in: change one env variable to start sending logs to PostHog
Battle cards
vs Datadog (and New Relic)
Their approach: Datadog is the dominant enterprise cloud observability platform, meaning it has mature features across logs, APM, metrics, RUM, and infrastructure monitoring. Pricing is layered by host + GB + retention tier + indexing rate and famously hard to predict. New Relic positions on simpler pricing with 100 GB/month free ingest and unlimited basic users, but is still infrastructure-first. Both are built for SRE and platform teams.
Where PostHog wins:
Customer is product-led, not infra-led. PostHog Logs sits next to product analytics, funnels, retention, cohorts, and experiments. Datadog and New Relic don't have any of those.
Customer wants logs tied to user behavior, not just hostname and pod – every log shares identity with the rest of the product data.
Customer can't justify the bill at their volume – simple $0.25/GB after 10 GB free, no per-host fees, no per-retention-tier surcharges, published pricing not quote-locked.
Datadog Agent drop-in lets the customer migrate with one env variable.
vs Grafana Loki and Grafana Cloud Logs
Their approach: Grafana Loki is open-source log aggregation, the L in the LGTM+ stack (paired with Prometheus/Mimir for metrics and Tempo for traces). Grafana Cloud Logs is the managed tier – 50 GB free, AI/ML insights, Adaptive Logs for cost control, a queryless Explore Logs app, and pricing across three dimensions (process + write + retain) plus a $19/month platform fee. Sells to platform engineers running the LGTM+ stack.
Where PostHog wins:
Customer's team is product engineering, not platform engineering. Grafana's mental model is metrics-and-infrastructure-shaped; PostHog's is product-shaped.
Customer wants logs connected to real product analytics (funnels, retention, cohorts, paths) and feature flags – Grafana has none of those products.
Customer doesn't want to manage three pricing dimensions or self-host Loki.
OpenTelemetry-native ingest works either way – no proprietary lock-in in either direction.
vs Better Stack
Their approach: Modern OpenTelemetry-native observability bundle – logs, traces (eBPF + OTel), metrics, RUM (session replay + web vitals), error tracking, incident management, status pages, on-call. Has an MCP server and an AI SRE that brings "Claude Code with the knowledge of your infrastructure." Headline pricing claim: 30x cheaper than Datadog ($687/month for 3 TB). Offers contract buyouts for Datadog migrations. Going hard after the same buyer we are.
Where PostHog wins:
Customer wants the full product analytics layer – funnels, retention, cohorts, paths, journeys, experiments. Better Stack has web vitals and RUM, not the product behavior stack.
Customer needs feature flags and experiments as first-class trigger and audience sources – Better Stack doesn't have flags or experiments.
Customer's team is product engineering, not SRE. Better Stack's AI SRE is explicitly framed for infrastructure workflows; PostHog AI is product-context-aware.
PostHog runs analytics, replay, errors, flags, experiments, surveys, and logs as one connected platform – Better Stack is observability + IRM, not product-led growth.
Objections
"You don't have distributed tracing or metrics. We need full observability."
Follow-up: What's your current tracing setup, and is it integrated with your logs already, or are they separate tools?
Answer: Honest – PostHog doesn't ship distributed tracing or metrics today. Both are on the roadmap, coming this summer. If full observability with traces + metrics + logs in one tool is non-negotiable today, Datadog or Grafana's LGTM+ stack is the right pick and we should say so. What PostHog does offer is logs connected to product analytics, session replay, error tracking, and feature flags – context layers no other observability tool ships. Many teams adopt PostHog Logs alongside an existing tracing solution and consolidate later.
Proof point: Logs ingest via OpenTelemetry, so an OTel-instrumented backend can send logs to PostHog and traces wherever – the standards make hybrid setups easy.
"Better Stack claims 30x cheaper than Datadog and has MCP, AI SRE, and a full observability + IRM bundle. What makes PostHog different?"
Follow-up: Who would own this, platform engineering and SRE, or product engineering? And is the pitch landing on infrastructure observability or product behavior?
Answer: Better Stack is OTel-native, MCP-capable, does contract buyouts for Datadog migrations, and has a fuller observability bundle than ours (traces, status pages, on-call). If the team is platform/SRE-led and the work is infrastructure observability + incident response, Better Stack is the more direct fit. Where PostHog wins is when the team is product-led, meaning they need logs connected to funnels, retention, cohorts, experiments, and feature flag exposures. Better Stack has web vitals and RUM; PostHog has the full product behavior stack and feature flags as first-class triggers. The differentiation isn't observability features, it's the product data layer those features connect to.
"How does PostHog handle terabytes of logs per day?"
Follow-up: What's your current daily volume, and where does the cost get painful – ingest, indexing, or retention?
Answer: PostHog Logs is per-GB ingest only, with volume discounts past the 10 GB free tier. At terabyte-per-day volume the bill is predictable but real – customers usually pair PostHog with sampling (drop debug-level logs in production) or use the OpenTelemetry collector to route only the logs that need product context to PostHog. For pure-volume use cases without that need (security audit, raw archival), self-hosted Loki or an enterprise platform may make more sense for bulk volume, and PostHog Logs for the product-relevant slice. The product integration matters most when the log is debugging a user-facing issue, not when it's part of a compliance archive.
Proof point: OpenTelemetry-native ingest lets you route logs by severity, service, or attribute to multiple destinations, PostHog for product-context logs, your existing tool for the rest.
"PostHog feels like a web/frontend/analytics company. Can you handle our backend logs?"
Follow-up: What languages and services is the backend running, and what's the daily log volume?
Answer: Analytics roots make the company look web-shaped from the outside, but Logs is actually the most backend-focused app in the bundle: OTLP/HTTP ingest works from Node, Python, Go, Java, your existing Datadog Agent, or any HTTP client. Browser console capture via PostHog JS is an additional feature, not the primary one. Most of the "web-focused" customer feedback in our research was about historic instrumentation maturity (web SDK shipped first), not about backend logs – the ingest infrastructure is OpenTelemetry-standard and works from any backend.
Proof point: PostHog uses its own Logs app internally for backend services. The Datadog Agent drop-in means existing backend log pipelines work without rewriting.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Workflows is an automation builder that turns any product event, schedule, or cohort change into a multi-step flow – send emails, fire Slack alerts, push webhooks, update feature flags, capture new events – all on the same data your analytics, replay, and experiments already use. Triggers and the builder are free; messages start at $0.005 per send after 10K free per channel each month.
Zapier and Make have triggers but no product context. Customer.io and Braze have lifecycle email but need a CDP in the middle. PostHog Workflows reads the product data, acts on it, and feeds the agents that act on it – for example, our customer Grantable replaced Zapier outright and cut workflow setup time by ~90%.
The unique belief
PostHog's vision is a self-driving product: software that watches itself for bugs and conversion drops, then ships the fix while you sleep. The signal layer is well-covered with errors, replays, logs, analytics. What closes the loop is what happens next. Knowing a checkout error hit your top customer doesn't matter if no one is paged. The systems that act on signals almost always live somewhere else, behind a CDP or homegrown glue.
Workflows is the act layer. Every event, cohort change, error spike, or ticket update can trigger a multi-step flow, including sending a message and updating a person property, without leaving the platform the signal came from. PostHog AI drafts email copy today; soon, agents will design and revise workflows through MCP.
Zapier and Make have triggers but can't see product data. Customer.io and Braze send messages but need a CDP to know what users did. PostHog Workflows lives inside the signal itself, so the action follows automatically.
Who this is for
Teams already on PostHog paying separately for Zapier or Make. They're paying for triggers they could get for free, and stitching identity by hand to do it.
Engineer-led teams building product-led growth motions. They want to act on product events – onboarding milestones, activation drop-offs, feature usage – without a CDP in the middle.
B2B teams running intent-signal automation. Triggering sales follow-ups, Slack alerts, or Linear tickets directly from product behavior, not delayed by CRM syncs. (Croissant does this.)
Startups consolidating their messaging stack. Workflows replaces Zapier + Customer.io + a CDP.
Customers on Customer.io, Iterable, Brevo, or ActiveCampaign for transactional and onboarding email. Especially when most of the trigger logic already lives in product events. (Suped migrated off Customer.io.
AI-native teams building agent loops. PostHog AI already drafts email copy from a prompt; multi-turn, agent-authored workflows ship through MCP.
Who this isn't for
Teams that need deep email infrastructure (deliverability dashboards, sent/open/click/bounce tracking, suppression lists at scale) – Iterable, Braze, and Customer.io are more mature here. We might get there somewhere down the line.
Marketing teams running complex cross-channel campaigns with mature audience-segmentation tooling – the bundle is automation-first, not marketing-platform-first. (For example, Workflows doesn't have predictive segments. At some point we might get there but right now we still aren't the best tool for this use case.)
Teams who only want a messaging tool and don't care about the rest of PostHog – the bundle is the whole point.
Messaging
Message 1: Your data and your automated workflows live in the same place
Problem: Most teams keep product data in one tool and run automation in another. To connect them they sync data through a CDP or stitch identities by hand across Stripe, HubSpot, and Slack. The sync breaks, the schema drifts, and the workflow fires on stale data.
Solution: Workflows runs inside PostHog, on the same event stream your analytics, replay, and experiments already use. Every event, every cohort, every person property is immediately available as a trigger or an audience, without having to sync multiple tools. The data and the automation share the same identity by default.
Supporting features:
Triggers run on the same events that drive your analytics
Trigger on feature flag exposure, experiment variants, or any other product event
Update person state inside the workflow – no reverse data engineering needed
35+ destinations (Slack, Linear, Jira, GitHub, Discord, more) for fan-out
API and MCP access for programmatic workflow management
Message 2: React to product behavior the moment it happens
Problem: Sales finds out a customer churned a week later. Support hears about an error after a ticket comes in. Engineering learns a feature flag broke during the post-mortem. The signal is in the data the whole time, and the response is late because the data has to travel through three tools first.
Solution: Workflows reacts in real time. A 404 fires a Slack alert. An error spike opens a Linear ticket. A user upgrading triggers a HubSpot update. The action happens the same second the event hits PostHog.
Supporting features:
Real-time triggers on any product event – clicks, conversions, errors, feature flag exposures
Direct dispatch to Slack, Linear, Jira, HubSpot, Discord, and 35+ destinations
Schedule triggers for time-based playbooks; batch triggers for cohort sweeps
Branch on conditions, wait for events, or chain workflows together via captured events
Message 3: Cut three vendors down to one platform
Problem: Most teams pay for several layers to move product events into the tools their team actually works in. An automation builder (Zapier, Make) to handle triggers. A lifecycle messaging tool (Customer.io, Brevo, ActiveCampaign) to send the actual emails. A CDP (Segment, Rudderstack) or hand-rolled webhooks to keep identities consistent across all of them. Three bills, six contracts, and every new destination is another integration to build.
Solution: Workflows replaces all three. Trigger from any PostHog event and fan out to 35+ destinations natively: Slack alerts, Linear tickets, HubSpot updates, Discord pings, custom webhooks. (Grantable replaced Zapier outright and cut workflow setup time by ~90%. Suped consolidated transactional email off Customer.io.)
Supporting features:
One platform for triggers, conditions, dispatches, and audience updates
35+ destinations natively: Slack, Linear, Jira, GitHub, Discord, HubSpot, Google Ads, more
Webhook step for anything not covered natively
Predictable per-send pricing; no per-user, per-MTU, or per-task billing
Battle cards
vs Zapier (and Make)
Their approach: General-purpose automation builders. Zapier connects thousands of SaaS tools via pre-built integrations and per-task pricing. Make uses a visual scenario builder with more powerful branching, iteration, and data transformation primitives than Zapier. Both are built to connect tools that don't natively talk, meaning events go into them, events come out the other side.
Where PostHog wins:
The customer is already sending product events to PostHog and Workflows triggers on them directly, no separate integration needed.
Per-send pricing is more predictable than per-task as workflow volume scales.
Bundled with analytics, flags, and experiments means no leaving PostHog to debug a workflow.
Identity stays consistent across the stack; workflows don't break when a user property changes.
Grantable replaced Zapier outright and cut workflow setup time by ~90%. Croissant: "Workflows is better for us than Zapier. It's simpler, and lets us move faster without adding another vendor to manage."
vs Customer.io
Their approach: Lifecycle messaging platform with mature email deliverability, drag-and-drop editor, Liquid templating. Hybrid pricing: per-profile + per-email-send. Essentials starts at $100/mo for 5,000 profiles + 1M emails; overage is $0.009/profile + $0.12/1K emails. Recently repositioned as AI-native with an AI Agent, MCP server, AI segment builder, and AI translator. Channels include email, SMS, push, in-app, WhatsApp, LINE, webhooks.
Where PostHog wins:
Workflows triggers on the same events that already drive PostHog analytics – no double-instrumentation, no identity drift across two systems.
Per-send pricing (no per-profile fee) – cheaper for low-frequency, large-audience campaigns.
Bundled with analytics, session replay, and feature flags – no four-tool stack to maintain.
Suped consolidated transactional email off Customer.io after running both in parallel.
The customer is already paying for PostHog and sending the same events to both.
vs Brevo (and ActiveCampaign, Mailchimp)
Their approach: Mid-market email marketing platforms with full multi-channel reach, including email, SMS, WhatsApp, push, live chat. Per-month pricing based on email send volume (Starter from 5K emails, Professional from 150K). AI features under the Aura AI brand. Strong fit for SMB and mid-market marketing teams running email-first campaigns. Customer base includes Mont Blanc, Michelin, eBay.
Where PostHog wins:
Workflows trigger on product events, not just lists or segments, meaning the customer doesn't have to engineer their own event pipeline.
Bundled with analytics, flags, and experiments means workflows can act on product behavior the email tool wouldn't see.
Per-send pricing instead of per-month-volume tiers – simpler to model at scale.
Targets product-led teams whose buyer is an engineer, not a marketer.
vs Iterable / Braze
Their approach: Enterprise customer engagement platforms with comprehensive multi-channel reach (email, mobile, web, SMS/RCS, WhatsApp; Braze adds LINE and KakaoTalk), real-time decisioning AI suites, mature segmentation tooling, and analyst recognition (Gartner Magic Quadrant Leader). No public pricing (enterprise contracts only). Customer base: Wyndham, HelloFresh, Canva, Washington Post, Square.
Where PostHog wins:
Product-led mid-market teams who don't need a full enterprise customer engagement suite.
Engineers who want product events as the trigger source rather than CRM events or campaign builders.
Customer wants a working workflow this week, not after a Q3 implementation.
Bundled with the analytics, flags, and experiments product-led teams already use.
Per-send pricing, published openly, not quote-locked.
Objections
"Customer.io / Brevo has more mature email features – open/click/bounce tracking, suppression lists, dedicated IPs. You don't."
Follow-up: Are you running serious lifecycle marketing or product-triggered messaging? What email volume are you sending monthly?
Answer: True today – PostHog Workflows handles transactional and product-triggered emails well, but it isn't a full lifecycle marketing platform. Most teams using Workflows are sending behavior-triggered sequences (onboarding, activation, error alerts) where the value is in the trigger logic, not the email infrastructure. If the customer is running hundreds of thousands of monthly marketing sends with dedicated IPs and per-campaign deliverability dashboards, Customer.io or Brevo is the right tool today and we should say so. If it's product-triggered or transactional, Workflows works.
Proof point:Suped consolidated transactional email off Customer.io after running both in parallel.
"You don't have native mobile push or WhatsApp. Iterable and Braze do."
Follow-up: Do you need them shipping in the next quarter, or are they on your 12-month plan?
Answer: Honest: push, SMS templates, and WhatsApp templates are still rolling out – email is the production channel today, with SMS via Twilio and webhook for everything else. If the customer needs full native push and WhatsApp shipped now, an enterprise customer engagement platform is the right pick. If they can route push through a webhook to their existing push service while we build native support, Workflows handles everything else with PostHog product data attached. The roadmap is committed and tracked publicly in our Q2 objectives.
"We already use Zapier – why switch?"
Follow-up: How many of your Zaps are actually triggered by product behavior versus tool-to-tool plumbing? And what are you paying in monthly task volume?
Answer: Zapier customers usually have two patterns. Tool-to-tool plumbing (Stripe → Slack, Calendly → HubSpot) – fine to leave in Zapier. Product-behavior-triggered automations (onboarding flows, error alerts, upgrade nudges) – that's where Workflows wins, because the events are already in PostHog. Migration doesn't have to be all-or-nothing; many teams run both in parallel before consolidating. Per-send pricing is also typically cheaper than per-task once volume scales.
Proof point: Grantable replaced Zapier outright and cut workflow setup time by ~90%. Croissant framed it the same way: "Workflows is better for us than Zapier. It's simpler, and lets us move faster without adding another vendor to manage."
"Workflows is too new – how do I know it's stable?"
Follow-up: Is the concern reliable execution, feature completeness, or vendor lock-in?
Answer: Reliable execution is solid – Workflows runs on the same engine that powers PostHog's CDP destinations and data pipelines. GA'd in December 2025 after a public alpha and beta with hundreds of teams. Feature completeness is honestly still growing (batch triggers are in beta, push/WhatsApp templates are rolling out) and we publish the roadmap. Vendor lock-in isn't a concern: PostHog is open source, OpenTelemetry-compatible, and workflows can be managed via REST API and OAuth scopes for portability.
Proof point: Grantable's onboarding email flow ran 179 times in 7 sessions without issues. PostHog runs part of its flows on Workflows and is planning full migration.
These are instructions for internal in-app comms tools at PostHog. To do in-app comms of your own, check out surveys.
Occasionally, we use in-app messages to tell users about certain things. We recognize that in-app messages can be intrusive and we want to avoid spamming our users with too many of them, too frequently. For that reason, we're judicious about the way in which we use them.
We currently don't have a separate system for tracking in-app messages, so Brand currently owns the channel and is responsible for ensuring that messages aren't used excessively.
Types of in-app message
Currently, there are three ways in which we can send in-app messages.
Notification bar: A message displayed across the top of the page, activated using the Notification Bar app.
In-app prompt: A customizable pop-up which can be targeted to certain URLs and made to appear in the center of the page, or anchored in the corner. Activated using the prompt feature flag. More info.
Notifications: A notification which is pushed into the navigation bar, as a number on the bell icon. Activated using the changelog-notification feature flag.
How we use in-app messages
We use each of the three channels above for different purposes, guided by the needs of a message and the level of intrustion.
The notification bar is only used for messages which must be urgently communicated to all users, such as messages about service disruption.
In-app prompts can be used for a wide variety of purposes, including promotion of new features. However, users will only see one in-app prompt per day and should be targeted to appear only on relevant pages and to relevant users. In-app prompts shouldn't be used to message all users at once, or to direct users to another part of the app.
Notifications can be used for a wide variety of purposes and are minimally intrusive. We regularly use notifications to promote new features via the PostHog changelog.
Creating new in-app prompts
In-app prompts are intrusive to users, but can be used for a wide variety of reasons. Therefore, if you create one we ask that you...
Add the Marketing tag to the feature flag used to power your in-app prompt
This will enable others in the team to more easily keep track of what in-app messages are being shown, and what their content is. As a reminder:
Users will only see one in-app prompt per day, at most
In-app prompts should be used only on relevant pages and towards targeted cohorts
If you have any questions, please ask in #ask-posthog-anything on Slack.
Incidents happen. Each one is different and not all incidents require comms, but when they do we need to have clear processes in mind.
For this reason we've kept our guidelines as flexible as possible and focused on providing high-level guidance and responsibilities. In the event that an incident occurs we trust each others' judgement on when to adhere or deviate from these guidelines.
Appointing a Comms Lead -----------------------
During and following an incident, Product Marketing Managers (PMMs) generally assume responsibility for handling customer communication at a broad level.
If an incident is focused on a particular product and that team has a PMM focused on it, that PMM typically takes responsibility and becomes the Comms Lead.
If this is unclear or there's no dedicated PMM, then ownership should be decided by the available PMMs and a single Comms Lead should be clearly designated in the incident channel.
The role of the Comms Lead typically involves planning how we will respond at a high level by:
Creating a simple comms plan (who we talk to, what we say, and when).
Taking ownership of any large-scale communication to users.
Coordinating with Support, Sales, and Success so we don't duplicate or contradict each other.
Oh no --- all the PMMs are on holiday or asleep!
If this happens, the incident lead may appoint a Comms Lead from the Content Team or another team. If the incident lead fails to appoint a Comms Lead, Team Blitzscale should appoint someone to lead Comms.
Guidelines for Comms Leads --------------------------
These are principles to keep in mind during any incident:
Identify the per-product impact.
This helps scope the customer impact. Always clarify the impact on feature flags, experiments, and workflows especially. It's always worth asking how it impacts each product and if any data is lost, or merely delayed.
Don't rush external comms.
It's better to be slower and correct than fast and wrong. The status page and support tickets usually cover the early phase while details are changing quickly.
Default to transparency, not overcommunication.
We shouldn't send comms unless there's a definite impact and a clear story to tell. If we do send external comms, target owners and admins in impacted orgs where possible, rather than being too noisy.
Use the status page as the primary public channel.
The status page should be the main place we direct users to during an incident. Extra channels (emails, social posts) are the exception, not the rule. If a post-mortem is created, this supersedes the status page.
Aim not to send broad customer comms until an incident is resolved or a post-mortem is published.
Major or critical incidents will often have a public post-mortem – this should usually be the backbone of any wider comms. Don't communicate before resolution unless there is a strong need.
When handling a security incident: align with the incident lead in the incident Slack channel about public communication of security issues before proceeding. E.g. it could make sense to hold back communication of an attack publicly, as this could make the attacker aware that we are investigating already. This could it make harder for us to stop this attack for good. However, in some cases of data breach and security incidents, like the download of malicious packages, it is better to notify users immediately, in case the incident lead has identified that users can take action to prevent the malicious packages from spreading further.
What does the Comms Lead do? ----------------------------
At a high level, the Comms Lead is responsible for how we talk about the incident, not for fixing it. In practice, that usually means:
Join the incident channel immediately and make your role clear.
Stay in the loop without adding noise.
Read the summaries and updates, follow the thread, and avoid asking for updates just to "check in". Only jump in when you need information for comms, or have a specific ask.
Make sure the status page is accurate and up to date.
Check-in periodically to ensure the status is updated at least once every six hours, that the current impact is accurately described, and that the incident is closed when needed. The Incident Lead is responsible for these updates.
Decide whether we actually need outbound comms.
If we do, you should put together a plan for doing so (below).
When do we need to notify users immediately? For security incidents, like the download of malicious packages, in case the incident lead has identified that users can take action to reduce their risk, we should notify users immediately with clear steps how to act on their side. Product downtime that doesn't involve security breaches/attacks should be addressed after the incident is closed and we have the context needed to inform users.
Support the post-mortem process.
For major/critical incidents you may need to help shape and review the post-mortem with the incident lead and approvers (Tim and/or Ben, and Charles). Once published, use the post-mortem as the primary reference for any follow-up comms (emails, service messages, etc.), rather than rewriting multiple different explanations.
After a data breach/security incident the comms lead should contribute to the post-mortem by transparently addressing the impact, what went well, and what could have gone better.
Keep Sales and Support teams notified of impact.
Often these teams are dealing with the brunt of the customer response and your goal should be support them by giving them the information they need to respond effectively.
Handover to another Comms Lead, if needed.
Most comms can be handled quickly, but in the event of a long-running issue you should develop a plan to handover or continue monitoring the incident status.
These steps are a starting point, not a script. In practice, the Comms Lead's job is to keep communication accurate, calm, and useful --- and to reduce noise, not add to it.
Including the organization name in incident emails --------------------------------------------------
Plenty of people work across several PostHog organizations. Bulk emails should say which organization was affected, so users can easily check their billing settings, etc. It's worth doing for major and critical incidents — for anything smaller, use your judgement. There's no automatic way to do this, so it takes some manual setup.
Export the list of affected users as a CSV, with an extra column for the affected organization name.
If a user is affected under more than one organization, concatenate the names into a single field ("Org 1 and Org 2") rather than sending them one email per org.
Upload the CSV to Customer.io, mapping that column to a new attribute with a unique name. See Customer.io's guidance on mapping attributes.
Pull the attribute into the email with Liquid, and set a generic fallback that shouldn't ever appear.
Validating the export is the slow part of this, so leave time for it. Once you're all set, test and check the previews in Customer.io for a user or two to make sure the org names are correctly shown to their owners.
What does the Comms Lead not do? ----------------------------
The Comms Lead is typically not responsible for:
Updating the Status Page. This should fall to the Incident Lead.
Updating VIP customers. This usually is best handled by the Sales team.
Providing technical support to users. They can leave that to the Support team.
Making technical decisions about the incident. The Incident Lead will handle this.
To keep up with what's shipped across the company, join #changelog – what's just shipped. Owned by the Wizard & Docs team and updated constantly as PRs merge.
The channel is populated by agentic workflows that scan merged PRs and feature flag changes in the posthog/posthog repo and summarize them into it. Engineers can also opt their PR in (or out) manually via the Publish to changelog? checkbox on the PR template, or via the @posthog Slack app. See how to publish changelog for the full flow.
Tip: The @posthog Slack app can also answer questions about our own product data. @PostHog it in any channel to pull metrics or PR something to the website.
Marketing values
Be opinionated
Pull, don't push
No sneaky shit
1. Be opinionated
PostHog makes your product self-driving – that's the vision our marketing and content needs to reflect, and not dilute it with boring corporate-speak. (For the canonical positioning, see Brand foundations.)
When we write content, we take a firm stance on what we believe is right. We would rather have 50% of people love us and 50% hate us than 80% mildly agree with us.
How we say it – clear, direct, honest, and with room for genuine humor – lives in the voice & tone guide. The short version: we have a distinctive, weird company culture and we share it with customers rather than putting on a fake corporate persona. PostHog should not look like a generic software company.
(Sometimes we use terminology like 'value propositions' because that is the standard marketing term for a well-understood concept. That's allowed.)
2. Pull, don't push
_We focus on word of mouth by default._
We believe customers will judge us first and foremost on our product (i.e. our app, our website, and our docs). We won't set ourselves up for long-term success if we push customers into using us.
If a customer doesn't choose PostHog, that means either:
The product isn't good enough
The product isn't the right solution for them
We didn't communicate the product and its benefits well enough
We don't believe companies will be long-term customers of a competitor because they did a better job of spamming them with generic marketing. We know this because we frequently have customers switching from a competitor to us – they are not afraid to do this.
Tackling (1) is the responsibility of everyone at PostHog. The job of marketing teams is to avoid spending time advertising to people in group (2), and making sure we do a great job avoiding (3).
This means:
Making sure our comms are extremely high quality
Sharing our messages in the right places, where relevant users can see them
Spending enough time and/or money in those places so that our messages get through
3. No sneaky shit
Our ideal customers are technical and acutely aware of the tedious, clickbaity, hyperbolic marketing tactics that software companies use to try and entice them. Stop. It's patronizing to them and the marketing people creating the content.
For these reasons, we:
Don't use any analytics except PostHog. No Google Analytics, Facebook Pixel etc. Customer trust is more important than making our marketing team's lives easier.
Don't make claims about our product that are not 100% genuine and verifiable. And we don't make promises for future functionality either beyond what's already in GitHub.
Don't unfairly criticize or make false claims about our competitors. We will compare ourselves to them to help customers make a decision, and occasionally they will be a better solution for what a customer needs. And it's ok to have a sense of humor about this.
Don't bombard customers with 'deals', pop-ups, and other dark patterns. These devalue our product in the long term.
Don't pretend our customers are different from us – i.e. more gullible, more susceptible to marketing. We are an engineering-led team building products for other engineers. If you wouldn't like it, assume our customers wouldn't either.
When doing cold outbound, do it tastefully. When was the last time you read the 8th email a company sent you and thought 'ok yes, I now want to use this product'? Keep it low-volume, thoughtful, and relevant.
Marketing vision
Beyond PostHog's company mission and strategy, we have some marketing-specific areas we want to focus on.
Things we want to be brilliant at
Word of mouth mindset: We want to build a hugely successful company driven primarily by word of mouth, rather than paid ads or PR. This means being known for quality in all things we do.
Helping our ideal customers be successful: Through our docs, tutorials, newsletter, emails, video, and beyond, we help our ideal customers be more successful, both generally in their goals as founders and engineers, and as users of PostHog.
Launches: Our team ships a lot of products and features. We need launches to break through the noise and get noticed. This helps create the momentum products need to succeed.
World-class documentation: We work with product teams to maintain up-to-date, high quality docs. We work with Website & Docs to ensure users can discover them. Doing this enables users to "self-serve," discover what they need, and get the most out of PostHog.
Supporting YC founders: Lots of PostHog's DNA comes from Y Combinator. Their companies and founders are our ideal customers. We've done a great job being valuable to them (50%+ of batches using us) and want to continue to do so.
Merch: We make the coolest tech company merch. Let's keep it this way.
Events: We have been involved in some events, but we are still figuring out "the PostHog way" to do them. We don't just want to be a name on the sponsor list. We want to create superfans.
Social media: Specifically Twitter, where we've seen good traction posting on James' personal account and the PostHog brand account. We have been posting more on LinkedIn to promote the newsletter. We don't use any other social media channels.
Paid ads: We run a lot of paid ads on Google and others. It is fuel for everything else we are doing. We want to be good at this, but do it in a way unique to PostHog. We're not throwing everything at the wall and seeing what sticks. We have a minimum brand bar we need to hit.
Graphics: We're not the most visually focused team, but creating visuals and animations is a great way to communicate complex ideas. They also make for excellent content. Create a basic version and get the design pros on the to help.
Developer influencers: We sponsor creators like Theo and Fireship to drive awareness and signups to PostHog. Many of the influencers we sponsor don't work out, but the ones that work drive great results.
Billboards: Billboards are a way to get our brand in front of a lot of people.
Things we don't want to spend time on
Optimizing marketing spend: We're more concerned about growing fast than being the most efficient marketing team. Go fast, run experiments, look for upside.
Big, highly coordinated marketing campaigns: We can do them, but our reactive, short turnaround campaigns have been far more successful.
PR: If we do word of mouth well, our community will be far more valuable/credible than an appearance in TechCrunch.
Being cool and interesting people in online communities: There are a bunch of communities we could be more active in like Reddit and Discord, but we'd prefer to focus on our own community first.
Conferences. We're not a natural fit for conferences and being a small fish in a big pond isn't really our style.
Short-form video. We tried it, but it didn't work. Our audience might be there, but we're not flashy or dedicated enough to reach them.
We work with creators and influencers to make content about PostHog and sponsor placements that drive awareness and sign ups.
We're always open to inbound proposals. If you'd like to collaborate with us, email Adlet Smykov directly – we love seeing thoughtful ideas.
Our approach
Influencer marketing at PostHog is relationship building. We look for long-term partnerships with people our ICP already trusts, and the best creators are usually users first: we'd rather work with someone who genuinely likes PostHog than someone with a much larger audience and no connection to the product.
We also optimize for recurring collaborations over one-off sponsorships. When a creator works with us across several launches, PostHog becomes a natural part of their story, which beats any single ad read.
Creator lifecycle
A sponsorship is the start of a relationship. The ideal lifecycle looks something like:
Most of the value shows up in the later stages, so it's worth investing early in creators you can see yourself working with again across launches.
Sourcing and evaluating influencers
You can find new influencers by looking at the creators engineers share or mention internally, searching for ones who have made relevant videos, looking at the recommendations of ones we've already sponsored, inbound, and Kuli (an AI-powered influencer discovery tool).
Don't limit yourself to individual creators. Great partnerships often come from other places too:
recommendations from existing creator partners
agencies
conferences and IRL events
founders building interesting products
people actively sharing what they've built with PostHog
The creator economy is surprisingly small. Building a good reputation compounds over time, so investing in long-term relationships is usually more valuable than constantly sourcing new creators.
When you're evaluating a specific creator:
Their audience needs to be relevant to us, ideally targeting our ICP, but broadly engineers and founders.
Even within this group, there are some categories to avoid like job interview prep, career growth, low-level engineering, and heavy computer science focus. Try to find web or mobile developers, product engineers, startup founders, and indiehackers instead.
The channel is growing, gaining in subscriber growth rate and views. Use Social Blade to see this.
They should have engaged audiences. Strong Twitter or Discord communities are good signs as well as view to like/comment ratios:
Above 5k views per video. Anything below this is just not worth your time. This number will likely grow over time. Larger influencers, although they charge a lot more, are often more efficient, so we don't have an upper limit for size.
Formats behave differently too. Long-form YouTube is still our strongest acquisition channel, while podcasts, Instagram, TikTok, and other short-form content are areas we're still figuring out. Don't expect direct sign ups from every format – short-form often does more for awareness, education, or reaching audiences we wouldn't get in front of otherwise.
Working with agencies
We increasingly work with agencies to help scale sourcing and relationship management.
Fundlevel, a Canadian agency, is a long-term partner we really enjoy working with.
Agencies are particularly useful when:
expanding into new regions
testing new creator categories
increasing the number of collaborations without increasing internal workload
They're less useful for strategic partnerships or flagship creators, where a direct relationship with PostHog matters more. Treat them as an extension of the team.
Negotiating with influencers
Make sure you know what type of slot it is: pre-roll, mid-roll, end-roll, integration.
Ask for examples of other ad slots they've run to judge the quality of ad read.
For creators we've never worked with, the initial quote is often negotiable. Understand the value of the placement before agreeing on a price, and use our pricing model as a reference rather than treating the first quote as fixed. Feel free to update the model if you think it's not accurate.
Make sure the link is in the top 3 lines of the description.
We pay invoices net 30 (30 days after they've sent them to us).
Working with PMMs
Influencer marketing works best when we're involved early. If a big launch is coming and the dates are known, post in the #influence-wrangling channel in Slack a month ahead (or as soon as you can). That gives us time to prep creators, fit into their schedules, and come up with a story that works the new product into their content naturally.
For launches, we generally need:
product context
messaging
demo access
visuals
launch timelines
someone available to answer technical questions
What should the placement actually look like?
Make a judgement call on whether to use a unique link set up with Dub (like https://go.posthog.com/sponsored) to point to specific UTMs unique to each video or an influencer-specific link using posthog.com redirects (like posthog.com/theo) to the same UTMs across videos. These links should have utm_source and utm_campaign set to the influencer and campaign name.
Make sure they tell their audience to "mention them on sign up" or "say that they heard about PostHog from them" so we can track the attribution.
We generally let influencers decide what the ad read is like so it best fits their audience. We can provide guidance on what to talk about though – our brand foundations go deeper, but the key points to get right:
The frame everything should ladder up to: PostHog makes _your_ product self-driving – it puts all your product's data in one place, turns it into signals, and uses agents to find problems and opportunities and ship the fix. Keep the creator's product (or their viewers' products) as the thing that becomes self-driving; avoid "PostHog is self-driving software," which centers us instead of the outcome.
PostHog is the platform for self-driving products – a suite of tools that gives developers (and their AI agents) everything they need to build successful products. Don't call it "an analytics platform" (we've grown well beyond that) or pitch it as a single product.
Be specific rather than benefits-y. Developers can smell marketing fluff instantly, so "it does X" beats "it empowers you to unlock X."
The suite spans product analytics, web analytics, session replay, error tracking, experimentation, feature flags, AI observability, and surveys. There's also a CDP for sending data to 50+ destinations and a data warehouse that connects to external sources like your database, Stripe, or Hubspot so you can query them with SQL (or no-code insights) alongside your product data.
All of this exists to help founders and engineers debug their product, understand their customers, and ship a more successful product faster.
There's a generous free tier for every product – you can sign up and start using all of them for free right away, and 90% of users stay on PostHog's free tier.
Setup is simple: install an SDK or paste a snippet into your site header, and we autocapture data like pageviews, clicks, and sessions. There are SDKs for all the popular backend languages too – Python, Node, Go, and so on.
There are a handful of video assets for them to use here. Feel free to add more, but also suggest the website and in-app as sources.
Ideally, a placement should relate to ongoing marketing efforts, like a new product launch, product push, or pricing change.
Measuring impact
Some metrics we look at for individual videos include:
CPM (cost per thousand views)
Unique sessions from the custom link (or clicks if you're using a Dub link)
Sign ups, either from converting from sessions or who mentioned the influencer on sign up
We track these on our marketing budget and spending spreadsheet. For a per-influencer and per-video breakdown, HogWatch joins that sheet with live sign up attribution and YouTube view counts. We also have an influencer marketing performance dashboard in PostHog that can help you get an overall view of different influencers' performance.
Attributed sign ups aren't the whole picture though. Some partnerships are valuable because they:
introduce us to new audiences
build long-term brand affinity
lead to future collaborations
generate clips that can be reused across channels
strengthen relationships with creators or platforms
are just really cool and worth doing for taste/vibes
Relationship management
We treat creators as people, not inventory. Good partnerships take months or years to build.
Reply quickly.
Give thoughtful feedback.
Celebrate good work.
Stay in touch between campaigns.
Meet creators in person when it makes sense.
The aim is for creators to think of PostHog first when they have a new idea, and to feel comfortable bringing us the weird ones.
Events and conferences
Conferences pay off through the people you meet more than the talks. In 2026 we've been to Stripe Sessions and VidCon, and both helped us meet the right people and grow our creator roster.
The biggest benefits usually come from:
meeting creators
meeting agencies
meeting platform teams
strengthening existing relationships
making introductions that continue after the event
If possible, prioritize speaking, hosting dinners, or organizing meetups over just attending.
Current experiments
We're constantly experimenting with new distribution channels. Current areas we're exploring include:
podcasts
Instagram & TikTok creators
startup founders as creators
agency partnerships
creator dinners and other IRL events
Not every experiment will work, and that's fine. Document the results and share what you've learned so the next person doesn't have to repeat the same experiment.
How PostHog's automated onboarding and lifecycle emails work in Customer.io, and what to do when you launch a new product. Aimed at product marketers. These are the patterns we use today — conventions, not hard rules. Build something new when a launch calls for it.
Launching something, or want a second pair of eyes? Joe Black owns customer comms — loop him in early.
This is about marketing onboarding (emails new users get automatically), not the Sales/CS onboarding program. For the underlying email setup — topics, unsubscribes, sending addresses — see email marketing.
How the system works
Four layers, stacked:
Data — events and attributes synced from PostHog (user signed up, user showed product intent, activation events).
Segments — saved groups built from that data ("signed up but not activated", "interested in flags").
Campaigns — the automated flows: triggered by data, branched by segments, and they exit people on conversion.
Subscription topics — the consent category each campaign sends under ("Welcome emails", "Changelog updates").
Two data concepts drive most of the logic, and both are owned by Growth Engineering — so if they don't exist for your product yet, that's step one:
Product intent — which product someone actually came for (primary, secondary, or basic), from the user showed product intent event.
Activation — whether they got value, defined per product by a qualifying event or set of events.
Segments come in families
There are hundreds; you only need the families. Before building one, check it doesn't already exist — duplicates are the biggest source of mess. Prefer dynamic (auto-updating) over static lists.
| Family | Purpose | | --- | --- | | Hygiene / deliverability ("Unsubscribed", "Valid Email Address") | Protect deliverability — almost every flow excludes these | | Instance & geography ("All Cloud Users", "Self-hosted Users") | Who can be messaged, and how | | Lifecycle / recency ("New Signups", "Logged in last 30 days") | Where someone is in their journey | | ICP / role ("High ICP", "Org owners or admins") | Tailor by fit and seniority | | Product intent ("Primary Intent: Session Replay") | Route people to content for the product they care about | | Activation ("Activated – Replays") | Know who succeeded, so we stop nudging them | | Beta ("Beta Users – Error Tracking") | Follow up with beta participants | | Programs ("Startups & YC") | Power program-specific flows |
The core flows
| Flow | Trigger | What it does | Goal | | --- | --- | --- | --- | | Onboarding 8.0 (flagship) | user signed up | 130+ emails that branch on product intent and behavior to tailor the first-run experience | Activate within 7 days | | Long-running onboarding | user signed up | Slower, spaced-out nurture over a longer window | Logs in again | | Waitlist, Alpha, Beta onboarding | $feature_enrollment_update | Branches on $feature_enrollment_stage: waitlist confirmation (concept), rough-edges warning (alpha), or a feedback ask after 5 days (beta) — you get this free for every early access feature | Collects feedback, activates a product | | Startups & YC | enters a segment | Program-specific content (credits, job board, integrations) | Activation |
The idea behind the flagship: it's intent-aware and activation-aware — it sends people content about the product they came for, and exits the moment they activate. (Avoid Customer.io's legacy "behavioral" campaign type for anything new — it silently excludes existing and backfilled people.)
The Waitlist, Alpha, Beta onboarding flow
Every early access feature gets lifecycle emails automatically. When someone joins a waitlist or opts in to a feature preview — in the app, or via a waitlist form on posthog.com — posthog-js fires a $feature_enrollment_update event carrying $early_access_feature_name and $feature_enrollment_stage. These events reach Customer.io through the "Send events to Customer.io" data pipeline destination, and any $feature_enrollment_update with both properties present triggers the flow.
The flow immediately segments on $feature_enrollment_stage:
concept — an immediate, simple confirmation that they're on the waitlist.
alpha — an immediate email warning of rough edges and asking for feedback.
beta — a 5-day wait, then an email asking for feedback on the beta.
When a feature's stage changes from concept to alpha or beta, everyone who registered interest is automatically opted in to the new stage and PostHog fires a user moved feature preview stage event (with from and to properties) for each enrolled person. When from is concept and to is alpha or beta, we send an email letting them know the feature is enabled and now available, and asking for feedback.
All beta feedback is centralized to the beta-feedback@posthog.com Google Group. Replies to this address are relayed into the #posthog-feedback Slack channel for everyone to see. PMs and team leads are encouraged to respond to and action this feedback for their alpha and beta releases, and to give merch credits as a thank you where appropriate.
The personalized "next steps" block
Inside the onboarding emails is an email with a block that recommends each person's best next product, based on what they've already activated and shown intent in. One quirk shapes how it's built: Customer.io's Liquid can't read segments or event history — inside an email you only get the person's profile attributes. So we copy segment membership onto attributes first:
Segments → "Attr sync" campaigns → attributes → email content. For each Activated/Intent segment, a tiny seg_attr campaign fires when someone enters it and runs one Update attributes action — no email, it just writes data. They share an Attr sync name prefix so they group together.
The email's Liquid reads these to pick the person's top un-activated product (biased toward their primary, then secondary intent) and personalizes the bullets, subject line, headline, CTA, and a closing "ask PostHog AI this" prompt — all tied to that same product. The editable copy lives in aligned lists at the top of the snippet, which lives in the email in Customer.io (ask Joe Black for the current version).
If you edit the Liquid: variables are per-block (include the logic in every block/field that uses it — including the subject), and use single quotes only (code blocks HTML-encode double quotes and break Liquid).
Launching a new product: the checklist
Not every step applies to every launch, but this is the path of least surprise:
Confirm intent + activation exist (Growth Engineering owns these). Without them the system is blind — do this before public beta.
In beta, lean on what's there. The Waitlist, Alpha, Beta onboarding flow already collects feedback for every opt-in, for free. Want more? Build a "Beta Users – [product]" segment and a small, single-purpose flow.
Decide: extend or build new.
Extend Onboarding 8.0 for a core product — add your intent branch and a few product emails to the main flow. Usually the right call.
Build a standalone flow for a distinct audience or behavior — event trigger for "when X happens", segment trigger for "everyone who is X".
Build the segments you need (intent, activation, plus any launch-specific audience).
Wire up the flow — trigger, entry filters, delays and send windows, branches, a real conversion goal, exit-on-conversion, subscription topic, and keep message limits on.
Add it to the personalized recommendations, if it should appear there (see below).
Test, then launch — preview and test-send every message, sanity-check the branches, move from draft to live, then watch conversion to activation.
Adding a product to the personalized recommendations
Source segments must exist — an "Activated – [product]" segment and "Primary/Secondary Intent: [product]" segments (from step 1 above).
Create the "Attr sync" campaigns — one seg_attr campaign per segment that sets the attribute (activated_[product] = "true", or intent_primary_product = "[product]"). Launch each with backfill so people already in the segment get the attribute, not just new entrants.
Add the product to the snippet — its key, display name, app URL, and recommendation sentence to the aligned lists (keep them the same length and order), its activated_[product] check, and its PostHog AI question.
Test against a profile with the new attributes set.
It's fiddly and easy to get subtly wrong (misaligned lists, or a campaign that wasn't backfilled) — loop in Joe Black rather than guessing.
Rules of practice
Respect consent — pick the right subscription topic, and never email unsubscribed users.
Always exit on conversion — stop the moment someone activates.
Set a real conversion goal (almost always activation) so you can tell if the flow works.
Keep message limits on — people are in several flows at once.
Prefer extending the main flow over rebuilding.
Name things clearly, and check for an existing segment/campaign before creating a near-duplicate.
Test before you launch.
These are conventions, not a cage — launches often need something the structure doesn't quite cover, and that's expected. For anything substantial (a new flow, a big change to the main campaign), talk to Joe Black first.
We do three types of sponsorships - commercial, charitable, and open source.
Measuring attribution directly is basically impossible with sponsorship activities, so we try hard to make sure we are targeting the right channels by validating opportunities properly first. We like to make sure their target audience is in our ICP and test with smaller amounts when possible.
Commercial sponsorship
Although we've done a variety of commercial sponsorships, including newsletter ads, podcasts, and billboards, we're mostly focused on sponsoring influencers to drive awareness and signups to PostHog.
We track these sponsorships in our marketing budget and spending spreadsheet.
Ian Vanagas has the contacts for these people if you want them.
We sponsored a variety of newsletters to drive subscriptions for our newsletter, build mode, but have put that on pause as we revaluate the quality of the subscriptions we're getting.
Charitable sponsorship
We are looking to partner with charities who are aligned with our mission of increasing the number of successful products in the world. These partners are likely to focus on giving greater access to under-represented groups in tech.
PostHog is an open-source developer platform built on top of many other amazing open-source projects. We believe in open-source and the open-core model. However, many open-source projects go underfunded.
We are investing in open-source, not just as a business, but directly via sponsorship in key projects we benefit from every day. We're doing this for three reasons:
We want valuable open-source projects to continue to be maintained and enhanced
We fundamentally rely on some open-source projects, and it's essential they continue to be maintained and enhanced
We believe the PostHog brand will benefit from the sponsorship
If you know of a project that is fundamentally important to PostHog, add the project to this page via a PR and tag Charles. If we decide to sponsor, we can set up the sponsorship via either Open Collective or GitHub. To get an invite to Open Collective, create an account first with your posthog.com email address and then ask Charles to invite you.
If you have a general marketing question, go to #group-marketing-and-content in Slack.
If you need help with the website, go to #posthogdotcom.
Product marketer (PMM) and product manager (PM) assignments
We generally only have product marketers on teams that _already_ have a product manager. Products without a product manager a) are usually too early for marketing to get involved, and b) distract engineers as they need to spend time briefing the product marketer, vs. shipping more stuff. Product managers help teams figure out what to build and how much to charge for it, product marketers then help you get as many users as possible.
We only add a dedicated product marketer when it becomes painful not to have one. Until then, the existing team supports newer products on the side, so we don't hire ahead of need or bloat the team. Ongoing marketing for a tool beyond its initial launch is covered by the individual PMM in the context of their product – e.g. Joe covers how you can create Experiments using the PostHog MCP.
| Product | PM | PMM | Blitzscale | | ------------------- | ------ | ------ | ---------- | | Context warehouse | Anna | Lizzie | Raquel | | PostHog Desktop | Annika | Cleo | Raquel | | PostHog Slack | Annika | Cleo → new hire | Raquel | | PostHog Web | Annika | Sara | Raquel | | PostHog Research | n/a | Joe | James H | | PostHog MCP | n/a | Joe | Raquel | | PostHog CLI | Unassigned | Unassigned | Raquel |
Cross-functional areas
These are some other areas that PMMs own outside of specific products.
Research – Joe
Incident comms – distributed, ask in #team-marketing if you need help
Lifecycle (i.e. email) & aligning with eng – Joe
Initial small launches for new products – Joe
Startups & partnerships – Joe
<summary>I need a product marketer, but my team hasn't been assigned one</summary>
Just ask in #team-marketing in Slack and tag Joe Black.
<summary>I'm interested in running, attending, or speaking at an event</summary>
<summary>Someone wants us to sponsor them</summary>
If it's an influencer, newsletter or podcast, refer them to Adlet Smykov.
If it's an event, speak to .
<summary>I want to create a video, or have a video idea we should try...</summary>
To start with, post ideas in the #content-and-video-ideas Slack channel. Alex van Leeuwen and Jordo Dibb on the content team are your main points of contact here.
Please also read How we do video at PostHog. We're still figuring things out, though, so very interested in suggestions.
If your idea is for PostHog Stories (HogTok), hit up Edwin Lim as well.
<summary>A customer is interested in doing a case study with us</summary>
Speak to Joe Black, Cleo Lant, or Sara Miteva.
<summary>A customer has an issue with merch</summary>
Please share in the #merch channel. Kendal Hall owns fulfillment issues. Lottie Coxon owns merch design and creation. Eli Kinsey and Ian Matson own the storefront.
<summary>I have a question / problem / suggestion for the website</summary>
The website is owned by Eli Kinsey and Ian Matson. Generally, the best place to ask is the #posthogdotcom Slack channel.
For larger pieces of work — a new product page, a significant copy overhaul — read Working with the website team for the process to follow.
<summary>Hey, can we run some paid ads for my product?</summary>
We probably are already, but if you have something specific in mind, ask in the #team-demand-gen Slack channel.
<summary>I need a new hedgehog design, illustration, or other art asset.</summary>
Direct them to press@posthog.com, where one of Joe, James, Charles, or Tim can respond. They're the only people who should speak to press. See: Press & PR
Paid ads sit with the . They have two jobs: capture demand that already exists and introduce PostHog to people our brand and content do not reach on their own.
We broadly split our budget 50/50 between conversion and awareness.
Ads are expensive, so we typically only advertise individual tools once they are generally available, have pricing, and have a feature set broadly on par with the main competitors.
Unlike most demand gen teams, we do not optimize for demo bookings. PostHog is self-serve, so our ads should help someone understand the product and start using it without talking to sales. We're very much a PLG company and are proud of it. However, we may add some ABM ad efforts in the future.
How we run paid campaigns
Every meaningful campaign should move through the same loop:
Propose: Define the audience, problem, hypothesis, objective, budget cap, creative, landing page, success metric, and what we will not be able to measure.
Launch: Use consistent campaign names and unique UTMs, QA the PostHog events and CDP destinations, confirm the budget cap, and set a decision date before spending.
Evaluate: Check delivery and tracking after five days, leading indicators after ten days, audience and creative quality after two weeks, and conversions in three to four weeks, depending on the objective.
Learn: Scale, change, or stop the campaign, write a brief postmortem, and share creative and landing page findings in #group-marketing-content-brand.
We run experiments on a rolling basis to improve performance, but we work hard to avoid testing paralysis. If something works, we go for it; if it does not, we try something new. We do not fix what is not broken, but no campaign should go more than 30 days without a touch from the demand gen team, and we do not spend budget just because it is available.
How and when we use LLMs for paid ads
Demand gen is a small team, so using AI to extend our capacity is critical, but we limit it to optimization with a human in the loop. We use a Scout to keep tabs on current campaign and creative performance via messages in Slack, and the Windsor.ai and PostHog MCPs to investigate the data.
All campaign ideation, creative work, strategy, media plans, and monthly Growth Reviews are designed and written by humans.
How we allocate budget
We use a 50/50 conversion and awareness split to make sure that we're educating as much as we're driving lower-funnel conversion, then adjust within each half:
Conversion: Cap Brand before it hits diminishing returns, and work to increase the success of our product campaigns to get within striking range of our brand ads.
Awareness: Use a mix of video, UGC, static, and content ads, with smaller budgets for new channels and creative tests.
Experiments: Design them with a smaller budget, a clear goal, and a date to decide whether or not to move forward with the campaign.
We are not moving away from conversion campaigns. Search will remain the backbone of PostHog's ad strategy because we must always be ready to capture high-intent conversions. We're scaling awareness campaigns as they bring the right people to PostHog at an efficient cost without annoying potential users with an onslaught of repeated ads.
Brian Young and <a href="https://www.heydigital.co/">Hey Digital</a> build the next month's media plan one week before that month starts, while Brian is preparing the Growth Review. Charles Cook approves the monthly cap at the same time. The media plan is not set in stone, and we update it as reporting comes in.
We use Engaged Visits and platform delivery metrics for early decisions, then compare those signals with signups, Healthy Orgs, and revenue as the results mature. Brian uses that data to reallocate budget within the monthly cap. When spend needs to exceed the cap, Brian and Charles work through the increase together, update the media plan, and record the decision in the Growth Review.
How we measure campaigns
Ad platforms deliver the ads and help us diagnose delivery via CTRs and impressions. Because we do not use their third-party pixels, we're somewhat limited in how effectively we can use their algorithms. The PostHog CDP still sends conversions back to each platform in the form of Click IDs and hashed user emails for use in tCPA/tROAS campaigns and to share data on the success of our awareness campaigns.
PostHog's Context Warehouse is the data backend. The paid marketing dashboard is the live view, the media plan is where we keep budget and pacing, and the monthly Growth Review is where we make and record decisions.
Conversion campaigns
We use the following sequence to judge conversion campaigns:
<PrivateLink url="https://us.posthog.com/project/2/insights/EyekVfx2"><strong>Non-freemail signups</strong></PrivateLink> tell us whether a campaign is attracting people using work emails. They function as a canary for newer tool ad campaigns and validate changes to ad copy and landing pages.
<PrivateLink url="https://us.posthog.com/project/2/data-management/events/billing%20subscription%20activated"><strong>Billing activation</strong></PrivateLink> is a useful leading indicator, but activating billing does not guarantee that an organization will pay an invoice.
<PrivateLink url="https://us.posthog.com/project/2/insights/Z0ZA1hLR"><strong>Healthy Orgs</strong></PrivateLink> are the quality indicator.
Revenue is a lagging result and needs roughly three months to mature, so we use it to validate long-term effectiveness, not to judge or pivot ad campaigns month to month.
See the Google Ads report for non-freemail signups by product over the last 12 weeks.
Awareness campaigns
Depending on the campaign objective, we use a combination of impressions, reach, frequency, completed video views, unique paid visitors, and Engaged Visits to judge awareness campaigns.
An Engaged Visit has at least two pageviews, an autocaptured interaction, or 10 seconds on the site. Its purpose is to indicate whether the audience and creative lead someone to engage with PostHog in a way that suggests they are interested in our offering and want to learn more.
What we cannot measure perfectly
We cannot track people across devices. This means:
An ad seen on a phone or connected TV will not receive credit when someone later signs up on a computer
First-visit attribution tends to favor branded search
Platform-reported conversions and PostHog conversions will not always match
This lack of attribution is a bit of a barrier, but we do have some qualitative data from the signup referral report, based on what people tell us during signup. However, this data is noisy and really only gives us insight into the channel, not the creative or campaign that resulted in the conversion.
We treat awareness metrics as directional and only use conversion metrics for decisions they can support.
Channels
We currently run ads on:
Google Search – _conversion_ (non-freemail signups and Healthy Orgs)
Reddit – _awareness_ (impressions and Engaged Visits)
Meta/Instagram – _awareness_ (impressions and Engaged Visits, experimental)
LinkedIn – _awareness_ (impressions and Engaged Visits)
X – _awareness_ (impressions and Engaged Visits)
YouTube – _awareness_ (video views and completion rate)
Connected TV – _awareness_ (video views and completion rate, experimental)
We have previously tried and no longer use ChatGPT ads, Bing, Product Hunt, Carbon Ads, and Google Display because they did not help us meet our goals and distracted us from honing in on our best-performing ad platforms. We may try them again in the future as capacity allows.
Where a channel allows it, we focus on the US, Canada, UK, Germany, and France. We prefer targeting desktop users when the goal is conversion because PostHog is mainly used on desktop.
Privacy and conversion optimization
We use PostHog and the PostHog CDP instead of third-party trackers or pixels like Google Tag Manager.
We follow these principles:
If it creates third-party cookies for us, do not do it
Do not share raw user PII contained within PostHog, including IP addresses
Collect only what is _absolutely_ required
Be transparent with users about what we collect
Click IDs are considered safe to send back to the relevant ad platform
Unless someone has opted out through our privacy policy, signup and newsletter email addresses are hashed and considered safe to send back to the relevant ad platform
Creative and landing pages
We change up campaigns frequently, but generally advertise the PostHog brand, self-driving, and individual products. All current copy can be found in the search ad copy sheet, and it is updated regularly.
We test both unhinged and enterprise coded ads. More and more, we find that enterprise coded ads perform just as well as, or slightly better than, our unhinged versions, but we feel experimenting with unhinged copy and ads is important for the brand.
For static creative, request artwork from the using the art request process, or, if it is generated by Hey Digital, submit it in #design-review to be checked by Lottie Coxon. For video, start with #team-video. For UGC, we get most of our content from #influence-wrangling via Adlet Smykov. We run ads from 6 to 60 seconds and from 9:16 to 16:9 because Shorts, Reels, YouTube, and connected TV have different completion rates and placement requirements.
We sometimes spin up landing pages for tests. Simplified versions of our docs outperformed previous product pages, but has now designed the existing product pages to use a similar format. When a landing page teaches us something useful, we pass the result to the website team rather than maintaining a permanent fleet of ad-only pages that may become out of sync with products as we ship new and better features.
Partners and roles
We work with Hey Digital to set up campaigns, lightly modify existing content for ads, help with some web design, and provide a second pair of eyes on pacing and spend. We share a Slack channel for day-to-day communication, and Brian Young has a monthly check-in with them.
We also have monthly calls with partner teams at Google, Reddit, and LinkedIn. Their advice can help diagnose platform performance, but PostHog data decides whether a campaign is working for us.
Within the demand gen team:
Brian Young owns the relationship with Hey Digital, ad platform partner teams, budget, channel strategy, analytics, and reporting
Jonah Svihus writes copy and develops creative across platforms, including video scripts
Charles Cook reviews copy, approves the monthly media plan cap, and joins the monthly Growth Review
Growth review
Brian Young runs a monthly Growth Review with Cory Slater, and Charles Cook. It is shared in <a href="https://posthog.slack.com/archives/C0ALU3889A6">#group-marketing-content-brand</a> and <a href="https://posthog.slack.com/archives/C06LMMS3YP4">#team-blitzscale</a>. We use it to reflect on the previous month's performance and plan the next one using leading indicators, while also checking longer-term performance through lagging results. It covers our broader marketing funnel, including organic, paid ads, and influencer spend.
See the Growth Review source sheet and monthly commentary.
We're frequently contacted about revenue-sharing partnerships, or individuals and agencies that want to be listed as official partners. Also, technology integrations!
If someone contacts you about partnering with PostHog, refer them to our partnerships page and ask them to complete the survey there. This will directly alert relevant teams internally.
Users who contact us about wanting support from a partner often want particular types of help. We've curated some resources below which we can give them so they can self-serve where possible.
Migration help
If a customer contacts us about migrating data into PostHog we should first refer them to the Sales & CS Team, who will triage them. We also have guides to help teams migrate data on their own.
Sometimes teams want help or advice on their event taxonomy, or creating specific insights. Users who look like they have the potential to pay >$20k should generally be referred to the Sales & CS team, otherwise they should go through the regular support flow. We also have a wide variety of dashboard templates and tutorials to help teams get started.
If users need more help than we can reasonably provide, they may ask for external support or partners. We do not have any official partners and users should know that any suggestions we may make are not vetted or accreddited in any way.
That said, some users have found success working with the following external partners:
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Analytics covers funnels, retention, trends, user paths, correlation analysis, and SQL – with autocapture so you never miss the event that mattered. Every graph links directly to the session recordings and feature flag states behind it. And because analytics is built into the same platform as replay, flags, experiments, and the data warehouse, agents can query it mid-loop without switching tools.
Amplitude and Mixpanel tell you what happened. PostHog tells you what happened and lets you act on it.
The unique belief (in terms of analytics)
PostHog is building the infrastructure for self-driving product development. The product autonomy loop – signals in, work out, evaluation, repeat – only closes if agents can measure whether their changes worked. Analytics isn't the end of the workflow; it's the truth the entire system runs on. Every funnel, retention chart, and correlation PostHog generates is a queryable signal. PostHog Desktop re-queries those same dashboards post-merge to evaluate its own work, or you can manually query the data yourself either via the MCP or with PostHog AI.
Analytics is the memory of everything users have done. Self-driving development is impossible without it.
Who this is for
Engineer-led product teams who want to understand user behavior without waiting on a data team.
Teams consolidating from Amplitude or Mixpanel who also want session replay, feature flags, and experiments in one platform.
B2B SaaS companies who need group/account-level analytics alongside individual user behavior.
Teams building AI-native products who need LLM observability and product analytics in the same place.
Startups moving fast who need autocapture to catch events they forgot to instrument.
Who this isn't for
Teams who need advanced cohort modeling and data science workflows – other platforms have more mature statistical tooling here.
Enterprises needing deep data governance (e.g. warehouse native requirements) without also adopting the broader PostHog platform.
Messaging
Message 1: Analytics that feeds your agents, not just your dashboards
Problem: Agents that only generate insights and dashboards are read-only. The product autonomy loop requires a system that can query product metrics, interpret the result, and use it to decide whether a change worked.
Solution: PostHog exposes every insight, dashboard, and HogQL query to PostHog Desktop, the MCP, and other agent runtimes. Agents can build dashboards, check event volume, and measure impact, and suggest changes based on results – all from within the loop, without human intervention.
Supporting features:
MCP: lets agents query PostHog from Claude Code, Cursor, and any MCP-compatible runtime
HogQL: full SQL access on your event stream
Autocapture: instrument your product retrospectively, not just prospectively
PostHog Desktop: The self-driving product development platform
Message 2: Autocapture means you never miss the signal that mattered
Problem: Traditional analytics starts too early and answers too late. You have to instrument an event before you know it matters, then wait around for data after the decision window has closed.
Solution: PostHog's autocapture records clicks, pageviews, form submissions, and rage clicks from the moment you install the SDK – no manual instrumentation required. You can always go back and analyze behavior you didn't know you'd need. And installation is easy with the Wizard!
Supporting features:
Autocapture on web and mobile
Retroactive event definition – define events from captured data after the fact
PostHog AI: ask questions about your data in plain English
Message 3: One platform – analytics, replay, flags, experiments, warehouse
Problem: Amplitude + FullStory + LaunchDarkly + Optimizely + Segment = five vendors, five bills, five contracts, five sets of data that don't talk to each other without custom integrations.
Solution: PostHog covers the full product intelligence loop in one platform. Every metric links to the sessions behind it. Every experiment is built on feature flags. Every flag state is queryable alongside product events.
Supporting features:
1M events/month free, forever – no time limit
No seat-based pricing
Group analytics for B2B account-level insights
Direct SQL access via HogQL and the data warehouse
Battle cards
vs Amplitude
Their approach: Deep analytics with advanced behavioral cohorts, data science integrations, and a mature product. Seat-based pricing. No native feature flags.
Where PostHog wins:
Usage-based pricing – no seat charges as your team grows
Native session replay, feature flags, and experiments included
PostHog Desktop agent integration; Amplitude has no equivalent
1M events/month free tier is more generous than Amplitude's
vs Mixpanel
Their approach: Clean, event-centric analytics with strong mobile support. No native feature flags. MTU-based pricing can surprise at scale.
Where PostHog wins:
No MTU pricing – pay per event, not per user, with a huge free tier
Experiments, feature flags, and more included
Full SQL access without a separate data warehouse
Also we have a data warehouse
Mixpanel has no equivalent to PostHog Desktop
Objections
"Amplitude has better analytics features"
Follow-up: Which features specifically? Let's check what you actually use.
Answer: Some Amplitude-specific features are more mature – particularly advanced funnel modeling and data science integrations. But PostHog ships quickly and we can rapidly improve our open source product. We also offer a wide range of features beyond analytics, including replay, flags, error-tracking, and more - each of which can be queried with analytics. The total cost comparison almost always favors PostHog, and while Amplitude may have a handful of extra features it's unlikely they'll be ones you need.
"We need SQL access"
Answer: HogQL gives you full SQL on your event stream – joins, aggregations, window functions. Same interface, no separate warehouse needed. For more complex queries, PostHog's data warehouse unifies product events with Stripe, HubSpot, and other sources.
"We're already on GA4"
Answer: GA4 is a marketing analytics tool and is limited and, frankly, unpopular. PostHog's web analytics tools offer approximate parity with GA4, but with a lot more flexibility.
"Autocapture is going to explode our event volume and our bill"
Answer: Autocapture is configurable and you can use allow/ignore lists, URL filters, element exclusion via the ph-no-capture class, and before_send hooks to drop events before they're sent. Pricing is per-event with a 1M/month free floor and no per-seat or per-MTU charges, so you only pay for what you keep. We can model your expected volume before you commit.
"Our data team lives in Snowflake/BigQuery and we don't want another silo"
Answer: PostHog isn't a silo in either direction. Batch exports send events to Snowflake, BigQuery, Databricks, Redshift, Postgres, S3, or Azure Blob. The data warehouse pulls in from Stripe, HubSpot, Postgres, Snowflake, BigQuery, and 20+ other sources so you can query product events alongside revenue and CRM data in the same HogQL query.
Selling to enterprise
Enterprise analytics customers get volume discounts, ~20% annual prepay, group analytics, SSO, advanced access controls, EU data residency, SOC 2, and HIPAA BAA. Contracts follow the four-lever framework.
The enterprise pitch is consolidation: PostHog replaces analytics, session replay, feature flags, and experiments with one contract, one data model, and one platform that agents can query natively. That's four vendors consolidated, four renegotiations eliminated, and one platform that gets more capable as PostHog Desktop matures.
Data pipelines are part of the broader context warehouse – the platform that ingests and stores your context. This page covers the pipelines specifically.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog's data pipelines move data into and out of PostHog without forcing you to buy a separate CDP, ETL tool, or reverse-ETL service. Sources are free, destinations and batch exports are usage-priced, transformations run on Hog functions inside the same platform that runs your analytics, replay, flags, experiments, warehouse, and agents.
That bundling is the pitch. Segment and Rudderstack only move data. PostHog moves it, lets you act on it, and feeds the agents that act on your behalf – typically 5–10x cheaper than Segment at equivalent volume.
The unique belief (in terms of data pipelines)
PostHog is a doing company. Agents already create the majority of dashboards through PostHog AI and MCP. PostHog Desktop runs the product autonomy loop: signals in, work out, evaluation, repeat.
That loop only closes if the agent can see the whole picture. Errors and replays don't tell you which customer to prioritize – revenue from Stripe, plan from HubSpot, tickets from Zendesk, spend from Google do. That data lives outside PostHog. So do some of the systems PostHog may need to push signals into.
Data pipelines are how PostHog becomes infrastructure for self-driving development. Sources bring business context in. Destinations and batch exports push enriched signals back out. Without pipelines the autonomy loop is half-blind. Segment and Rudderstack just move data. PostHog moves it and runs the agents that act on it.
Who this is for
Teams already on PostHog sending the same events through a separate CDP. They're paying twice.
Engineer-led teams building AI-native products. They already get the "agents need context" argument.
Startups consolidating their stack. PostHog replaces Segment + Mixpanel + LaunchDarkly + Fivetran. $50k credits via the startup program.
Customers on Segment, Rudderstack, mParticle, or Fivetran today. We'll buy out the contract.
Compliance-sensitive teams. EU residency, SOC 2, HIPAA-ready.
Who this isn't for
Teams that need 700+ destinations on day one – Segment wins on breadth.
Mature data orgs with deep tracking-plan governance needs – Segment Protocols is more mature.
Teams who only want a CDP and don't care about the rest of PostHog – the bundle is the whole point.
Messaging
Message 1: Pipelines are the context layer for self-driving development
Problem: Agents that don't see revenue, plan tier, or support history can't prioritize. They see a stack trace, not the fact that the error hit your top customer.
Solution: Sources pull Stripe, HubSpot, Salesforce, Zendesk, and 40+ other systems into PostHog so every signal carries its business context – for your engineers and your agents.
Supporting features:
44 sources, free to import
Warehouse Sources for Snowflake, BigQuery, Databricks, Postgres
Unified SQL across product and business data
MCP exposes the same data to Claude Code, Cursor, and other agent runtimes
Hog functions for transformations, schema enforcement, PII scrubbing
Message 2: Cut three vendors and an ETL backlog down to one
Problem: Segment + Mixpanel + LaunchDarkly + Fivetran + Hightouch + BI = six vendors, six bills, six renegotiations, and a data-engineering queue that grows every time someone wants a new destination.
Solution: PostHog covers the whole loop – analytics, replay, flags, experiments, warehouse, CDP, agents – in one platform. Destinations fan out from the same event stream. Product teams self-serve.
Problem: Other CDP tools introduce regular sticker shock or bill on difficult metrics, like MTUs. Meanwhile, home-rolled ETL pipelines silently fail and need maintenance.
Solution: Per-event for real-time, per-row for batch, with 10K trigger events + 1M rows free monthly. Batch exports run on Temporal with retries, dead-letter queues, and at-least-once delivery.
Their approach: The original CDP. 700+ destinations, mature identity resolution, Protocols for governance, Personas/Engage for audiences. MTU-based pricing – anonymous visitors count.
Where PostHog wins:
Bundled with analytics, replay, flags, experiments, warehouse, agents
Per-event pricing – no MTU surprises for B2C
Sources are free
Pricing is published, not quote-locked
vs Rudderstack
Their approach: Warehouse-first CDP, Segment-compatible APIs, Reverse ETL as the headline, AGPLv3 open source. 200+ integrations.
Where PostHog wins:
Customer wants analytics, replay, flags, experiments in the same tool
Customer doesn't have a mature warehouse to anchor warehouse-first
Customer cares about agent-readiness – MCP, PostHog AI, PostHog Desktop
vs Fivetran
Their approach: Managed ELT. 500+ connectors loading SaaS data into Snowflake / BigQuery / Databricks. dbt-native, Census for reverse-ETL. Warehouse-destination-only, MAR-based pricing that's known for jumping at scale.
Where PostHog wins:
Customer wants real-time destinations, not just warehouse loads
Stripe, HubSpot, Salesforce, Postgres are the load-bearing connectors (we have all of them)
Mid-market customers hitting the MAR cliff
Customer wants analytics in the same tool
Objections
"Segment has 700+ destinations, you have 145"
Follow-up: Which destinations do you actually use today?
Answer: Almost every customer uses fewer than 10. PostHog covers the common ones natively; Hog functions and webhooks cover anything with an HTTP API. The 700-vs-145 framing rarely survives a specific list.
Follow-up: What are you paying today across CDP, analytics, flags, experiments, and ETL? How much engineering time goes into the pipeline?
Answer: The CDP line alone usually closes the gap; the bundled-platform savings make it lopsided. Start with PostHog Sources (free) and batch exports for the destinations they care about. We'll buy out the existing contract on an annual commit.
Proof point:Rebtel migrated off mParticle + Snowflake + dbt with a phased plan. Great Expectations consolidated lead enrichment onto PostHog + Databricks.
"Reliability – we've been burned by ETL before"
Follow-up: What does reliable mean – at-least-once, exactly-once, replayability, observability?
Answer: At-least-once with retries, exponential backoff, dead-letter queues, monitoring. The export system was rebuilt on Temporal in 2024 specifically to fix the duplicate-data and locking problems home-rolled ETL hits at scale. Our support team is engineers.
PostHog does enterprise the same way we do everything else. Pricing is published. Contracts follow the four-lever framework – volume, commitment, payment timing, forecast certainty – up to 40%+ off. No "let me talk to my manager" theatre.
Enterprise gets volume discounts on real-time and batch usage, ~20% annual prepay, custom DPA, BAA for HIPAA, EU residency, SOC 2, and dedicated support. Contract buyout: if a customer is locked into Segment / Rudderstack / Fivetran / mParticle and commits $20k+/year annually, we cover them for up to 6 months while the old contract runs out.
Enterprise does not get an APM-style sales motion, months-long POCs, or a CDP that operates outside our analytics platform. If a prospect needs any of those, the deal isn't a fit – say so early.
The context warehouse is the platform everything else in PostHog is built on, not a co-equal tool. It's the data warehouse plus the full context-ingestion pipeline – data pipelines, modelling, and batch exports. Don't call this "the PostHog Data Stack" externally.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
The context warehouse brings your product events and business data – Stripe, HubSpot, Salesforce, Zendesk, and 40+ more – into one place, queryable together with SQL (and with PostHog AI to help you write it). Because it's part of PostHog, every piece of data is immediately available to your products – analytics, experiments, feature flags – and to your agents.
Snowflake stores data. The context warehouse stores data and acts on it.
The unique belief (in terms of the context warehouse)
PostHog is building the platform for self-driving product development, and the context warehouse is the layer everything else is built on. The product autonomy loop – signals in, work out, evaluation, repeat – only closes when agents can see the full picture. That means product events and business context: revenue, plan tier, support history, CRM data.
The context warehouse is where that picture lives. Every event PostHog captures, every Stripe charge, every HubSpot deal, every Zendesk ticket – it all lands in one place, queryable together. That unified store is what makes PostHog Desktop meaningful. Agents running the autonomy loop need context, and the context warehouse is the context layer.
Snowflake, BigQuery, and Databricks are powerful. They're also expensive, complex to operate, and don't connect to your product tools without significant glue, which usually has to be owned by a dedicated data team. The context warehouse is different: it's integrated, not bolted on. Your data never needs to leave the platform that acts on it.
Who this is for
Startups who haven't built a data stack yet. PostHog gets them to a complete, queryable data foundation in minutes, not months – and our startup program offers up to $50k in credits.
Engineer-led teams tired of maintaining pipelines. No ETL to babysit. Data flows in automatically from 40+ sources.
Teams already using PostHog for analytics. Adding the warehouse unifies product and business data in the place they already work.
Compliance-sensitive orgs. EU residency, SOC 2, HIPAA-ready – data stays in PostHog.
Who this isn't for
Teams that need petabyte-scale with hundreds of concurrent analysts – Snowflake is the right answer.
Data orgs with mature dbt pipelines and advanced modeling needs – we're not there yet.
Teams who only want a warehouse and nothing else – the integrated platform is the point.
Messaging
Message 1: The warehouse is the context layer for your agents
Problem: Agents can see product signals – errors, funnel drops, slow sessions. But without business context, they're guessing. An agent can't prioritize the right customers without seeing revenue and plan data.
Solution: PostHog's warehouse brings Stripe, HubSpot, Salesforce, and 40+ other sources alongside your product events. Every query, every insight, every agent prompt runs on the same unified dataset – no joins across systems, no pipelines to keep in sync.
Supporting features:
44+ sources including Stripe, HubSpot, Salesforce, Postgres, Snowflake, BigQuery, Databricks
Unified SQL across product events and business data
MCP exposes warehouse data to Claude Code, Cursor, and other agent runtimes
PostHog AI generates queries and SQL from plain English
Message 2: One platform replaces five
Problem: The typical data stack – Snowflake + Fivetran + dbt + Looker + product analytics – costs a lot. Six figures per year, easy. More if it requires a dedicated data team to maintain.
Solution: PostHog collapses analytics, session replay, feature flags, experiments, CDP, and warehouse into one platform. Data flows automatically between tools. No pipelines. No hand-offs. Product teams self-serve.
Supporting features:
Warehouse data available instantly in analytics, experiments, and feature flags
1M synced rows free per month, then $0.000015/row – no seat charges, tiered pricing as you grow
SQL editor, notebooks, and dashboards built in
PostHog AI for teams without a dedicated analyst
Message 3: Modern data infrastructure for the AI era
Problem: Traditional data stacks were designed for batch processing and BI dashboards. AI-native product development needs something different – real-time signals, unified context, and data that agents can query directly.
Solution: PostHog's warehouse is the foundation for the product autonomy loop. Product signals and business data converge in one place, accessible to PostHog AI, MCP, and (soon) PostHog Desktop. That's infrastructure for how software gets built now – not a legacy stack with an AI label on it.
Supporting features:
Warehouse-backed MCP for agent context
PostHog AI to interrogate data in natural language
Real-time event ingestion – no batch lag on the signals agents act on
Open architecture – bring your own tools or use ours
Battle cards
vs Snowflake / BigQuery / Databricks
Their approach: Enterprise-grade cloud warehouses. Scalable to petabytes, rich ecosystems, strong governance. Expensive to operate, slow to set up, and often require separate analytics and product tools.
Where PostHog wins:
No virtual warehouses, credits, or cluster management
Analytics, experiments, and feature flags are built in – no integrations needed
Hours to first insight, not weeks
Published, usage-based pricing – no surprise bills or "contact sales" for a number
vs Statsig / Amplitude / Mixpanel (warehouse-native)
Their approach: Connect to your existing Snowflake or BigQuery and run queries there. You keep the warehouse; they run product tooling on top of it.
Where PostHog wins:
PostHog is the warehouse – no separate warehouse to buy or manage
Session replay, feature flags, CDP, and agents are included – not add-ons
If you already have Snowflake, sync what you need into PostHog instead of running another tool on top
Objections
"We already have Snowflake – why change?"
Follow-up: What do you use for product analytics, feature flags, and experiments today? How do you connect those to Snowflake?
Answer: You have two paths. Use PostHog as your integrated warehouse and eliminate the maintenance burden entirely. Or keep Snowflake as your source of truth and sync the tables you need into PostHog via Warehouse Sources – your Snowflake data then becomes available in PostHog analytics, experiments, and agents without custom pipelines. Many teams do both and eventually consolidate.
"We need warehouse-native"
Follow-up: What's driving that requirement – performance, compliance, or avoiding data movement?
Answer: PostHog's warehouse is integrated into the platform, so data never needs to travel between tools. If you're already on Snowflake, sync what you need in via Warehouse Sources. If you're starting fresh, PostHog gives you the warehouse and every product that runs on top of it. The outcome is the same: unified data, no data movement, integrated workflows – without paying for Snowflake on top.
"We'll outgrow PostHog at scale"
Follow-up: What's your current data volume and query pattern?
Answer: PostHog handles the analytical workloads most product teams actually run. Where Snowflake genuinely wins – petabyte-scale governance, hundreds of concurrent analysts – we'll tell you directly. Most teams don't need that yet, and locking in that complexity early just adds cost and maintenance they don't need. When you get there, we'll help you make the right call.
Selling to enterprise
Enterprise data conversations at PostHog follow the same rules as everything else: pricing is published, terms are clear, and we don't oversell.
Enterprise warehouse customers get volume discounts on synced rows, ~20% annual prepay discount, EU data residency, SOC 2 certification, HIPAA BAA, custom DPA, and dedicated support. Contracts follow the four-lever framework – volume, commitment, payment timing, forecast certainty.
The honest enterprise pitch: PostHog is not Snowflake, and we don't pretend otherwise. We win with teams who are tired of running five tools, want modern infrastructure for AI-native development, and value a vendor who prices transparently and ships fast. If a prospect needs petabyte-scale governance, mature dbt tooling, or has Snowflake contracts they can't exit, say so early. The right deals close faster when the fit is honest from the start.
For the canonical frame everyone at PostHog uses (the self-driving story and standard description), see Brand foundations.
Elevator pitch
PostHog Desktop is a product editor for product builders. Context, knowing what's actually happening in your product, is what separates a fix that works from one that just deploys. That context (analytics, session replay, error tracking, experiments, and feature flags) already lives in PostHog, a layer above the usual devtools, so you and your agents just think about what to ship. Usage data in, pull requests out, with your whole team steering that work together from a multiplayer interface.
Self-driving, and where Desktop fits (vs web, Slack, and MCP)
The self-driving loop runs anywhere PostHog does, and each interface is a different way to use it. Desktop is the one built for working hand-in-hand with agents across everything you do in PostHog. The other surfaces are for reviewing the loop, or embedding it in tools you already have.
PostHog Web is the full app in your browser: Query your product data with PostHog AI, chat to kick off cloud coding tasks, and review proactive agent work in the Inbox.
PostHog Slack brings the loop to you: PRs, reports, alerts, and quick follow-ups in a thread.
PostHog MCP & PostHog CLI pipes PostHog's context into the agent you already use (Claude Code, Cursor).
PostHog Desktop is where you build with agents. You hand over whole problem spaces (not just one-off tasks), agents do the heavy lifting, and you build together in real time.
The unique belief (in terms of PostHog Desktop)
Agents write most of the code now, but someone still has to hand them a task, and review the changes. That's what a product editor does, and it only works if it can see your product data.
The old way to build with agents: one engineer prompting one coding agent (a few if they're savvy), alone, working locally from whatever's in their head. Desktop is the new way: your whole team steers a fleet of agents from one shared space, and context acts as fuel to build better products.
Who this is for
AI-pilled software teams at engineering-led companies. Adoption starts bottom-up (the way PostHog always wins) with one engineer connecting a repo.
| Persona | Fit | Why | | --- | --- | --- | | Founding team | Strong | Five people with agents can outship a company 10x their size. The self-driving loop hones the founder instinct (obsess over details), and Desktop gives structure to how small teams collaborate. | | Startup | Strong | They've got PMF and a backlog of small fixes nobody has time for. Agents clear it without another hire, and the self-driving loop gets stronger the more context they generate, since PostHog's own tools instrument that context automatically. | | Scaleup | Strong | The product surface has grown past what any one team can watch closely, and at this revenue scale, a fraction of a percent of conversion or retention is real money. Desktop puts a fleet of agents on that surface continuously and measures every fix against the metric that matters, so small wins compound into real growth. | | Enterprise | Good, with caveats | More data means more signal, but also more noise, and a bigger blast radius when an agent ships into a huge, complex codebase. Add the org politics and it's a harder sell, unless they already act like a compound startup. |
Who this isn't for
Teams who haven't shipped a product to real users. No product data means no signals to act on.
Non-technical builders\* without a repo to point at (using Lovable, Replit, and other no-code platforms).
\Desktop is built for engineers, but adoption across a product org is expected: PMs, marketers, pesky execs trying to steer the roadmap, basically anyone in build mode can benefit.*
Messaging
Message 1: Ship like a team 10x your size
Problem: Midjourney hit $200M in revenue with 40 people. Coding agents make that kind of leverage possible, but only up to a point: one person can only track so many agents at once, and when everyone on the team runs their own separately, none of that work compounds.
Solution: Desktop puts a fleet of agents in one shared workspace, so a few people can track and steer all of it together. That's how a small team outships one 10x its size, without losing the attention to detail that speed usually costs.
Supporting features:
Command Center: run multiple agents at once, each on its own task, local, in a worktree, or in the cloud
Multi-model: pick Claude Code or Codex, plus the model and reasoning effort, per task
Channels: a shared space for a team's agent work, with memory that persists across sessions (alpha)
Canvases: generate a dashboard, report, or internal tool from your real data model (alpha)
Message 2: Agents check their own work
Problem: Agents are shipping far more changes than your team used to. Code review can tell you the diff looks right, but not whether the change did something meaningful (and no one has time to set that up for every agent PR).
Solution: In PostHog Desktop, agents don't just write the fix, they flag it and measure it too. When a change is worth verifying, it ships behind a feature flag and gets checked against a metric you care about before it rolls out any further.
Supporting features:
Feature flags: agents wrap riskier changes in a flag before rolling them out
Experiments: agents scaffold an A/B test tied to a metric
Track events: agents instrument the events needed to measure whether a change worked
Track errors: agents capture exceptions and stack traces to catch regressions fast
Message 3: Your product gets better while you're not looking
Problem: Every team has a backlog of small, real bugs that's been sitting for months. None of them are ever quite bad enough to bump the sprint, so they don't get fixed.
Solution: PostHog agents work that backlog continuously, so it gets cleared without pulling anyone off what they're already doing. They watch for it, triage it, and ship the fix. No human has to notice the problem first.
Supporting features:
Scouts run on a schedule and open a PR when they find something worth fixing, no prompt required
Signals draw from errors, support tickets, session replays, GitHub issues, Linear, and Zendesk
Inbox ranks incoming reports and PRs by importance and impact
Usage-based pricing: 100 credits = $1, no markup, with a $20/month free tier and a $50 default billing limit
Battle cards
vs Claude Code / Codex
Their approach: Anthropic's and OpenAI's own coding products, built on the same models Desktop runs on top of. They're both the harness we use and a competitor (they sell a single-player interface around those models).
Where PostHog wins:
Multiplayer: your whole team and their agents share channels and context, not private terminals
Native product context: work is sourced from and measured against your product data
Not either/or: Desktop runs the Claude Code and Codex harnesses through one app at usage-based pricing, no per-tool subscription
vs Devin, Factory, and other scoped AI engineering tools
Their approach: An autonomous cloud engineer that takes a task and runs. Strong at unattended work, scoped to the codebase and the task you hand it.
Where PostHog wins:
A product editor you actively steer (plan, review, redirect mid-run)
Multiplayer by design: a shared team surface, not a single autonomous worker
Work is grounded in and measured against your product data, then shipped behind a flag
Usage-based pricing, not a fixed monthly seat
vs the agentic multiplayer-workspace (Buzz, Capy, PromptQL, Dust)
This is a new and fast-moving category. Check what each one actually shipped recently before leaning on specifics.
Their approach: A growing set of tools putting agents into a shared, multiplayer workspace, layered on top of your existing data or tools.
Where PostHog wins:
We own the whole stack the agents act on (product data, analytics, flags, experiments, replay) instead of bolting an agent onto someone else's data
The loop actually closes, because the same platform ships the change and measures whether it worked
There's no data to integrate and no context to lose in a handoff, because there is no handoff
Objections
"Why a new app? Just give me an MCP into my existing setup."
What they're really saying: I live in Claude Code or Cursor. My workflow is settled.
Answer: Our MCP is awesome, and for a lot of teams it's the main way they use PostHog. But a terminal only shows you one agent at a time, so if you're running more than a couple of tasks, or want your team to see what's in flight without a status update, MCP might limit you.
"Why pay usage when my Anthropic subscription is subsidized?"
What they're really saying: Inference feels free right now, and anything metered next to a flat, subsidized sub looks expensive (especially if the token budget is tight or the procurement process is slow).
Answer: A lot of the work you're doing doesn't need a frontier model. PostHog runs multiple models, including open-source ones that are getting good enough to handle plenty of tasks for a fraction of the price. You're not locked to one subscription that's subsidized today and will probably be repriced tomorrow. If budget's genuinely tight, start with one task or one repo connected, cap the spend, and expand once it's paying for itself.
"Why would I trust PostHog to ship code? You started as an analytics tool."
Answer: The code is written by the same models you'd use anyway. What PostHog adds is everything around it: error tracking to catch regressions, session replay to see exactly what happened, experiments to prove a change is a net positive, flags to control the rollout, plus the memory, context, and data agents need to build the next change with less prompting.
"Our codebase is legacy, huge, or on a stack agents don't know well. Will this even work?"
What they're really saying: I've seen agents choke on repos like mine.
Answer: Honestly, worry less than you think. Models have gotten very good at working in legacy and unusual codebases, and if part of yours is still tougher, multi-model support means you can point it at whichever model handles it best. And worst case, it's just code: you review the PR before it merges, and if something still gets through, you flag it off or revert. Nothing here is one-way.
"I don't trust agents to ship. We review every PR by hand."
What they're really saying: The 2030 story is ahead of my org, whether that's general AI skepticism or just not having the bandwidth to review more PRs right now. Don't sell me the destination.
Answer: No problem, most teams are here. Our version of the agent loop is worth running because it doesn't rely on autonomy from humans (just autonomy from instruction). You set the bar for which repos to connect, PostHog agents follow your CI rules, and you cap the spend on PR creation. If review bandwidth is the real constraint, start with scouts and signals as alerts only, no PRs, until you're ready to act on them.
How to sell it
Find out which tool a team already has running (error tracking, replay, analytics), and pitch Desktop as the next step from there.
Don't lead with "connect your repo and let agents ship code" as if everyone's ready for that. Most teams need to see real findings first, then ease into self-driving. For example:
They're already using at least one PostHog product (ideally analytics, error tracking, or session replay) so there's real data to work from
Scouts start running against that data and generating reports, still entirely in the web app, no Desktop involved yet
The coding part happens in Desktop: once a report is worth acting on, that's the natural point to connect a repo and let an agent write the fix
Usage expands from there: more repos, more agents, more of the team shipping through Desktop
The Slack app is often in the mix too, surfacing the same findings and PRs wherever the team already works
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Endpoints turns any saved insight or SQL query into a stable, authenticated HTTP endpoint. No backend to build, pipeline to maintain, or data engineer needed.
Other tools tell you what happened. PostHog lets you act on your data, and now, easily share it with your customers.
The unique belief (in terms of Endpoints)
PostHog is building the infrastructure for self-driving product development. The product autonomy loop only closes when data can flow freely; into agents, into products, into every surface that needs it.
Endpoints is the egress layer for that loop. The data is already in PostHog. The hard part was getting it out: building a custom API, maintaining it, versioning it, rate-limiting it, keeping it from breaking when someone tweaked a query. Endpoints removes all of that.
For teams building AI-native products, it goes further. Endpoints exposes PostHog data directly to your MCP, and any agent runtime via clean HTTP with no additional infrastructure required. The warehouse stores the context. Endpoints delivers it.
Tinybird and custom-built analytics APIs solve the same surface problem. They don't solve the underlying one: the data still isn't in PostHog, which means agents can't query it natively, flags can't act on it, and experiments can't measure it. With Endpoints, you can use data from any source connected to PostHog, shared externally wherever your customers need to see it, including your MCP.
Who this is for
Existing customers already using two or more of these – Product Analytics, SQL/Logs, Dashboards, Surveys
If you've heard a customer say any of the following, you should pitch them Endpoints:
"We're exporting CSVs and pasting numbers into a slide every Monday."
“We want to show our customers their own usage data inside our product."
"We're thinking about Tinybird / building a custom analytics API."
"Our data team is the bottleneck on getting numbers out of PostHog."
Who this isn't for
Teams who only use session replay or feature flags and don't have product analytics queries to expose.
Teams whose needs are fully met by PostHog's native dashboards and don't need data surfaced anywhere else.
Messaging
Message 1: Reliable APIs, without building a backend
Problem: The data is in PostHog. Getting it out means either exporting CSVs by hand, or building a custom API and owning it forever. That's slow, fragile, and doesn't scale.
Solution: Endpoints turns any saved insight or SQL query into a stable, versioned, authenticated URL. Embed it in your product, power an internal dashboard, give your MCP access. No backend. No pipelines. No maintenance.
Supporting features:
Materialized queries for fast response times, even on large datasets
Configurable cache TTL per endpoint
Versioning - pin a query snapshot so upstream edits don't break callers
2,400 req/hr rate limit, production-ready
Parameterized queries for per-user / per-tenant scoping
Message 2: A simpler way to ship customer facing analytics
Problem: Getting PostHog data into a product, report, or customer dashboard used to mean one of three things: file a ticket and wait for engineering, buy another tool (Tinybird, a custom API service), or build and maintain a backend yourself. All of those options are slow, and unavailable to a PM or marketer on a Tuesday afternoon.
Solution: Endpoints is self-serve for anyone who can save an insight. PostHog handles the query, caching, rate limits, and the schema, you get a URL you can use anywhere. No data science background needed or custom API to maintain.
Supporting features:
We handle the query, cache, rate limits, and schema, you have nothing to build or own
Your data is already in PostHog, no pipeline to Tinybird, no additional vendor
PMs, marketers, and ops leads can ship an Endpoint without engineering help
Parameterization for safe per-user / per-tenant scoping
Versioning so query tweaks don't break what you've already shipped
Message 3: The data layer for your AI workflows
Problem: Agents running the product autonomy loop need live product signals as context: event counts, funnel states, metric comparisons. Wiring that up today means custom retrieval infrastructure on top of an already complex pipeline.
Solution: Endpoints exposes PostHog data over HTTP to any agent runtime, or MCP-compatible tool. PostHog already has the data. Endpoints makes it fetchable without exposing your entire database.
Supporting features:
Stable URLs - build agent prompts that reliably resolve to fresh data
Clean HTTP - works with any agent runtime, no SDK required
Parameterization for query-time filtering
Battle cards
vs Tinybird
Their approach: A real-time data platform that turns data sources into queryable HTTP APIs. Powerful for teams that want to build analytics APIs from scratch on top of arbitrary data sources.
Where PostHog wins:
Zero additional infrastructure, if you're using PostHog, the data is already there
No data movement required, no custom pipeline into Tinybird, no schema mapping
Data stays in PostHog, no separate tool to maintain and bill to pay
vs Custom-built analytics APIs
The DIY approach: Engineers build a purpose-made backend including a query layer, caching, rate limiting, auth, versioning. Fits exactly what the team needs.
Where PostHog wins:
Endpoints takes minutes to set up
Zero ongoing maintenance, no infrastructure to monitor, scale, or fix
Works without an engineer, PMs, marketers, ops leads can ship an Endpoint themselves
Versioning, caching, and rate limiting are built in, not bolted on
Objections
"We already built our own analytics API"
Follow-up: How much engineering time goes into keeping it working? What happens when someone changes a query?
Answer: You've already proven the use case. Endpoints removes the maintenance treadmill. Versioning means query changes don't break callers, materialization means you're not running expensive queries on every request, and rate limiting is handled. Same outcome, one less thing to own.
"This sounds like it needs a developer"
Follow-up: Walk them through saving an insight in PostHog.
Answer: If they can save an insight, they can ship an Endpoint. The demo is the best answer here and if you can demonstrate the MCP doing it all for you even better. A PM or marketer can go from query to production API.
"We're thinking about Tinybird"
Follow-up: Where is your data right now, and what would you need to move it?
Answer: Tinybird is a great product if you need to build an analytics API on top of data that lives outside PostHog. If your data is already in PostHog, Endpoints gives you the same outcome, authenticated, cached, rate-limited HTTP endpoints, without a second tool, a data pipeline, or a separate bill. PostHog customers suitable for Endpoints will have data in PostHog already. With PostHog you can connect all your data sources easily, with Tinybird you need to build a custom pipeline for every data source.
"Is it production-ready?"
Answer: Yes. 2,400 req/hr, materialized queries, configurable caching, versioning, parameterization. Beta customers ran customer-facing dashboards on it before GA. The reliability story is the same as the rest of PostHog.
Selling to enterprise
Enterprise Endpoints conversations follow the same rules as the rest of PostHog: pricing is published, terms are clear, and we don't oversell.
The enterprise pitch is the data egress story. Large organizations often have PostHog deployed across multiple teams and use cases, but data still escapes via manual exports and one-off scripts. Endpoints replaces that pattern with something versioned, auditable, and self-serve – without requiring a data engineering queue.
The honest pitch: Endpoints wins when the data is already in PostHog and the team is tired of the work required to get it anywhere else. If a prospect's data isn't in PostHog, the right conversation is data pipelines and the data warehouse first.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Experiments run on top of Feature Flags, so every experiment is a controlled rollout by default. Multiple metric types – funnels, trends, retention, ratio metrics – let you measure what actually matters, not just what's easy to track. Watch session replays of each variant's users. Measure side effects across your entire product.
For self-driving development, this means enabling PostHog Desktop to create experiments and re-query the results automatically - making experiments the evaluation layer for agents.
Most experiment platforms run tests. PostHog runs tests and closes the loop from signal to fix to evaluation.
The unique belief (in terms of experiments)
In traditional product development, an A/B test is the last step before shipping. In self-driving development they are tactically important because they turn product data into a control system. They let the agent make changes without pretending it has perfect judgment. The agent can be wrong safely, because every change has a measured blast radius and a pass/fail signal.
That’s the PostHog-shaped belief: autonomous coding only becomes trustworthy when the agent can measure whether its own work improved the product.
Experiments are how the autonomy loop knows whether it's working. Without experiments, agents can ship changes indefinitely without knowing if anything improved. Experiments are the feedback signal that makes self-driving product development trustworthy – not just fast.
Who this is for
Product teams who want statistical rigor without a dedicated experimentation platform or data science team.
Data science teams that want a choice of models. Teams can choose between frequentist and Bayesian models.
Engineers running safe, measurable rollouts who want to graduate from "deploy and hope" to "deploy and measure."
Teams replacing Optimizely or VWO who want experimentation built into their analytics and replay platform.
AI product teams who want to formally compare model variants, prompt changes, or UI approaches with proper statistical power.
B2B SaaS teams who need account-level experiment analysis alongside user-level results.
Who this isn't for
Teams who need no-code visual editors for landing page and CRO tests – Optimizely Web or VWO handle that better.
Marketing teams running experiments outside the product (ad creative, email subject lines, landing pages).
Messaging
Message 1: Experiments as the evaluation layer for agents
Problem: An agent that ships code without measuring impact isn't self-driving – it's just automated code generation. The autonomy loop requires a closed feedback cycle: change made → outcome measured → agent learns. Experiments are part of that.
Solution: PostHog Desktop can scaffold experiments end-to-end. The same metric that triggered the fix signal is used as the experiment goal. Post-merge, PostHog Desktop re-queries the result and evaluates whether the change worked – without human intervention.
Supporting features:
PostHog Desktop skills for full experiment lifecycle management
MCP exposes experiment results to agent runtimes for automated evaluation
Experiment results queryable alongside all PostHog data via HogQL
Automatic re-evaluation after defined exposure periods
Message 2: From flag to experiment to decision in one platform
Problem: Running an experiment can require a flag in LaunchDarkly, analytics in Amplitude, and a session tool in FullStory. Alternatively, you rely on a dedicated tool like Optimizely or VWO with a more limited feature set.
Solution: PostHog Experiments are built on Feature Flags. Every experiment starts as a flag variant. Every result is visible in PostHog Analytics. Every variant's sessions are watchable in PostHog Replay. Everything is in one place, with one data model - and all available to the PostHog MCP and PostHog Desktop to facilitate agentic workflows.
Supporting features:
Experiments and flags share the same 1M/month free tier
Multi-metric experiments – measure primary goal plus secondary effects
Minimum detectable effect calculator and sample size guidance
Group analytics: measure experiment impact at the account level
Message 3: Watch replays of your experiment variants
Problem: Experiment results tell you which variant won. They don't tell you why. The "why" usually requires separate qualitative research or guesswork about what users were experiencing differently.
Solution: PostHog lets you filter session replays by experiment arm. Watch what users in the control group did. Watch what users in the treatment group did. Understand the behavioral difference, not just the metric difference.
Supporting features:
Session replay filtering by experiment variant
Funnel and path analysis segmented by experiment arm
User-level drill-down from aggregate results
Side-effect monitoring across metrics you didn't explicitly target
Battle cards
vs Optimizely
Their approach: Mature web experimentation with no-code visual editor, strong CRO tooling. Enterprise-focused, expensive. No native session replay or product analytics.
Where PostHog wins:
Usage-based pricing vs Optimizely's enterprise contracts
Native session replay per variant – Optimizely has no equivalent
PostHog Desktop evaluation loop – Optimizely has no agent integration
Better fit for product engineering experiments vs marketing CRO
Objections
"We can't run experiments with our traffic volume"
Answer: PostHog shows minimum detectable effect and required sample size before you start an experiment. It won't let you launch an underpowered test without a clear warning. For low-traffic products, PostHog supports Bayesian-style continuous monitoring via sequential testing, reducing the time to a confident result.
"We already use LaunchDarkly flags for experiments"
Answer: PostHog's experiments use the same flag infrastructure you'd use with LaunchDarkly – but with analytics and session replay built in. You don't have to migrate your flags to start running experiments. Connect PostHog to your event stream, define a goal metric, and you can measure the impact of existing LaunchDarkly flags in PostHog today.
Selling to enterprise
Enterprise experimentation customers get volume discounts, group analytics for account-level experiment analysis, SSO, access controls, EU data residency, and SOC 2. Contracts follow the four-lever framework.
The consolidation pitch is strong: Optimizely or VWO contracts at enterprise are often $50k+/year for a tool that only runs tests. PostHog covers experiments, analytics, session replay, feature flags, and error tracking for a comparable or lower total spend – and adds the agent evaluation loop that no pure experimentation vendor offers.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Feature Flags support boolean flags, multivariate variants, JSON payloads for config changes without deploys, and local evaluation for <50ms latency. Every flag is queryable alongside your analytics and session replay – filter any insight by which flag variant a user saw. And every flag PostHog Desktop ships is automatically wired into the analytics that measures whether it worked.
LaunchDarkly manages flags. PostHog manages flags and shows you the impact of every rollout.
The unique belief (in terms of feature flags)
Feature flags started as deployment safety nets – a way to ship code slowly without exposing too much to users. In the product autonomy loop, they're the mechanism through which agents ship code safely. PostHog Desktop's instrument-feature-flags skill wraps relevant changes it opens in a flag by default. The enricher shows stale flags inline in your editor. When an agent ships a fix, the flag is the rollout control.
Flags aren't just for humans anymore. They're the guardrails that let agents work autonomously and safely.
Without flags, agents can't ship incrementally. Without incremental shipping, agents can't evaluate safely.
Who this is for
Engineering teams who want safer deployments without adding ops overhead or per-developer seat costs.
Teams replacing LaunchDarkly who are tired of paying $10-20/developer/month for a tool that doesn't connect to their analytics.
B2B SaaS companies who need account/group-level targeting (flag this feature for Enterprise plan customers only).
Teams building AI products who want to gate model versions, prompt variants, or experimental features.
Anyone using PostHog analytics who wants to filter session replay and metrics by flag variant.
Who this isn't for
Enterprises with complex governance requirements – multi-stage approvals, change management workflows, compliance-grade audit trails – LaunchDarkly Enterprise is more mature here.
Marketing teams who need non-technical flag management with visual editors and no-code targeting.
Teams who need experimentation without product analytics – Optimizely or VWO handle that use case more simply.
Messaging
Message 1: Flags that agents write and the enricher can read
Problem: Coding agents that ship without feature flags are unsafe. A bad change rolls out to 100% of users with no kill switch. Evaluating whether the change worked requires manually querying separate analytics.
Solution: PostHog Desktop can add flags automatically to every PR it opens. The enricher detects existing flags in your codebase and shows rollout percentage, staleness status, and flag evaluation inline – without leaving your editor. Close the loop: agent ships with flag → analytics measures impact → agent evaluates → agent removes stale flag.
Supporting features:
PostHog Desktop instrument-feature-flags skill: adds flags to PRs automatically
Enricher: detects isFeatureEnabled calls and shows live rollout data inline
Stale flag detection built into the enricher
MCP exposes flag state to any connected agent runtime
Message 2: No per-developer pricing
Problem: LaunchDarkly charges $10-20/developer/month. For a 50-person engineering team, that's $6,000-12,000/year before you've run a single experiment. Seat pricing punishes team growth.
Solution: PostHog charges per flag evaluation, not per developer. The first 1 million evaluations per month are free. A team of 50 engineers pays the same price as a team of 5.
Supporting features:
1M flag evaluations/month free forever
No seat limits – every engineer, every service, every agent gets full access
Same billing model as the rest of PostHog – pay for what you use
Pricing published publicly, no "contact sales" for a number
Message 3: From flag to experiment in one step
Problem: Flags and experiments are managed in separate tools. You gate a feature with LaunchDarkly, then measure it in Amplitude, then run the A/B test in Optimizely. Three tools, three integrations, three contracts, three data models that don't talk to each other.
Solution: PostHog Experiments are built on top of Feature Flags. Every experiment starts as a flag. Every flag can become an experiment. The same evaluation infrastructure serves both – both connect to the same analytics and session replay data, and both end up available to the MCP and PostHog Desktop.
Supporting features:
Experiments and flags share the same 1M/month free tier
Jump from flag targeting to experiment setup in the same UI
Watch session replays filtered by flag variant or experiment arm
Group analytics: measure experiment impact at the account level, not just the user level
Battle cards
vs LaunchDarkly
Their approach: Strong governance, mature SDKs, deep integrations (GitHub, Jira, PagerDuty, DataDog). Per-developer seat pricing.
Where PostHog wins:
No per-developer pricing – typically 80-90% cheaper for equal team sizes
Native analytics and session replay – LaunchDarkly requires separate tools for impact measurement
PostHog Desktop integration – LaunchDarkly has no agent loop equivalent
Sources are free in PostHog; every PostHog tool shares the same event stream
vs GrowthBook
Their approach: Open source feature flags and A/B testing. Self-hostable. Requires your own data infrastructure for analytics.
Where PostHog wins:
Fully managed – no infrastructure to run (this is better, trust us)
Replay, analytics, error tracking included
PostHog Desktop integration
Still open source (MIT)
Objections
"LaunchDarkly has better governance"
Follow-up: What specific governance features are you using today – approval workflows, change requests, audit logs?
Answer: LaunchDarkly Enterprise's governance is more mature. PostHog has flag history, audit trails, and access controls that satisfy most teams. If the requirement comes from a compliance checklist rather than active daily use, it's worth checking whether those features are actually being used or just required on paper. The cost delta between PostHog and LaunchDarkly is typically large enough to justify a closer look.
"We need local evaluation"
Answer: PostHog supports local evaluation natively. Flags evaluate in under 50ms without a network call. SDK downloads the full ruleset on init; evaluation is in-process.
"We're already using flags in our codebase – migration is painful"
Answer: PostHog Desktop's enricher detects existing isFeatureEnabled patterns in your codebase and surfaces flag data inline. You don't need to migrate on day one. Start by connecting PostHog analytics to measure flag impact, then migrate flags incrementally as they come up for review. The enricher makes the transition visible without forcing a flag-by-flag rewrite.
Selling to enterprise
Enterprise flag customers get volume discounts, SSO, advanced access controls, audit logging, EU data residency, SOC 2, and dedicated support. Contracts follow the four-lever framework.
The LaunchDarkly displacement motion is strong at contract renewal time. LaunchDarkly's per-seat pricing means costs balloon as engineering teams grow. Present the total cost comparison – seat pricing vs PostHog usage-based – before the renewal window opens. Contract buyout available for customers locked into LaunchDarkly with $20k+/year annual PostHog commitment.
PostHog makes your product self-driving. For the canonical frame everyone at PostHog uses – the self-driving story, the standard description, and the apps / products / context / context warehouse model – see Brand foundations.
This section is the product-marketing detail: the vocabulary we hold ourselves to, an opinionated playbook for each product, and how we name and position what we ship.
The house position:PostHog makes _your_ product self-driving. Everything we write ladders up to that. Keep the customer's product as the subject: they get a product that improves itself; PostHog is how. Don't write "PostHog is self-driving software" in customer-facing copy. We do use the same capabilities on PostHog itself – that's a proof point, not the pitch.
The words we use
We've repositioned around self-driving. That only works if we all use the same words for the layers of what we offer – across marketing, content, and positioning. The four layers (apps, products, context, context warehouse) are defined in brand foundations.
Use these words
"Apps" for Web / Slack / MCP / CLI / Desktop (and Mobile in future)
"Products" for analytics / replay / flags / error tracking, etc.
"Context" for events / recordings / logs / business data, etc.
"Context warehouse" for the data warehouse plus ingestion pipeline
Avoid these
Don't call the apps "products." "Products" is reserved for the functional capabilities (analytics, replay, flags). Call the surfaces "apps."
Don't call the apps "interfaces." Too corporate for a developer audience.
Don't say "tools" for either layer. We retired the word: it overlaps with agent tool-calling, and the capabilities are now "products."
Don't say "PostHog Data Stack." The data warehouse, modelling, pipelines, and batch exports are all part of the broader context warehouse. "Data Stack" is not a thing we talk about externally.
Don't call context "sources." "Sources" already means something specific in the data warehouse (Stripe, Postgres, etc.) and will collide.
Examples
✅ Say: "Add the PostHog Slack app." / ❌ Not: "Add the PostHog Slack product."
✅ Say: "Product analytics is one of our products." / ❌ Not: "Product analytics is one of our tools."
✅ Say: "Your events, replays, and logs are the context that feeds self-driving." / ❌ Not: "...the sources that feed self-driving."
The product playbooks
A reference index to the per-product pages. Each follows the same shape – unique belief, who it's for, elevator pitch and three messages, battle cards, common objections, and selling to enterprise – so you can scan them quickly. Pull from them freely, but they work best when remixed and pressure-tested in real conversations, not framed on a wall and cited religiously.
Analytics – Product analytics built for engineers, not dashboard tourists
Session replay – Watching real users beats imagining them
Replay vision – Batch AI analysis that reads your session replays so nobody has to watch them
Feature flags – Shipping switches that don't require a separate vendor
Experiments – A/B testing wired to the same data as everything else
Data pipelines – CDP, reverse-ETL, and transformations bundled – typically 5–10x cheaper than Segment
Endpoints – Turn any saved insight or SQL query into a stable, authenticated HTTP endpoint
AI Observability – Knowing why your LLM-powered feature is bleeding money or shipping nonsense
PostHog AI – A query interface that already knows your schema (and your users)
PostHog Desktop – The product editor: where you, your team, and a fleet of agents build together
The context warehouse has its own page too, but treat it as the platform everything above is built on – the data warehouse plus modelling, pipelines, and exports – not as a co-equal product in this list:
Context warehouse – The context layer for your agents, not just a SQL bucket
Not static. Products evolve, pricing changes, and competitors ship things. Treat every page as the current best version, not the final one.
If something here feels off, doesn't match what the product team is actually building, or contradicts itself across pages – open a PR or flag it in #team-marketing.
How we name and position things
Naming at PostHog is deliberately messy. Usually an engineer builds something and names it; sometimes James or Tim get the positioning right up front, but more often design iterates the name afterwards (and adds it to the all-hands so everyone catches up), and we reinforce it from there. The upside is that design and "execs" aren't a blocker to shipping – and since we usually soft-launch, the downside is small.
Pick names users already recognize. By default, position something as what a _user_ is familiar with, not the most technically accurate description – we often name new products after what the major competitors call themselves. Users get it faster, we grow more quickly, and it keeps us building the basics a product needs before trying to innovate ahead of product-market fit.
Positioning is dynamic. It changes as products mature – we might position something narrowly at first to get feedback from a specific segment, then broaden or refine it as we learn how it's used. Every new product should still reinforce the core story: PostHog makes your product self-driving.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog AI Observability tracks every model call – latency, tokens, cost per user, quality signals, errors – alongside the product events and session data from the humans using your AI features. When something goes wrong, you can trace it back to the exact conversation, the exact prompt, and the exact user cohort affected. And because it's PostHog, PostHog Desktop can read those traces and propose fixes – automatically.
Langfuse shows you the trace. PostHog shows you the trace and what it cost you in user retention and makes that information queryable to PostHog Desktop, the self-driving development platform.
The unique belief (in terms of LLM analytics)
Every team building an AI-native product is running two products simultaneously: the product users see, and the AI layer underneath it. That AI layer has its own failure modes – bad prompts, cost explosions, latency spikes, quality regressions – and none of those show up in standard product analytics. That's where LLM analytics comes in!
PostHog Desktop already uses LLM traces optimize AI features as part of the product autonomy loop. Its built-in exploring-llm-traces and exploring-llm-clusters skills let agents find patterns in model calls and propose prompt improvements. But that only works if the traces exist. AI Observability is the signal layer that makes AI products self-improving.
If you're building AI features without LLM observability, your agents are flying blind.
Who this is for
Teams building AI-native products – chatbots, copilots, agents, AI-assisted features – who need to understand model performance.
Engineers debugging why AI features underperform – wrong answers, high latency, unexpected costs.
Product teams who want to correlate LLM quality with user retention and conversion.
Teams who want LLM observability in the same place as product analytics – not in a separate tool.
Who this isn't for
Data science teams who need model training infrastructure, fine-tuning pipelines, or MLOps – that's not PostHog. Yet.
Teams who only care about billing/token costs – those tools exist, but PostHog adds user context that pure cost monitors don't.
Enterprises with deeply embedded observability platforms (Datadog) where adding another tool isn't worth the friction.
Messaging
Message 1: LLM traces as product signals
Problem: An LLM trace tells you a model call failed. It doesn't tell you whether that failure caused the user to churn, downgrade, or file a support ticket. Without that connection, you can't prioritize what to fix.
Solution: PostHog links every LLM span to the user's full session – their history, their plan tier, their previous behavior. A 3% quality degradation in your AI assistant looks very different when you can see it's impacting your highest-value accounts.
Supporting features:
LLM span tracking linked to PostHog person profiles
Cost-per-user and cost-per-feature analysis
Cluster analysis to find patterns across conversations
PostHog Desktop's exploring-llm-traces skill triggers automated investigation on quality regressions
Message 2: Cost visibility with user context
Problem: Token cost monitors tell you what you spent. They don't tell you whether you spent it on users who converted or users who churned.
Solution: PostHog shows LLM costs alongside product metrics – retention, conversion, NPS responses – so you can make informed decisions about which model to run, which features to optimize, and where cost reduction would hurt versus help.
Supporting features:
Cost trends by model, feature, and user cohort
Latency analysis tied to user-visible outcomes
Alert on cost spikes or quality regressions
Full event stream alongside trace data
Message 3: The only LLM observability that knows your users
Problem: LLM observability tools were built by infrastructure teams. They're excellent at tracing model calls. They don't understand that the user behind the call is a churned customer, a free trial, or your top enterprise account.
Solution: PostHog's AI Observability sits inside a product platform with full user profiles, cohorts, and behavioral history. Every trace has a person behind it. That context is what makes the data actionable – and what makes PostHog Desktop's agent research meaningful rather than mechanical.
Supporting features:
Supports OpenAI, Anthropic, Google Gemini, and major LLM providers
Session replay correlation – watch the session where the AI feature failed
Feature flag integration – A/B test prompt variations formally
Unified dashboard with product analytics
Battle cards
vs Langfuse
Their approach: Open source LLM observability. Excellent trace visualization, evaluation pipelines, prompt management. No product analytics, no session context, no agent loop integration.
Where PostHog wins:
User context – traces linked to person profiles and behavioral history
PostHog Desktop integration – traces become inputs to the autonomy loop
Session replay correlation – watch what users did before and after an LLM call
One platform – LLM observability inside your existing PostHog setup
vs Helicone
Their approach: LLM cost monitoring and request logging. Simple setup via proxy. No product data, no user behavior context.
Where PostHog wins:
Cost data with user and cohort context, not just raw token counts
Product analytics alongside LLM metrics in one dashboard
Agent integration for automated investigation
vs Datadog APM
Their approach: Full infrastructure observability including LLM tracing. Enterprise-grade. Very expensive. Designed for SRE teams, not product engineers.
Where PostHog wins:
Purpose-built for product engineering teams
Dramatically lower cost for the observability product teams actually need
Native integration with feature flags and experiments for model A/B testing
PostHog Desktop agent integration
Objections
"We already use Langfuse"
Follow-up: How do you connect your LLM quality data to your product metrics today?
Answer: Langfuse is a strong trace tool. PostHog AI Observability adds what Langfuse doesn't have: user context, session replay correlation, product metric linkage, and PostHog Desktop agent integration. Many teams run both during evaluation and consolidate as PostHog's LLM features mature.
"We just need cost monitoring"
Answer: Cost monitoring is one metric. Can you build a better product if you just look at one metric alone? PostHog shows cost per user, cost per feature, cost per cohort – so you can answer "are we spending money on users who convert?" That's the difference between a billing tool and a product tool.
"Our LLM features aren't production yet"
Answer: That's the perfect time to instrument! Retroactive instrumentation means you lose the data from your beta cohort. PostHog is easy to add during development and grows with you into production.
Selling to enterprise
Enterprise AI Observability customers get the same four-lever discounting as other PostHog products: volume, commitment, payment timing, forecast certainty. The enterprise conversation usually centers on cost governance (which model, which features, which teams are driving spend) and compliance (is LLM trace data covered by the DPA; does EU residency apply to conversation data).
The forward-looking pitch: as PostHog Desktop matures, teams with well-instrumented AI Observability will have a fully automated quality improvement loop – traces in, agent optimization out. That's the infrastructure play for AI-native companies in 2030, and it starts with getting the observability layer right today.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog AI understands your full data model – event taxonomy, user properties, cohorts, flags, experiments, warehouse sources. Ask it a question in plain English. It writes the query, runs it, and explains the result. No prompt engineering. No schema briefing. No waiting for a data team ticket to be picked up. It will also speak like a pirate to you on International Speak Like A Pirate Day.
PostHog AI is wired into PostHog Desktop via MCP, so it's not just a query interface for humans – it's the intelligence layer that agents use to understand product impact, measure experiment results, and evaluate whether their changes worked. A key part of the product autonomy loop.
The unique belief (in terms of PostHog AI)
General-purpose AI is impressive but context-blind. When you ask ChatGPT "why did signups drop last Tuesday?", it doesn't know your event taxonomy, your funnel structure, your user cohorts, or what shipped last Monday. Without an MCP (which PostHog also has) you spend more time explaining the context than getting the answer.
PostHog AI is different because it already has the context. It knows your event names, your properties, your SQL schema, and your product's entire behavioral history. It doesn't need to be briefed. It's the query interface for humans and agents alike – and in the product autonomy loop, it's the layer that connects PostHog Desktop to every insight, dashboard, and metric in the platform.
PostHog AI isn't AI added onto analytics. It's the interface through which a self-driving product understands itself.
Who this is for
Product managers and non-technical stakeholders who need product insights without writing SQL or waiting on a data engineer.
Engineers who want to move faster – PostHog AI writes the query so they can iterate on the result.
Teams without a dedicated analyst where self-serve analytics is the only option that scales.
AI-native product teams who want to expose their product data to agents and other LLM runtimes via MCP.
PostHog Desktop users – PostHog AI is the query engine that powers agent access to product data.
Who this isn't for
Teams who prefer writing SQL directly and always want to do things the hard way. You _can_ do that in PostHog, but then why use PostHog AI?
Organizations that need formal AI output auditing before any query runs in a production data environment.
Teams looking for a general-purpose AI assistant for tasks outside PostHog – PostHog AI is intentionally scoped to product data.
Messaging
Message 1: The query layer for humans and agents alike
Problem: Product data is valuable but inaccessible to most of the people who need it. Non-technical stakeholders can't write SQL. Engineers don't want to context-switch to write a dashboard for a one-off question. Agents need to query metrics programmatically without human intervention.
Solution: PostHog AI serves all three audiences from the same interface. A PM asks "what do power users do in their first session?" PostHog AI writes the query and shows the answer. PostHog Desktop asks "did this deploy regress conversion?" and gets a structured result it can use in the evaluation step of the autonomy loop.
Supporting features:
Natural language to HogQL query generation
Supports events, persons, cohorts, funnels, retention, trends, and warehouse data
MCP integration: PostHog Desktop and any MCP-compatible agent runtime can query via the same interface
Explains query logic so you can verify or modify before running
Message 2: The democratization of your data
Problem: Self-serve analytics doesn't mean much if "self-serve" requires SQL fluency. Most product teams are bottlenecked on the analyst who can translate business questions into queries – and that analyst is always busy.
Solution: PostHog AI democratizes query access across the entire product team. A customer success manager can ask "how often do enterprise customers use this feature?" A designer can ask "where do users get stuck in the onboarding flow?" An engineer can ask "which error type has the most user impact?" All without SQL, all without a ticket.
Pre-built awareness of PostHog's product functions (flags, experiments, cohorts)
Integrates with warehouse sources (Stripe, HubSpot, Salesforce data queryable in natural language)
Dashboard generation from natural language
Message 3: Context-aware from day one
Problem: General AI tools require extensive prompt engineering to be useful for product analytics. You have to explain your schema, your naming conventions, your business logic, and your question – every time.
Solution: PostHog AI has full access to your event taxonomy, your user property schema, and your existing dashboards. It autocompletes event names correctly. It knows which properties are populated. It understands which cohorts exist. The first time you ask a question, it already knows how to answer it.
Supporting features:
Automatic awareness of installed PostHog products and their data
Knows your team's event naming conventions and existing dashboards
Ingests schema context from connected warehouse sources
No prompt engineering required for standard product analytics questions
Battle cards
vs Amplitude AI
Their approach: Amplitude's AI features work within Amplitude's product analytics context. Good for querying Amplitude data. No feature flag, session replay, warehouse, or agent integration.
Where PostHog wins:
PostHog AI has access to the full PostHog platform – analytics, flags, experiments, replay, and warehouse in one context
MCP integration for agent access – Amplitude has no equivalent
PostHog Desktop integration: PostHog AI powers the evaluation step of the product autonomy loop
vs ChatGPT / Claude (direct)
Their approach: Powerful general-purpose LLMs. Excellent for many tasks. Completely context-blind about your specific data model, event taxonomy, and product structure unless you add our MCP.
Where PostHog wins:
No schema briefing required – PostHog AI already knows your data
Executes queries directly – general LLMs produce SQL you then have to run elsewhere
Integrated into the platform where you already work
MCP bridge for teams who want to use Claude Code or other agents with PostHog data
Objections
"AI-generated SQL isn't reliable enough for production decisions"
Answer: PostHog AI shows you the query it generated before running it. You verify, modify, or reject. It's a query accelerator and first-draft generator – not an autonomous decision-maker. You still make the call; PostHog AI removes the SQL translation step.
"We have data analysts who write SQL"
Answer: PostHog AI frees analysts from repetitive "how many users did X?" questions and gives everyone else self-service access to answers. Analysts can focus on the work that requires real judgment – designing experiments, interpreting ambiguous results, finding non-obvious patterns. PostHog AI handles the questions that shouldn't take analyst time.
"We're worried about AI hallucinating column names or event names"
Answer: PostHog AI autocompletes from your actual event taxonomy and property schema – it doesn't invent column names. It can misinterpret business logic in complex queries, which is why we show you the SQL before running. Simple to medium complexity queries are reliable. Very complex multi-step analyses should be verified.
Selling to enterprise
PostHog AI is included in the platform – there's no separate AI product to price. The enterprise conversation is usually about data governance (can AI generate queries on sensitive user data?) and access controls (can we restrict which users can use PostHog AI?).
The forward-looking pitch: teams that have PostHog AI set up properly today are the teams that will have the most capable PostHog Desktop autonomous loop tomorrow. The MCP integration between PostHog AI and coding agents is the technical foundation for self-driving product development – and it starts with getting the query layer instrumented and accessible. Enterprises which don't adopt it are falling behind faster every day.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
Replay Vision is batch AI analysis of your session replays. Point a scanner at any filtered set of recordings, ask a question in plain language, and get a structured answer back, on demand or continuously, across tens of thousands of sessions or more, without watching one. Findings become queryable events sitting next to your analytics, funnels, flags, and experiments.
There are several YC startups that do this to a much smaller extent as a separate tool, making them quite limited. They also don't have the full data platform and other engineering tools PostHog has. Replay Vision lets you write the criteria, run your scanners continuously, and use the output anywhere in PostHog.
2,500 credits free every month, which is 500 standard observations (or 1,250 lite ones), no credit card. After that, it's usage-based at $0.01 per credit with volume discounts, roughly $0.02 to $0.15 per observation depending on the model, with no tier upgrade or add-on to buy.
The unique belief (in terms of Replay Vision)
The things that explain why your product works or fails for people aren't always events. They can also be behaviors: hesitation, struggle, dead-end exploration, the moment someone gives up without ever clicking anything you track. They live in your session replays, and the only way to see them has been to watch one recording at a time.
The problem is that once you grow past a certain point, it's impossible to watch them all.
So your most important signal about the user experience is also the one you might have been throwing away. Replay Vision reads your sessions for you. The insight that used to take an afternoon of manual review now runs continuously: Replay Vision reads every session as it comes in, based on the scanners you've set up, and the scouts pull what matters into your Inbox.
This is the vision layer of the self-driving engine the scouts rely on to read what happened in a session, the sense that turns raw recordings into signal the system can act on.
Who this is for
Product engineers, PMs, and founders at product-led companies who record more sessions than anyone could ever watch.
Teams already on PostHog session replay, recording at volume, currently reviewing recordings by hand or piping them into an outside AI tool to make sense of them.
PMs and founders who want summaries and journey interpretation.
Support and ops teams who want anomaly and friction flagging: "show me the sessions that went wrong."
Technical teams who want scan results piped into agents and workflows via API.
UX researchers who want increased rigor in how they understand and monitor user behavior
Any of these can be the champion. The common thread is someone drowning in recordings, or anyone who sees the value in recordings but doesn't engage with them actively due to volume.
Messaging
Message 1: Your product watches its own session recordings
Problem: Watching replays doesn't scale. Past a certain volume, review turns into spot-checking: someone sets aside an hour, watches a dozen recordings, and forms an impression from whatever they happened to click on. Everything else goes unwatched.
Solution: Scanners read the recordings for you and deliver a standing read on your sessions, on a cadence you determine.
Supporting features:
Built-in scanner templates cover the common shapes, so a customer can start without writing a prompt
Scanners summarize and label any set of recordings automatically, across hundreds at once
Bulk-scan on demand, or set scanners to run on a schedule
Findings land as queryable events and get routed to your Inbox, so what matters surfaces to you instead of piling up as a backlog to review
Sampling and coverage controls scope a scanner to a percentage of matching sessions, or to one segment or page
Message 2: Your sessions can answer questions now. Just ask.
Problem: Your metrics tell you the funnel drops at checkout. They don't tell you why. The answer is in the recordings, but the handful that explain it are buried among thousands that don't, and the only way to find them is to watch everything else first.
Solution: Ask PostHog AI (or any of your preferred agents) in plain language and get the behavior behind the metric: why they hesitated, struggled, or gave up. Failure modes that were never event-shaped become visible.
Supporting features:
Ask in plain language, and an agent (Claude, Cursor, your own workflow) spins up a scanner through the PostHog MCP, runs it, and reads the answers back
Configure a scanner once for any question you have
"Why are mobile users dropping at checkout?" becomes a question your sessions answer
Monitor and classifier scanners flag and tag sessions automatically
Summarizer and scorer describe struggle, confusion, and abandonment your events never captured
Every observation deep-links to the exact moment in the recording
Message 3: Session insights, right next to all your product data
Problem: Your analytics live in one tool, and the AI that reads your recordings is a second subscription on top of it – often with your session data exported to a third party to get there. That's two bills for one job, and the bigger cost is that the findings are stranded: "users hesitate at checkout" sits in a different tool from the funnel, the flag, and the error that explain it.
Solution: Analyze your sessions where they already live, under one bill, and one platform. Connect the findings to the rest of your product data.
Supporting features:
Observations become queryable events, sitting next to your analytics, funnels, flags, errors, and experiments
Chart scanner output over time, and feed it into cohorts and experiments
Because it's all one system, a replay finding connects to the funnel, the error, and the release that caused it, and the fix comes back to you in the same place
Refined output via API, no raw export needed
Spend projects forward per scanner, so cost stays legible as usage grows
Keep your sessions on PostHog instead of paying a second tool to scrape and analyze them
Battle cards
vs FullStory (StoryAI)
Their approach: Summaries, Opportunities, and Ask StoryAI. Gemini-powered. The most mature offering, but locked inside FullStory's platform and pricing.
Where PostHog wins:
No per-run cap. StoryAI analyzes 10 recordings per run; PostHog points a scanner at any filtered set of recordings.
Everything past the basics is API-only for them, and gated to Enterprise/Advanced: custom prompts, yes/no monitors, arbitrary labels, scoring on your own criteria. In PostHog all four are in the UI on every plan.
Their UI classifier does sentiment and nothing else.
Findings come back as queryable events you can chart over time and feed into experiments and cohorts. FullStory returns AI output via API and stops there.
Scheduled and continuous runs, plus sampling and coverage controls. FullStory has fixed jobs and no sampling controls.
Usage-based pricing against their tier-plus-add-on.
Where they win, say so: natural-language search, deep-link citations, mobile replay AI, and proactive alerts are all table stakes both of us have. The maturity argument is real; the lock-in and the 10-per-run ceiling are the openings.
vs Contentsquare
Their approach: Planned analyses with a 100-recording-per-run ceiling, Sense Analyst in beta for custom prompts, and a vendor-trained 0–100 friction score. Scheduled runs, MCP access, and a REST API are all there.
Where PostHog wins:
Their AI output is one number. The friction score is the only thing that becomes queryable, chartable, or usable in experiments and cohorts. PostHog turns every observation into an event you can use anywhere.
Configurable scanner types (monitor, classifier, scorer, summarizer) against their fixed planned analyses.
No 100-per-run cap, plus sampling and coverage controls they don't have.
Their score encodes their definition of friction on a fixed scale. The Frustration score scanner template lets you set the scale and the criteria.
Custom prompting is still beta for them.
Where they win, say so: their score works with no configuration on day one. If the buyer wants a number handed to them rather than criteria they define, Contentsquare is the easier sell.
vs Datadog
Their approach: One fixed AI job over session data, priced per 1,000 sessions. Telemetry-only natural-language search, MCP limited to RUM events.
Where PostHog wins:
You can't point it at a filtered set of recordings at all. No custom prompts, no monitors, no classification, no cross-session theme summaries, no mobile replay AI.
No queryable findings, no charting, no experiment or cohort feed, no proactive anomaly detection on AI output.
Their custom metrics aren't AI-derived.
The usual frame applies: Datadog is infra-first, and this is a product behavior question.
vs Mixpanel
Their approach: Playlist-based fixed job, cross-session theme summary in beta, natural-language search via MCP. Tier plus add-on.
Where PostHog wins:
Playlist-scoped only, with no custom prompts, no monitors, no classification, no scoring.
Their theme summary is still beta.
No queryable findings, no charting, no experiment or cohort feed, no REST API for AI output, no mobile replay AI.
vs Sprig AI Analysis for Replays
Their approach: Themes replay clips automatically, but it's a separate UX-research tool with targeted capture, not analysis across all the sessions you already record.
Where PostHog wins:
Targeted capture means they analyze the sessions they went out and recorded for a study. Replay Vision analyzes everything you already record, continuously.
Research-cycle shaped, so answers arrive when a study concludes rather than as sessions come in.
Their output stays in a research tool. Ours becomes events next to your funnels, flags, and experiments.
vs bolt-on AI scrapers (Lucent, HumanBehavior, Autoplay)
Their approach: Customers pull replays out via API into a separate AI tool, paying twice and shipping their session data elsewhere.
Where PostHog wins:
Two bills, one of them for storage you're already paying us for.
Session data leaves your platform and lands with a vendor you haven't diligenced.
Their output can't come back as events, so nothing charts, nothing feeds an experiment, nothing reaches your Inbox.
$0.02 to $0.15 per observation with 500 free every month is hard to beat by adding a vendor.
Objections
"We already pay for FullStory, and StoryAI is included."
Answer: StoryAI is the most mature product in this space. The ceiling is the opening: 10 recordings per run, and custom prompts, yes/no monitors, arbitrary labels, and scoring on your own criteria are all API-only on Enterprise and Advanced. Their UI classifier does sentiment. So the person with the question usually can't run it, and the run is too small to answer it anyway. On PostHog, scanners cover any filtered set, in the UI, on every plan.
"We already built our own AI replay analysis."
Answer: The analysis is the easy part. What they haven't built is anywhere for the answer to go. A DIY agent produces a report; Replay Vision produces events next to your funnels, flags, experiments, and errors, so a finding becomes a cohort, a funnel breakdown, an experiment population, or an Inbox signal. Observations also arrive already joined to who the person is, their plan, and their flag variant. Rebuilding that join is the expensive part, not the model call.
"Is this HIPAA compliant?" / "A model is reading our users' screens."
Answer: On masking: privacy controls run in the browser, so masked content never reaches PostHog or a scanner. Vision sees exactly what Session Replay captured. Careful there, because a customer masking inputs but not text and images is still sending those. On HIPAA: no. Scanners send session data to an external AI subprocessor and we hold no BAAs with them. If they're under a BAA or handling PHI, Vision isn't available today. Address your additional questions in #legal.
"Usage-based pricing means we can't predict the bill."
Follow-up: How many sessions a month, and is the worry the total or one runaway scanner?
Answer: Start with the unit, since that's the opaque part: a credit is $0.01, and an observation costs 2, 5, or 15 depending on the model. The spend widget projects forward, showing what you'll land on by period end and the date you'll hit your limit. You find out in week one, not on the invoice. "View usage by scanner" names the one responsible, so you fix it instead of throttling everything. Before creating a scanner, ask the MCP to estimate its volume. After, cap it with a per-scanner monthly budget – $100 for this one, $50 for that one – on top of the organization-wide limit, and scope it further with sampling and filters. A runaway scanner stops at its own ceiling instead of eating the whole budget.
Image: Spend widget
"Can we use our own model, or our own API key?"
Answer: Not today. Scanners run on a fixed lineup chosen for output quality, and you pick among them per scanner at 2, 5, or 15 credits. The lineup is narrow because the pipeline is built around it – recordings are rasterized into video before a model ever sees them, which this engineering post walks through. Bring-your-own-key has been asked for by beta customers and is under discussion, with no date. If the ask is really cost, the lightweight model plus sampling usually closes the gap. If it's about where data goes, that's the compliance answer above.
For the canonical frame everyone at PostHog uses – the self-driving story and standard description – see Brand foundations.
Elevator pitch
PostHog Session Replay records every user session across web and mobile. From any analytics insight, jump to the sessions behind it. From any error in Error Tracking, watch exactly what the user was doing when it happened. From any rage click pattern, let PostHog Desktop Inbox research and open a fix PR.
Want to watch sessions manually but overwhelmed by the amount of data? PostHog AI can group and summarize sessions for you, separating signal from noise in an efficient way.
FullStory and Hotjar record sessions. PostHog records sessions and connects them to everything else – your metrics, your errors, your flags, and your agents.
The unique belief (in terms of session replay)
Session replay used to be reactive – you watched what went wrong after a user complained. In the product autonomy loop, replay is a proactive signal source. PostHog Desktop's Inbox reads replay patterns – rage clicks, dead ends, unexpected exits – and converts them into researched, prioritized fix PRs before users ever file a ticket.
The shift is fundamental: replay isn't just evidence of a problem. It's the trigger that starts automated remediation. Watching sessions is what humans do. Generating signals from sessions is what self-driving product development does.
Who this is for
Engineers debugging why users are dropping off – they need to see the session, not just the funnel.
Product teams correlating qualitative behavior with quantitative metrics – jump from a funnel drop to the sessions behind it in one click.
Teams replacing FullStory or Hotjar and consolidating to a platform that also covers analytics, flags, and experiments.
Mobile teams who need iOS, Android, React Native, and Flutter replay with the same analytics integration as web.
Anyone using PostHog who wants to close the gap between "what happened" and "why."
Who this isn't for
Enterprises needing advanced session reconstruction for legal, compliance, or accessibility audits – FullStory's enterprise features are more mature here.
High-volume consumer apps that need aggressive client-side sampling and complex retention policies – larger enterprise plans are required.
Marketing teams who primarily need heatmaps as the UX research tool – Hotjar is simpler for that specific use case.
Messaging
Message 1: From graph to session in one click
Problem: A funnel drop tells you users are leaving. It doesn't tell you why. The gap between quantitative data and qualitative context is usually filled by guesswork, surveys, or expensive user research sessions.
Solution: Every PostHog insight links directly to the session recordings of the users behind it. See a drop on step 3 of onboarding? Filter to those sessions. Watch what five users did. Fix it in an afternoon.
Supporting features:
One-click jump from any funnel, trend, or retention chart to related sessions
Session filtering by user properties, feature flags, events, or cohorts
Console logs and network requests captured alongside the recording
DOM snapshot for precise element inspection
Message 2: Replay as a signal source, not just a recording
Problem: Most teams watch session replays when something goes wrong. The signal is already cold – the user has churned or complained. Proactive replay analysis requires someone to watch hundreds of recordings, which doesn't scale.
Solution: PostHog Desktop's Inbox connects to Session Replay as a signal source. Replay patterns – rage clicks, repeated form abandonment, dead-click clusters – are automatically surfaced, researched, and converted into prioritized fix PRs. Sessions feed directly into PR, while AI summarization enables manual review to scale as PostHog AI can group and summarize sessions for you.
Supporting features:
PostHog Desktop Inbox integration with Session Replay as a signal source
Session replay summarization and automatic playlist generation
Rage click and dead click detection
Session collections for grouping related recordings
Automatic severity scoring by user impact
Message 3: Mobile replay with the same analytics integration
Problem: Mobile session replay tools are either expensive standalone products or limited SDK add-ons that don't connect to your analytics. Teams end up with separate replay data for web and mobile with no unified view.
Solution: PostHog's mobile replay covers iOS, Android, React Native, and Flutter with the same one-click path from analytics to session. Mobile events, mobile flags, and mobile replays all live in the same platform.
Supporting features:
Native SDK support for iOS, Android, React Native, Flutter
Same filtering and analytics integration as web replay
Privacy controls consistent across platforms (element masking, network filtering)
Mobile replay add-on for extended retention
Battle cards
vs FullStory
Their approach: Enterprise session replay with advanced DX data, session reconstruction, and compliance features. Expensive. No native analytics, no feature flags, no agent integration.
Where PostHog wins:
Native connection to analytics, feature flags, experiments, and error tracking
PostHog Desktop agent integration – replays become inputs to automated fix PRs
Significantly lower cost at equivalent session volume
More generous free tier (5,000 sessions/month forever vs FullStory's trial limits)
AI summarization and automatic playlist generation
vs Hotjar
Their approach: Simple heatmaps, scroll maps, and basic session replay. Popular with non-technical teams. No analytics depth, limited mobile support, no feature flags.
Where PostHog wins:
Full analytics integration – jump from Hotjar's heatmaps to PostHog's funnel and back is not possible; PostHog provides both
Feature flag correlation – filter sessions by which flag variant the user saw
Agent integration for automated investigation
AI summarization and automatic playlist generation
vs LogRocket
Their approach: Developer-focused session replay with strong frontend performance monitoring. No product analytics or feature flags. Good DevTools integration.
Where PostHog wins:
Broader platform – analytics, flags, experiments, warehouse, and error tracking included
PostHog Desktop Inbox integration – LogRocket has no equivalent agent loop
Usage-based pricing without seat limits
Objections
"FullStory has better enterprise features"
Follow-up: Which specific features does your security or legal team need?
Answer: FullStory's enterprise session reconstruction and compliance features are genuinely more mature for legal and accessibility use cases. For product engineering teams, PostHog has everything needed at a fraction of the cost. If the requirement is driven by a compliance checklist rather than active use, it's worth stress-testing whether FullStory's premium features are actually being used.
"We're worried about user privacy"
Answer: PostHog has CSS masking (any element, including dynamic content), network request filtering (block sensitive endpoints), and input field masking by default on sensitive types. Privacy controls are explicit and auditable. You define exactly what gets recorded.
"5,000 free sessions isn't enough"
Answer: 5,000 is the forever-free tier, not a trial. Paid tiers are usage-priced with no seat limits. Compare to Hotjar's 35 daily sessions on the free plan and $100+/month for meaningful volume. PostHog's paid replay is typically 3-5x cheaper than FullStory or Hotjar at equivalent usage.
Selling to enterprise
Enterprise session replay customers get volume discounts, extended mobile replay retention, advanced access controls, SOC 2, and EU data residency. The consolidation pitch is particularly strong here: FullStory and Hotjar contracts are often standalone line items that can be eliminated when replay is included in a PostHog annual deal.
The forward-looking pitch: replay as a signal source for PostHog Desktop Inbox is a capability no other vendor offers. Teams that instrument replay properly now will have a fully automated UX investigation loop as the agent features mature.
Any press-related enquiries should be directed to press@posthog.com - this includes any emails you receive personally. Only Joe, James, Tim or Charles should be talking to the press on PostHog's behalf.
With the exception of occasional major press releases (see below), PR is purely a reactive activity at PostHog. We do not invest in proactive PR yet, as we believe other channels are a higher priority.
Managing press releases
From time to time, we may have significant company news that we want to release via the press, in addition to our usual channels. This is usually for significant company milestones such as funding rounds.
We have a simple process to ensure that any press releases go smoothly.
First steps
[ ] Write up objectives and comms strategy - what is the purpose of the press release? What key message(s) are we trying to get across?
[ ] Set an approximate target date
Two weeks before release
[ ] Confirm key messages and write first draft press release
[ ] Finalize target date
[ ] Pitch and secure a media exclusive - our investors can help with this
[ ] Secure approval for any third party involvement, e.g. quotes we want to use
We currently prefer working with a single media partner on an exclusive basis, as we believe a single, high-quality story is more impactful than taking a broad approach, given our current early stage.
One week before release
[ ] Finalize press release and share with exclusive media partner
[ ] Any media prep if interviews have been scheduled
On the day of release
[ ] Wait for the media partner's story to go live first! Check it carefully and ask for any errors to be amended before proceeding with the below...
[ ] Push out the press release via BusinessWire
[ ] Submit via YC's social media request from
[ ] James to post on his personal LinkedIn (and tag all relevant people)
[ ] Post in our PostHog Users Slack
[ ] Post in YC Slack
[ ] Write post on our blog about the news
[ ] Post on PostHog Twitter (and tag all relevant people)
[ ] Share links to all of the above to the PostHog team so they can share
[ ] Update any relevant online company profiles; Crunchbase, Pitchbook, Glassdoor.
Press release template
Include media and quotes from James, Tim or influential people.
# Headline
News
## About PostHog
PostHog is an open source platform for self-driving products. It pairs the full context of a product's data – events, errors, logs, replays, and more – with agents that find opportunities and ship improvements, so software teams can build better products, faster. Teams get product analytics, session replay, feature flags, experiments, and more in one platform, and PostHog's open source approach lets companies self-host, removing the need to send data externally.
Founded in 2020 by James Hawkins and Tim Glaser, PostHog was a member of Y Combinator’s Winter 2020 batch, and has subsequent raised $12m in funding from GV, Y Combinator and notable angel investors including Jason Warner (CTO, GitHub), Solomon Hykes (Founder, Docker).
## About Y Combinator Continuity Fund
YC Continuity is an investment fund dedicated to supporting founders as they scale their companies. Our primary goal is to support YC alumni companies by investing in their subsequent funding rounds, though we occasionally invest in non-YC companies as well.
Like YC’s early-stage partners, the entire YC Continuity team has strong operating experience. We work to create opportunities for founders to continue their personal growth and scale their companies successfully.
We also run the YC Growth Program, which brings together founder-CEOs who are leading rapidly growing companies.
Have something you want to announce? Let the Developer Marketing team know in #team-marketing! If it's an iterative update, you can also demo it in the all-hands, or post in #tell-posthog-anything.
Product marketers take responsibility for coordinating and publicizing news about PostHog, including product launches. We also help with incident and maintenance announcements, if needed.
Releases vs. launches
The word "launch" gets used to mean a dozen different things, which creates confusion about who owns what. So we split shipping something new into two distinct moments, with two different owners:
A release is when a product or feature becomes available to existing users for the first time. This is the product team’s responsibility. The PM or team lead drives it, using their own release checklist. A release can be gradual, targeted, or fully open.
A launch gets a product in front of existing and new people – potentially millions who've never heard of us. This is led by marketing with the product marketer working from the launch checklist below. If there is disagreement within a team about whether something is ready to launch, that team’s lead should make the decision - it’s either on or it’s off (“we want to launch, but not yet” is off).
Where we can, releases and launches should happen together, but they don't have to. If pricing, the feature set, or even the name is still moving right up until the day before release, it makes no sense to build and then rebuild the product page, the video, and the campaign around a moving target. In those cases it's completely fine for the launch to follow immediately after the release, once the details are locked. Timing depends on how certain we are about what we're shipping. The more settled it is, the tighter the two can be coupled.
People involved with releases & launches
Releases and launches involve lots of moving pieces. It's helpful to be very specific about who is responsible for what, so you don't waste time figuring this stuff out:
Product team lead – product readiness for launch, flag setup, and stability.
PM – pricing and packaging readiness, building the target cohort.
PMM – go-to-market readiness, launch messaging, product page, and working with other teams on campaign assets (website, video, social, editorial, paid ads).
If you are one of these people, you can give feedback to each but you shouldn't block decisions not in your lane. For example, the team lead can say the product is not ready, but should not block a the content of an email. Similarly, marketing can decide what the product page says, but should not block a pricing decision.
How we launch: rolling, not big bang
You'll see companies save everything up for a single, coordinated, big-bang moment. That's not us, and it's a deliberate choice.
Our style is a rolling one: a smallish launch, followed by shipping lots of stuff the moment it's ready. This fits how our small teams actually work – they move independently and don't wait for a company-wide launch train to leave the station. The alternative means more coordination, more launch meetings, and more waiting, and we don't think the payoff is worth it.
It's easy to look at what competitors post on X and feel like we should be slicker, but we pay far more attention to that stuff than the wider world does. Look at the actual numbers rather than the vibes: on a comparable launch, we tend to massively outscore peers on release (we simply have far more users) _and_ on launch (far more people watch and read our content). We may not look as coordinated in the moment, but we ship things that huge numbers of people genuinely watch and read.
Got feedback on what you'd like to see from a launch? We'd love to hear it – drop it in #team-marketing
Types of announcement
We classify announcements into four tiers, from a full-blown new product launch (tier 1) down to a minor changelog note (tier 4). The tier defines how much we do to market something. It's a guideline, but PMMs have free rein to do something different.
This framework helps us manage expectations with other teams. When a team lead or PM tells us about a launch, we use the context they give us (plus our own judgement) to decide which tier it falls into. Share that back with the team so they know what marketing will deliver.
Deciding what to market
Before you settle on a launch tier, work through the questions below. They shape how you pitch a launch and who you point it at.
Who is this for, and what do they expect from us? Remember that existing users have fixed notions of what PostHog is and what it's for. As we attract new users with the self-driving story, that gap will widen – so be deliberate about which story a given audience is expecting and how this launch relates.
Which surface is it for? Should a user reach for this new thing through MCP, desktop, web, or the Slack app? Be explicit about where it's most relevant to the user based on the interface(s) they're engaged, or which interface you want them to adopt.
What can their role actually do with it? Match the audience to their permissions. Launches with pricing usually target owners and admins, since they make a purchase decision when enabling the new thing. Owners and admins are also the ones who have to turn on integrations before the rest of the team can use the new product or feature (as was the case with the Slack app launch).
How does it fit the self-driving story? Some launches feed the loop by giving the system a new source of context (tickets, conversations). Other launches close the loop by acting on that context (Scouts generating Inbox reports). Both promise the same thing: the user's product gets better. A support product isn't exciting because an agent can read tickets. It's exciting because bugs buried in those tickets get found and fixed without anyone prompting it.
What's the "now what?" Once someone clicks the email, ad, or notification, what's the one meaningful action we want? Be diligent about setting a goal metric in Customer.io, usually tied to the activation criteria for thing that's launching (the PMM can ask the PM for this). Actions that carry more decision or risk, like connecting a GitHub account to enable self-driving, will typically have lower conversion and need more follow-ups emails and marketing.
Tier 1: New product announcements
New product launches are our biggest tier. They have their own GitHub template: Launch Plan. Product marketers should always create a launch plan for new product announcements.
Here are some activities your Tier 1 launch could include:
New product page
Sales enablement doc
Competitive comparison (can be added to the product page)
A case study
Blog announcement
Social media brief for Liam
Demo video
Email announcement (or multiple, if you want to segment users and personalize your message)
Custom designs for blog covers, social posts, etc.
Having a messaging doc is very useful for bigger launches because it can be used by different content-producing teams, and it brings alignment on how we want to communicate the product.
Initiate communication with the billing team so you're on top of billing changes and schedule your announcements accordingly.
Meet with the related PM regularly to stay informed about changes and get their input on what you're writing. Read more about how PMs and PMMs collaborate.
Create a separate Slack channel and communicate all updates there. Add all relevant stakeholders and make sure it's active. Post a weekly/bi-weekly update of the progress.
Create a canvas in your Slack channel where you'll be dropping all relevant links to things published, your launch plan, Figma files, etc. This makes it easier for engineers, PMs, and other stakeholders to find what you've been working on.
If the product is moving from free beta to paid general availability (GA) you might also want to choose a reward for beta users. Examples of this include giving PostHog AI beta users 30 extra days of unlimited free usage, or giving Workflows beta users a discount code for merch.
If the product has been free for a while and it's becoming paid with the launch, make sure to plan to notify free customers in advance and clearly communicate pricing.
_Note: All of these are suggestions, not must-haves. It's likely that not all of these things can be ready for launch. A case study, for example, can follow a few weeks after._
Best practices and other processes
Ensure the product has a product page added to the website.
Ensure the product team has implemented intent and activation signals for the product.
Ensure the product has at least one customer story created for it within 3 weeks of launch. example
Ensure we publish best practice content for the product and link to it from docs. example
Ensure the product has at least one tutorial created for it at launch. example
Ensure launch activities (such as changelog) link clearly to the docs.
Ensure the product is added to email and in-app onboarding flows.
Ensure the product is added to the pricing page (this is typically owned by the product team's PM and the as part of the product's release)
Add an 🚀 annotation in our PostHog project on the launch date, so the launch's impact is visible on dashboards.
Submit an art request for any creative assets needed for the email campaign, blog post, social media posts etc...
Major announcements involve changes which have a noticeable impact on the experience of most users, or require specific action from affected users. They may introduce new features, require product downtime, or include opt-in betas for upcoming work.
Medium announcements involve changes which have a noticeable impact on the experience of some users, but not the majority. They are likely to involve visual or functional changes, but do not introduce wholly new features. They do not require action from users and pose no known risk.
We may typically support medium announcements by:
Including them in the weekly changelog update and related emails.
Minor announcements involve changes which have no noticeable impact on the experience of most users. They can involve small visual changes, such as UI tweaks, but are more often small bug fixes or back-end changes. They do not require action from users and pose no known risk.
Occasionally, we have to conduct scheduled maintenance. When this happens, it's important that we tell users about it in advance if they would experience any disruption.
If you're aware of any upcoming maintenance which would cause disruption, please inform the Support, Marketing, and Customer Success teams as soon as possible. Marketing will ensure that users are notified as the work is planned and completed. Customer Success may wish to inform specific users at the time.
Typically, Product Marketers take responsibility for informing users about maintenance work beforehand by telling users who will be impacted through email and other channels.
When informing users about maintenance, it is important to answer all of the following points:
When will the maintenance occur?
How long will it take?
Who will be impacted?
Will any data be lost?
Do users need to take any sort of action?
How will feature flags and experiments be impacted?
What will the impact be? Will insights, etc., still function?
Why is the maintenance being done, and what benefit will there be for users?
We typically notify users of upcoming maintenance by email, so the Developer Marketing team will need a way to target the correct users before they can update them. For smaller maintenance updates which will not cause any user updates, engineering teams can also update our status page.
Incident communications
When an incident is declared the Brand team should join the incident channel as observers, and monitor to make sure that customer comms are handled correctly.
This page isn't accurate - we have deprecated Pylon and don't have a comparable broadcast capability in SupportHog or elsewhere. In the meantime if you want to get a Slack message out to customers ask account owners to do it on your behalf in #group-cs-sales-support
We share Slack channels with many of our customers and partners via Slack Connect, managed through Pylon, our own tool. These channels are normally used for support and relationship building, but Pylon's broadcast functionality also lets us send a single message to every customer or partner Slack channel at once.
This is a powerful way to amplify product announcements and other comms directly to the people building on PostHog, alongside our usual email and in-app channels.
Slack broadcasts do not reach our PostHog Discord. The Discord community is managed by the Builder Relations team, not Marketing, and is a separate audience. If you want your message to reach Discord too, coordinate with the Builder Relations team.
When to use a Slack broadcast
Broadcasts go to every shared customer and partner channel, so they're best reserved for messages that are genuinely relevant to that whole audience. Good candidates include:
Invitations to betas, events, or programs aimed at existing customers.
Because every customer sees the same message, keep broadcasts infrequent and high-signal. As a rough guide, no more than one broadcast every couple of weeks as it's easy to tip over into spamming people. If a message is only relevant to a subset of accounts, it's usually better to let the account owner share it directly.
Check with Sales before sending
Broadcasts reach live customer and partner channels, and Sales or the TAMs may know of sensitive accounts that should be excluded from a particular comm. Always give them a chance to flag any before you send:
Share a brief update in #group-cs-sales-support describing the comm you're about to send and who it will reach.
Allow at least 24 hours for salespeople and TAMs to respond with any accounts that should be excluded or any other concerns.
Ping more than once. A single message is easy to miss. Follow up a couple of times, and give a final heads-up with the scheduled send time (e.g. "this is going out at X") so people have a last chance to flag anything.
If no feedback is received within that window, go ahead and send - you don't need to wait for explicit sign-off or be blocked.
Pylon broadcasts should be treated like email messages and added to the Marketing Messaging calendar as standard. This step is required, but it keeps PMMs unblocked while giving the people closest to our customers a simple way to catch anything sensitive.
Excluding channels before you send
Beyond accounts that sales or CS flags, scan the audience yourself for channels that shouldn't receive the message:
Drop legacy and archived channels. Pylon's audience often includes old or inactive channels. They're usually obvious from the name – exclude them so the message only lands in live channels.
Check for recent negative sentiment. It's worth quickly asking an LLM to scan the #posthog-* channels and surface any negative sentiment from the last two weeks. This usually turns up a handful worth excluding.
Consider excluding people already using the feature. If the broadcast is nudging people towards something, exclude accounts that already use it – or word the message so it still works for them (e.g. framing it as "in case you missed these features" rather than assuming they haven't seen them).
How to send a broadcast in Pylon
Log into Pylon using SSO with your PostHog email address.
Find the broadcasts feature in Pylon and create a new broadcast.
Select the audience – typically all customer and/or partner Slack channels. Double-check the audience before sending, as the message goes to live customer channels.
Write your message. Keep it short, friendly, and link out to the changelog, blog post, or docs for the full detail.
Send the message as yourself, not as PostHog. Pylon lets you choose the sender - sending from a real person feels more personal and gets a better response than a faceless company message.
Preview, then send.
Before you send
Write copy that follows our style guide. These messages land in customer-facing channels, so they should read like a helpful heads-up from a teammate, not a press release.
A light, self-aware tone works well. Leaning into the fact that it's an automated broadcast (rather than pretending otherwise) tends to land well and pre-empts any "stop spamming us" reactions.
Link, don't dump. Point people to the canonical source (changelog, blog, docs) rather than pasting long updates into Slack.
Coordinate with related comms. A broadcast usually accompanies an email and/or in-app announcement. Make sure timing and messaging are consistent across channels.
Remember the audience is live customers. Once sent, a broadcast cannot be unsent from people's Slack, so review carefully.
After you send
Broadcasts generate replies, and how they reach you isn't always obvious:
Replies land in a thread in your private Slackbot, which isn't shareable with the rest of the team. If a customer replies outside the thread in their channel, you won't see it at all unless you're already a member of that channel.
Expect a lot of questions. Use judgement on what to answer yourself versus what to hand off:
Simple, generic questions (e.g. "where can I read more?") are fine to answer directly.
Account-specific questions (e.g. "how would we use this?") are usually better routed to the account's TAM or CSM, who have the context to answer well.
Got a launch, Beta, GA, or project you want promoted on social? Tag Liam Graham in Slack and use the checklist below to give him the information he needs.
Who controls our social accounts
Liam Graham owns and runs PostHog's main social media accounts. If you need something posted from an official account, want a reply sent from one, or have a question about our presence on a platform, he's your point of contact.
If you have a more general question about how we post to social media, your answer is likely found in the handbook's social media content section.
When we promote a launch on social, he needs a handful of things to turn it into great posts.
What to share
In the initial (or second) message you share about a launch, Beta, GA, or project, add this bullet list where you'd normally tag Liam Graham:
ELI5 of what's getting promoted, and how you want it presented on social.
Messaging doc(s). Do you have email copy that lives somewhere? A general messaging doc? Send both if you have them.
Link(s) to the main video or photo asset(s). As a gentle reminder, 4:5 aspect ratio is best for graphics and photos, and 9:16 is best for video.
Link(s) to the blog article, if we've got one.
When should the first post on social go live?
Confirm the OpenGraph image is updated on the product page. See OpenGraph images below.
That's the whole ask. If something doesn't apply (for example, there's no blog post yet), just say so.
Where and when to send it
You should aim to give as much notice as you can, but ideally at least a week. You can share the checklist in either of two places:
A widely broadcast Slack message you're already sending out about the launch.
Post in either the #team-marketing or #team-editorial Slack channels
In both cases, tagging Liam Graham.
We want to make sure we're being transparent with this, so you should avoid sending this information by DM.
OpenGraph images for product pages
Every _product_ page should have a custom OpenGraph (OG) image, so that when someone shares a link on social media it shows a purpose-built visual rather than defaulting to the website homepage image or, worse, showing up as a missing image.
What's needed: a custom OG image for each product page. This is an art request rather than a copy request, so there's usually no messaging doc to go with it.
Good examples: the Feature Flags and Session Replay product pages already have working OG images that render correctly. Use these as a reference for what we're aiming for.
Design guidance: because these render on small screens, keep designs and copy simple – bright colors and chunky text work best.
Check your work: paste the product page URL into opengraph.xyz to preview how the OG image renders across platforms.
If you can sort the OG image yourself for a product as you pick up assignments, that's one less thing to coordinate.
You volunteered or have been asked to speak at a dev meetup, give a demo at a conference, or present PostHog to a virtual or in-person audience. Maybe you said yes before you thought too hard about it. That's fine — good talks happen this way. This guide is for preparing and delivering your talk.
Before you build anything, answer three questions:
Who's in the room? A meetup for early-stage founders is different from a Clickhouse conference. Find out: their persona. Are they product engineers or founders? What sized team do they work at? What stack? What company stage? Also, how many people will be in the room? Ask the organizer — they want your talk to land too.
What format are you filling? Confirm the exact setup:
Length (20 minutes including Q&A? 45 minutes? Lightning talk?)
Slides, live demo, or both?
Will you have reliable Wi-Fi, or should you run demos locally?
Microphone or projecting your voice?
Is it recorded?
What else is on the agenda? If you're one of four speakers, you don't want to cover the same ground as the person before you. Get the full lineup.
2. How we talk about PostHog (and how we don't)
No talk should ever be a blatant product or company pitch. Whatever your audience, they didn’t come to this event to receive a pitch (anyone can visit PostHog.com themselves.)
The PostHog voice in talks:
Let the work speak. Lead with what you built, what broke, what you learned. PostHog appears naturally because you work here and we love to dogfood.
Share real lessons. The interesting part of any content is the thing that went wrong, the assumption you had to throw out, the number that surprised you, the unpopular opinion.
Have opinions. "Here's what I think about this" is more useful than "there are tradeoffs on both sides." Take a position, avoid hedging.
Be inclusive with language. Avoid jargon that excludes people who aren't already PostHog users. Assume the audience is smart, not that they're familiar.
If you finish writing your talk and the word "PostHog" only comes up three times, that's probably good.
3. Build the talk around one true thing
Kelsey Hightower — a best in class technical speaker — doesn't use slides as a crutch. He treats his talk like a live demonstration of a belief. Every word moves toward a single point.
Pick your one true thing → build evidence for it → show it working live
That's the whole structure. You don't need five points. One claim and the proof. Good examples of what a "one true thing" sounds like:
What we learned from pivoting 5 times before reaching PMF
Lessons from a year of building AI agents in production
Why we stopped writing unit tests for our data pipeline (and what we do instead)
How we cut our onboarding drop-off by 60% without a redesign
Notice what these have in common: they're useful to the audience whether or not PostHog exists.
4. Your demo is the talk
Software demos should tell a story, not show features. The biggest mistake we can make demoing PostHog at events is simply narrating the UI instead of showing a problem being solved.
Bad: "So here's the dashboard. You can see we have charts. This one is a trend. This one is a funnel..."
Good: "We shipped a new onboarding flow last Tuesday. By Wednesday I was looking at this drop-off and thinking something was wrong. Here's what I found." Then show that.
Pick one real scenario — something that happened at PostHog related to your work, or something a real user told you. Build the entire demo around it.
Demo setup checklist:
\[ \] Use a demo project, not a live account with customer data
\[ \] Pre-load data that looks real — sparse data makes features look broken
\[ \] Disable notifications on your laptop
\[ \] Silence your phone
\[ \] Bookmark your demo URL — don't type it live
\[ \] Know what happens if Wi-Fi dies (screenshots as backup)
\[ \] Zoom your browser to 125–150% so the back row can read it
Code on slides: use a large font (24pt minimum), a dark background, and only show the lines that matter. If you're pasting a full file, you've already lost.
One idea per slide. If you're writing full sentences, you're writing speaker notes, not a slide. If applicable, allow memes to replace text.
If a slide doesn't support the one true thing you identified in step 3, cut it.
Speaking of speaker notes, you will save yourself time and head space if you always have notes.
Reading your talk in your head doesn't count. Your mouth is slower than your brain. The VM Brasseur public speaking guide has a useful rule: practice until the words feel boring to you. If they still feel fresh and interesting when you say them, you haven't done it enough.
Two run-throughs, out loud, at speaking pace, with your actual demo running.
The “cut” rule: If you stumble on a section more than twice in practice, that section is probably bad. Rehearsal reveals structural problems — stumbling usually means the logic isn't clear, not that you need to practice more. Stop, figure out why it's hard to say, and fix the content.
7. The first 60 seconds are everything
Open with something that makes the room lean in:
An uncomfortable question: "How many of you are flying blind on what users do after signup?"
A specific number: "We had 847 session replays from one user in a single session. Here's why."
A short story: "A customer emailed us asking why their funnel had 0% conversion. The button said 'Sumbit'."
Don't introduce yourself first. The host does that. You start with the thing. Then you can re-introduce yourself to set the context of why you’re the person qualified to speak on this subject.
8. Prepare to not know something
We always want to encourage Q&A after our talks as it builds conversation and connection. Someone will ask a question you can't answer. Don't bullshit. The right response: "I don't know — but here's how I'd find out, and I'll follow up with you." Then actually follow up.
If you receive a question that you believe is off-topic or unfitting for the setting, you can let the asked know this and express an interest in moving on to the next one.
9. After the talk
Express an willingness to keep the conversation going - by letting the audience know that you (and any other team members in the room) are sticking around to chat more.
Write down the questions you couldn't answer — do this right away so you don't forget and can focus on interacting with attendees the remainder of the event.
Tell the marketing team — a 2-line Slack in #team-builder-relations with the event recap, approximate audience size, and any interesting take-aways.
Share your slides — Share them on social, QR code, email, path of least resistance. Don't make people hunt.
| Feature | Startups | Y Combinator | | --------------------------- | ----------------------------------------------------- | ----------------------------------------------------- | | Eligibility | <2 years old, <$5M raised, not acquired, company email domain | Must be in YC (proven with a YC verification link), <$25m raised, company email domain | | Credit | $50,000 for 12 months | $50k per year, whilst eligible | | Can use credit for add-ons? | ⚠️ Yes, but cannot use credit for BAA in Boost package | ✅ Yes, and can use credit for BAA in Boost package | | Can use credit for AI tools? | ❌ No, from September 14, 2026 (PostHog Desktop, PostHog Slack app, Replay Vision, PostHog AI, Inbox) | ❌ No, from September 14, 2026 (PostHog Desktop, PostHog Slack app, Replay Vision, PostHog AI, Inbox) | | Founder merch | Welcome pack (max 1) | Different welcome pack (max 4) | | Community | — | Tim's Whatsapp, priority support | | Apply via… | Startup page | Secret YC page |
PostHog for Startups
Any company that is <2 years old and has raised less than $5M in funding is eligible to apply, from a PostHog account that uses the company's email domain, and claim the following:
$50,000 in PostHog credits (valid for 12 months)
One unique welcome pack for founders
Partner benefits with Speakeasy and Incident.io
A monthly newsletter for founders
❗Credits cannot be used toward a BAA under the Boost plan.
❗From September 14, 2026, credits cannot be used toward AI tools such as PostHog Desktop, the PostHog Slack app, Replay Vision, PostHog AI, and Inbox, due to the prohibitive and unpredictable nature of token-based pricing. Teams that joined before that date can still pay for usage incurred before the cut-off with credits.
⭐ Small open source projects without corporate backing and less than $200k annual revenue can contact support to have the 12-month credit expiry waived.
All applications are automatically approved, then manually reviewed for eligibility.
Applications from free or disposable email domains (gmail.com, outlook.com, and similar) are rejected automatically at submission. This applies to both programs. Founders who don't have a company domain yet can still use the monthly free allowance on every product and apply once they have one.
This program is similar to our startup program but has some key differences for YC teams. Teams can be in any YC batch, with any amount of funding raised, and can claim the following:
$50,000 per year – they only need to register once and it will renew automatically while they're eligible (<$25m raised)
If they previously registered for the old deal and it expired, they need to re-register
Up to 4 unique founder merch packs (different from the startup program)
Access to HogPatch for the duration of their time in the batch
Partner benefits with Speakeasy and Incident.io
You can find the copy for the latest deal on Bookface in this doc. To post updates, you need to ask James or Tim to do it.
This deal is not available to YC alumni, who started another company – if they're eligible, they can apply for PostHog for Startups instead
This deal is also not available if the YC company has been acquired by a non-YC parent. If an acquisition happens mid-term, existing credits can be honored until expiry but will not auto-renew. The acquiring company can apply for PostHog for Startups if eligible.
✅ Credits can be used to claim a BAA under the Boost plan.
YC teams must apply via our secret YC page, from a PostHog account that uses the company's email domain. To prove their eligibility, we ask for:
Alongside the two programs above, we run two external partnerships that offer PostHog benefits to partner audiences. See campaigns and coupons for how redemption works.
Lenny's Product Pass
Subscribers with Lenny's Newsletter Product Pass who are new paying customers get:
2x the free tier limits on all usage-based products
The Scale add-on for free
Valid for one year
Product exclusions are the same as for the PostHog for Startups plan, including PostHog Desktop, the PostHog Slack app, Inbox, and Replay Vision. See posthog.com/startups for more detail.
$2,000 in credits for core products (only for new paying customers), with the same exclusions as for the PostHog for Startups program
$2,000 in credits for AI products, covering products excluded from the PostHog for Startups program
What happens after companies apply?
Application
A company signs up to PostHog, adds billing details, and applies via the startup form.
Credit
If they meet the basic criteria, we automatically apply the correct amount of Stripe credit.
Welcome + merch
Shortly after, they receive an automated email) from Joe Black, in which we
Confirm their acceptance, welcome them and explain perks
Provide unique code(s) to claim founder kit(s) from the merch store (orders are fulfilled by Micromerch, merch questions can go in the #merch Slack channel)
Milestones
When teams reach 50%, 75%, or 100% of their credit usage — or when credits expire — they receive milestone emails. These come from Customer.io and are managed by Joe Black.
Post-credit
Once credit is fully used or expired, teams are moved to a standard paid plan automatically. We automatically email users to let them know and offer a one-time $500 credit bonus to help soften the transition.
Reviewing applications
Applications are automatically enriched with Clearbit and Clay, then approved. We then manually review all emails to ensure eligibility. If there's a mismatch (e.g. on founding date or funding raised), we’ll email the founder. If we don’t hear back in a week or confirm ineligibility, we remove the credits.
Merch
All merch is fulfilled through the PostHog store by Micromerch.
Founders receive unique codes via email to claim merch.
They can request up to 4 merch packs for co-founders during signup.
We send a short, founder-focused newsletter once per month to all program participants. This is handled as a Customer.io broadcast using a prebuilt template.
Credit usage
Credits can be used for most PostHog products and add-ons, including platform packages.
Startups: ❌ Cannot use credits toward a BAA due to legal risk.
YC teams: ✅ Can use credits for a BAA under the Boost plan.
AI apps and products: ❌ From September 14, 2026, credits cannot be used toward AI apps and products such as PostHog Desktop, the PostHog Slack app, Replay Vision, PostHog AI, and Inbox, due to the prohibitive and unpredictable nature of token-based pricing. Usage incurred before the cut-off can still be paid with credits.
Buying a platform package with credits – including the enterprise add-on – does not come with a dedicated account manager, CSM, or sales contact, in the same way it does not come with high priority support. Those are for paying customers. Founders who want one-to-one help can buy a 30-minute onboarding call from the merch store.
Credits are valid are not transferable, and don’t carry over or convert to cash. They are valid for 12 months and that timer begins at application. Once expired or fully used, teams are moved to standard billing.
Partners
We currently partner with:
Incident.io – $1,500 off a teams plan
Speakeasy – 50% off for 6 months
Discount codes are sent in the welcome email after signup.
If users run into issues with redemption, we can help liaise – though all offers are ultimately at partner discretion.
Contacts:
Incident.io: Zain Mobarik
Speakeasy: Nolan Di Mare Sullivan
We previously offered DigitalOcean credits ($25k), but this was retired in Q2 2025.
Program extensions
We don’t usually extend credits – the 12-month window is intended to be firm and fair. However, we’re open to requests in exceptional cases.
Founders must clearly explain why they couldn’t use the credit in time and provide evidence of recent progress or changes. Requests are reviewed manually by the Customer Success team.
If the Slack invite isn't sent or you discover founders did not receive it, you can manually invite users to the #posthog-founders-club channel. Make sure to select that they are "An external organization" when prompted right after adding their email address. A Slack admin will need to approve them before they're fully added to the channel.
If they did not receive the automated coupon email, check the startup_plan_customer_added event or Customer.io email history to find which coupon codes were generated or sent, then send those links to the founder.
For Shopify access, look up the Shopify credentials in the shared 1Password account.
If there is no startup_plan_customer_added event or Customer.io email record, open the Shopify discounts page, pick an active discount for the same merch type, duplicate it, regenerate the coupon code, confirm it is limited to one use, and save it. You'll have to repeat the process for every founder.
If they have the codes but they no longer work, the most common issue is that the codes expired. Search for each code from the Shopify discounts page. If the codes expired and should still work for this founder, extend the end date on those specific codes, for example by another month. If the codes are missing, already used, or should not be reused, follow the same instructions above to create new ones.
Credentials for Zapier, Shopify, etc. are available in the shared 1Password account.
Dashboard templates simultaneously showcase the use cases of PostHog and make it easier for users to get started. You can find a full list of them on the templates page.
This is "internal" documentation to show PostHog staff how to add new global templates.
Let us know on this GitHub issue if you'd like to see templates that are private for your team.
Creating a new dashboard template
Create your dashboard with all the insights you want on it. Be sure to add descriptions to both.
Open the dashboard dropdown, click "Save as template."
Add variables as objects with the format below. Reference them in your template by adding the ID in curly brackets, like {SIGNUPS}, to replace the placeholder event.
"variables": [
{
"id": "SIGNUPS",
"name": "Signups",
"type": "event",
"default": {},
"required": true,
"description": "The event you use to define a user signing up"
}
],
Once done, click "Create new template." Test that it works in the team project.
Create a dashboard image in Figma in the Hoggies file. Make the size of image small (like 396x208). Export and upload to Cloudinary.
With the URL, go to templates list under dashboards, click the three dots to the far right of your template, and click "Edit." Add the URL to the image_url field and press Update template.
For the website, copy the same hedgehog as a small square thumbnail image (400x400) with a transparent background. Export and upload to Cloudinary.
While you are in Figma, create a 1920x1080 feature image with a couple of the insights. Export and upload to Cloudinary.
In the posthog.com/contents/templates folder, copy another .mdx file from another template, and modify for your new template. Add the thumbnail and feature images you uploaded to Cloudinary.
Open a pull request.
Once merged, click the three dots on the far right again, and click "Make visible to everyone."
To add to EU Cloud, click the three dots to edit the template and copy the JSON. Go to the PostHog EU Cloud instance, create a new blank dashboard, click "Save as template", paste the JSON (minus deleted, created_at, created_by, team_id, and scope), and "Create new template." Add image_url, edit, and test if needed. Finally, make visible to everyone.
Removing a dashboard template
If you ever need to remove a dashboard template, you need to:
Click on the three dots to the right of the template you want to remove and then click Make visible to this team only. This is a required step before you can delete it.
Click on the three dots again and then click Delete Dashboard.
Be sure of what you're doing as this is a non-reversible action.
We collect reviews from users on G2, both to act as social proof and to collect feedback on our product. After a process of trialling incentives, messaging and processes throughout 2022 we have established that:
Reviews are best sought from users who have had a meaningful experience with the product (see below)
Direct gift card incentives work better than other incentives, including charitable donations
Batching reviews into monthly sends is imprecise and a non-trivial amount of work
As such, we have automated our review request process using Customer.io.
The automation currently invites users to leave an honest review in exchange for a $25 gift card, if they match the following criteria.
User has completed the insight analyzed event at least 3 times in the last 30 days
OR
User has completed the recording analyzed event at least 3 times in the last 30 days
OR
User has completed the feature flag created event at least 1 time in the last 30 days
OR
User has completed the experiment launched event at least 1 time in the last 30 days
AND
User has a valid email address and is in the Valid Email Address segment
AND
User has not previously been asked to review PostHog and is not in the Historic G2 Requests segment
This process is handled in Customer.io using the G2 Review Requests segment and the G2 Review Requester campaign workflow. Users are only asked to review PostHog once, with a 2-day delay after the targeting confirms a match. This is important so we can avoid bombarding users with emails and do not nag users for reviews after the initial request.
New reviews are automatically collected for team members in the internal #posthogfeedback Slack channel.
Testimonials
We speak to our users regularly and are often fortunate enough that they say nice things about our product or our way of working. Other times users talk about us in public, such as on social media or on review platforms and forums.
Not all of the feedback we receive can be used publicly. We don't assume that comments from product feedback calls can be used without explicit approval, for example, though approved customer stories, public reviews and social media comments certainly can.
If feedback can be used publicly then we collect it here, so that we can use it elsewhere to enhance our website or docs.
Increase awareness of PostHog, especially among people in our ideal customer profile, through content that is genuinely entertaining
Help developers and PostHog users be more successful through, through content that is genuinely informative
Our model is that of content creators, not a marketing department, as it is for the rest of content. This means that we start from a place of producing great video first that stands alone, irrespective of its connection to PostHog and our products. We have found over the years that if we get this right, the marketing benefits naturally follow, but if we start from a marketing-first perspective, people are never as interested.
As a result, our focus is on awareness, not converting people to sign up or revenue. Other parts of our marketing and product are a much better fit for that.
Product engineers: Software engineers who want to improve their product skills, understand users, and build successful new products.
Founders: Technical and non-technical founders seeking advice on how to run a successful startup.
Who is our competition?
Our competition is _not_ our competitors' video content (the bar is too low), it is the other stuff that our audience is generally watching and enjoying. Think popular YouTube creators, podcasts, even viral content on TikTok and Instagram.
Entertaining vs. informative
Videos exist on a spectrum from 100% entertaining to 100% informative. Some are in the middle and do a bit of both. Generally, when we are making a video, we should try to aggressively pursue one path only, as doing both is _extremely difficult_ - the most likely outcome is that we fail at both and end up with something that is ok.
What does success look like in 2026?
We have a successful YouTube channel. Success means momentum. Momentum means a predictable publishing schedule of videos that fit our audience and brand, thousands of views per video, and a strong understanding of what works.
Video that extends the reach of the brand. We have a consistent and well-oiled system for producing video that extends the reach of PostHog products, features, and the brand.
We are a benchmark. People love what we do. They want to copy what we do. We are proud of our work. People on the internet cite our video as an example how to do video right.
What we're working on
Going from most informative to most entertaining:
Core brand assets: Demo videos and short feature trailers that showcase cool things you can do in PostHog.
Launch videos: The goal is to have a creative format that's repeatable and can be shot at (reasonably) short notice.
These can also easily be repurposed as ads
Startup stories: Regular YouTube output focused on telling the stories of cool companies that our audience is interested in.
Brand-centric hero videos: We have a unique culture and brand, and we want to share that through weird content that no one else would invest in because it's too hard - who else would do an action figures video for April Fools'?
This is where we have the greatest freedom to #do-more-weird - we just need to be wary of the pitfalls of corporate try hard
How to work with the video team
Know what type of video you want to make. Try to fit it into one of the above categories (and remember, we're up for doing a "one-off" film that is totally different to what we've done before).
Got a random idea? Share in the content and video ideas channel.
Got a specific request? Reach out to the video team directly in the Team YouTube channel and explain your idea thoroughly.
Know your product, even if it's early. What does it do? What are the important features? What are some real world use cases? What's coming next? Why should someone pick it over a competitor? What's interesting about it? Many videos will rely on these details.
Accept that the team may say no to your cool idea. Like all small teams, Team YouTube have the final say in what is worked on.
The website is owned by Eli Kinsey and Ian Matson. For general questions or quick updates, the best place to start is the #posthogdotcom Slack channel.
Before you make a change, read Should I open an issue or a PR?. It is the full guidance on which changes you can ship yourself and which ones the website team builds. In short: content changes go in a pull request, everything else goes in an issue.
For larger pieces of work — a new product page, a significant copy overhaul, a new landing page — there's a more structured process to follow.
Why can't I vibecode? You can, but vibecoded stuff tends to be harder for the website team to review and has a tendency to not work well with some existing systems.
Requesting large website changes
1. Draft the content in a Google Doc
Start with words, not designs. Write out the full copy, structure, and any specific requirements. This gives the website team something concrete to work from, and keeps early-stage feedback focused on what matters: the message.
2. Submit it to the website team as a GitHub issue
A brief description of what you're trying to achieve and why
A link to your Google Doc
Any relevant context or references
Your timeline and deadline, if there is one
3. The website team builds from that and opens a PR
Once the issue is picked up, the website team will build the page. They'll open a PR and tag you when it's ready for review so you can give feedback on changes.
4. Review and give feedback from the PR
Review the PR, leave comments, and iterate from there. This is the right moment to give design and layout feedback — not before, when things are still just ideas.
Curious about your request? Issues get triaged onto the website project board, which tracks all of the team's tasks.
Why this process
This approach is designed to stop time being spent on designs that don't get used. It also keeps the dynamic clear: the PMM team hands off, the website team builds, and everyone can feedback.
We don't want to overbake or complicate this process. This is as simple as it can be and as complex as it needs to be.
Chrome extension billing case study: Wildfire Systems
Wildfire Systems implemented PostHog in a Chrome Extension environment. Due to how extensions handle session and identity persistence, they experienced unusually high event volume and feature flag calls, which led to inflated billing.
This document explains the technical causes, the customer's solution, and how to identify similar cases using Metabase.
Technical root cause
| Issue | Explanation | |------|-------------| | PostHog re-initialized on every extension wake | Chrome extensions create a new runtime context when switching from idle to active. Each context re-initialized PostHog without access to prior storage. | | A new distinct_id was created each time | Since local storage is isolated per context, the PostHog SDK could not persist the ID. This triggered a new anonymous ID on each wake cycle. | | identify() was called repeatedly | Each new ID triggered a comparison to the persisted UUID. Since they always differed, identify() was called each time. | | identify() triggered reloadFeatureFlags() | Every call to identify() refreshed feature flags. | | /flags requests were billed, even when quota-limited | PostHog counted these requests toward the usage quota, even if the response returned no flags. | | Added budget mid-cycle had no effect | When the team increased their billing limit, it did not retroactively unlock flags. Only new requests after the monthly reset were allowed. |
Fix implemented by the customer
The Wildfire team applied the correct approach:
Persisted a shared UUID via chrome.storage.local
This ID was generated once, then reused across all extension contexts.
Bootstrapped PostHog with the UUID
On every initialization, the distinct_id was passed via bootstrap.
Avoided calling identify() unnecessarily
The team checked if the existing distinct_id matched the UUID before calling identify().
Minimized /flags requests
Bootstrapped feature flag values were passed during init, reducing the need for real-time flag fetches.
Used PostHog dashboard to monitor
The "My PostHog Billable Usage" dashboard showed real-time data to verify that fixes worked.
How to spot this in metabase
If a customer is using a Chrome Extension without proper initialization, you will often see the following patterns in the usage dashboard:
1. Extremely high identify event counts
identify makes up more than 70 to 90 percent of all events
Often accompanied by minimal actual user activity events (clicks, views, etc)
2. /flags usage is abnormally high
Feature flags represent a significant portion of the total volume or cost
Check the forecasted bill by product to confirm this
3. Total event volume appears inflated without a matching frontend footprint
Session volume may be high without corresponding actions
Repeated initialize-then-identify patterns from ephemeral clients can drive this
4. Usage patterns appear to "pulse" or reset regularly
Graphs show sharp daily spikes at regular intervals
Indicates extension wake cycles creating new sessions and IDs
5. No batch exports, minimal standard library usage
Chrome extensions often do not use session replay, heatmaps, or full web libraries
You may see a custom library version or just raw SDK usage
6. High $set, $identify, $groupidentify volume with few custom events
Suggests backend or SDK-driven implementations without user interaction data
When you see these signs together, it is a good idea to ask: "Are you using PostHog in a browser extension product or other ephemeral context?"
If confirmed, you can share bootstrapping and identity persistence best practices.
---
Recommendations for extension developers
| Task | Details | |------|---------| | Persist ID manually | Use chrome.storage.local to persist UUID | | Bootstrap identity | Pass the UUID during posthog.init() with bootstrap.distinctID | | Avoid repeated identify() | Only call identify() if the ID has changed | | Reduce /flags usage | Use bootstrap.featureFlags and disable polling if needed | | Monitor proactively | Use the "My PostHog Billable Usage" dashboard | | Educate early | Customers should be aware that extensions require manual handling |
Metabase dashboards mirror a customer’s PostHog usage so we can diagnose billing, implementation quality, and quick-win optimizations. For audio and video learners, check out these:
Metabase overview recording
Billing deep dive walkthrough
While checking the account in Vitally, you can access a dedicated Metabase dashboard for this account directly from the sidebar:
Image: Vitally Dashboard Usage Link
(Note that you may need to configure your properties first to see that by clicking on the "+" button next to properties)
There are two Metabase instances, US and EU, that correspond with the PostHog instance that the customer is on. There might be some visual differences, but accessible data should be roughly the same:
Image: Metabase Customer Usage Dashboard Example
What to pay attention to
1. Billing history
Here you can see an overview of the billing: past bills that went through, bills that were covered with the usage of credits, refunds, and future forecast:
Image: Billing history and credits as seen in Metabase
Looking at credits can be especially relevant for Startup or YC Plan customers (that usually use credits or might run out of credits and also display a forecasted MRR). If we ever issued one-off credits (e.g. for spikes), their usage will also be similarly displayed here.
Refunds are also visible with a red bar:
Image: Refunds as they would appear in Metabase
The forecast corresponds with the forecasted MRR that you can see in Vitally’s sidebar, while if you’re interested in how much has been incurred so far, it’s something you can check directly in Stripe’s invoice:
Image: Vitally forecasted MRR and Stripe links
2. Forecasted bill breakdown by product (all projects)
This is where you can quickly see what constitutes the majority of the bill and what can be a lever to reduce customers' spending. It's the best place to start the conversation around the value they take from PostHog.
Image: Metabase billing circle
Check the highest % to see if we can share some recommendations on how to reduce the spend, see if it’s not caused by improper implementation, and pay attention to whether the user is not billed for the add-ons that they don’t use in practice (e.g., Groups, data pipeline).
3. Billing limits
The default limit for the data warehouse is $500, and $150 for PostHog AI, so that’s something you may see quite often. Seeing other billing limits added might be an indication that someone could benefit from a more long-term solution and a cost-cutting strategy, as once the limit is hit, the data is not ingested anymore and is lost forever. Billing limits are just a temporary patch, but not a solid solution.
Image: Metabse billing limits
4. Projects for the organization
This is where you can see whether any Session Replay controls have been implemented (minimum duration, sampling, feature flags). Any URL/event triggers won't be visible here.
If controls are missing but usage is high, recommend applying them before scaling replay usage. Most users should at least have minimum session duration enabled as most < 2 second recordings are not valuable but still racks up usage and billing.
Image: Metabse session replay controls
Session replay controls must be added for each project separately.
5. Org membership permission level
We use all_admins_owners to send our outreach emails on the onboarding team. You can copy all of them for your first email, and if the list gets too long, you can compare it with the list of active users in Vitally to see who might see your email. After a while, if you haven’t heard back, next time you can experiment with emailing recently active users from Vitally as well.
Image: Metabase admin owner member emails
6. Key event volume (all projects)
The heart of our analysis. You can see the % of the most used event types. You can see whether they’re using Autocapture, custom events, or when they have an unusual spike in $pageleave events. If you see a high ratio of autocapture events, but 0 Actions in the “Actions (by type)” graph, you can assume that they may not take enough value from it.
Image: Metabse key event volume for all projects
7. Total event counts (all projects)
A supplementary chart to the “Key event volume”. Both should be reviewed together. The area chart shows the most used events, and potential unexpected spikes. Events marked by the $ sign are the default PostHog events.
Image: Metabse total event counts for all projects
This graph corresponds with “Billable usage insight” insight within the “My PostHog billable usage” dashboard template. It’s a good idea to show it to users, so that they can keep an eye on their usage and decide if everything they see there is needed for their tracking.
8. Event ratios per person or session (implementation error check)
If you see an unnatural spike in $set or $identify events in the two previous charts, here you can see whether their implementation is correct. Usually, 1-3 calls per session are alright, and things may get tricky if it’s more than 4. If they are using group analytics, pay attention to the groupidentify calls per session as well. Feature flag calls per session can also help indicate further troubleshooting may be needed if it's too high:
Image: Metabse event ratio checks for implementation errors
9. Hog Destinations
If they pay for data pipelines but have no active destinations, flag the mismatch and suggest enabling or removing the add-on. Newer accounts pay by usage (rather than the add-on), so keep an eye out for that as well.
Image: Hog destinations, batch exports, data warehouse syncs
You should also check whether they are using batch exports or data warehouse syncs.
Billing Deep Dive dashboard
The link is already available in our Daily view in Vitally, but make sure you also have it handy in the Account’s sidebar as well. Go to Properties > PostgreSQL> Billing Deep Dive Dash, and click on a pin icon:
Image: Metabase billing deep dive dashboard from within vitally
This dashboard is extremely helpful to dive deeper into the usage of Feature Flags and Session Replay, which is not that clear and easily accessible in the default Metabase dashboard. It gives you more insight into mobile vs. standard web reply, or decide vs. local evaluation requests for feature flags.
It’s really handy when you want to investigate a spike in usage (e.g., due to an error in the implementation) and for how long it lasted. Some users struggling with their config may ask you about it specifically.
Pick the appropriate feature from the Category dropdown, update the filter, and adjust the period.
Here, for example, you can see an error in the implementation of the Feature Flags local evaluation, how it compares to Feature Flags in the front-end, and when the problem has been resolved:
Image: Metabase billing deep dive dashboard example
The breakdown by “product x team_id” helps understand the usage per project (by project ID). It's a very popular feature request that the Billing team is working on so that it can also be accessible within PostHog.
Image: Metabase billing deep dive usage per project
Operational billing actions
Re-authenticate the billing admin
Go to billing.posthog.com with your PostHog Gmail, then billing.posthog.com/admin should load again after login.
Adding credits
Watch this video: How to add credits (Loom)
Image: Adding credits in the billing admin
In the billing admin portal, click “Add” next to Credits, search by Organization ID, set amount and reason, and leave an internal note.
Credits now fund the Stripe balance; legacy “credits expire” fields may still appear. Notify Billing if credits do not stick.
After adding the credits, return to Stripe to ensure the changes were applied correctly.
Rectifying a failed invoice
Watch this video Issuing a credit note (Loom)
Sometimes, you may notice that a customer has deliberately not paid their invoice due to an unexpected spike in product usage or because the bill exceeded their planned budget. In some cases, they haven’t reached out to us for help before the bill was renewed.
In these situations, we're here to help them sort out their usage and billing. However, it's no longer possible to simply add credits—we now need to adjust the already-issued invoice directly in Stripe.
This can be done using credit notes, which allow you to either compensate the full amount or offer a pro-rated relief. Please ensure you have the appropriate Stripe permissions; otherwise, you may not be able to access this option:
Access the invoice in Stripe.
Look for the “Issue a credit note” option.
Select a reason and add an internal note explaining the context.
Check the items to credit. If you’re compensating the full amount, all items should be selected. If you're addressing a specific issue—such as an unexpected spike in usage—select only the relevant line items to discount that specific amount.
After saving the changes, you should see on the main invoice page that the invoice is marked as “Canceled”, and that the credit note has been sent to the user.
Image: Stripe failed invoices and issuing credit notes in lieu of a refund
As a best practice, always engage with the user first to understand their specific situation. This allows them to confirm whether an unexpected event occurred on their end, rather than us proactively rectifying failed invoices. The reason for this is that the customer may churn, and in that case, the invoice might be considered uncollectible rather than refunded.
Lastly, always add a note in Stripe to explain why credits are being issued.
Welcome to the PostHog's Onboarding team! We only hire about 1 in 400 applicants, so you've done well to make it here! Unlike a lot of companies, we don't have a super-long onboarding process and would prefer you to be up and running with your customer base as quickly as possible.
Here are the things you should focus on in your first few weeks at PostHog to help you achieve that.
Ramping up is mostly self-serve - we won't sit you down in a room for training for 2 weeks. If you're not sure who is supposed to make something below happen, the person responsible is almost certainly you!
Below is a rough plan for your first month - use it as a guide, not a contract. The handbook itself is a work in progress, so you'll find gaps as you ramp up, things you needed to know that weren't written down. That's normal, and when you find a gap, your job is to fill it in so the next person has it easier.
Meet with Magda, who will run through this plan and answer any questions you may have. In addition, come equipped to talk about any nuances around how you prefer to work (e.g., schedules, family time, etc.).
Setup relevant tools and check out tools specific for the Onboarding team.
If you start on a Monday, join your first PostHog All Hands (at 4.30 pm UK/8.30 am PT) and be prepared to have a strong opinion on whether pineapple belongs on pizza.
If you start on a Monday, join your first Onboarding standup.
We fill in a GitHub issue every week before this meeting, so we are prepared for the discussion topics. Magda will add your GitHub handle to the template.
Rest of week 1
This week is about getting set up and learning how we talk about PostHog. You'll feel extremely unproductive, and that's fine - the aim is to set yourself up for in-person onboarding. Read everything you can, work through the product fundamentals, and gather questions we can work through together.
Explore Slack. We're public by default, so Slack is one of the richest resources you have.
Meet with Ben Bradley, who's responsible for GTM teams.
Week 2
Shadow more live calls and listen to more BuildBetter recordings. Check out our Onboarding folder, where you can also find sessions on productivity and workflows.
Explore Vitally and Metabase – take note of any questions you have to go through during in-person onboarding.
Try running through the onboarding exercise that Kaya designed to test your skills for working with customer accounts.
Towards the end of the week, schedule a demo and feedback session with Magda. We might need to do a couple of iterations over the next few weeks as you take on board feedback, don't worry if that's the case!
Get comfortable with the PostHog Docs around our main products.
Learn how to think about each product. As you go through the fundamentals, for each product you're trying to be able to answer:
The value add - why a customer would care
How it's implemented and implementation quirks worth knowing
Signs of poor implementation
How it works alongside other PostHog products
How to get value out of it
What you can do with the MCP
In-person onboarding
Ideally, this will happen in Week 2-3, with the company of a few colleagues (depending on where we do it and who's around). It will be 3-4 days covering (among others):
Demo practice session with the team.
The data we track on customers in PostHog and some hands-on exercises to get you comfortable using PostHog itself.
Deep dive on Vitally and Metabase, i.e., seeing how the systems we use come together day-to-day.
Toolkit and internal processes.
No stupid questions session.
Detailed training plan available in the new hire onboarding checklist. This is a checklist for the Manager, you don't have to read it beforehand.
We'll start routing new leads to you at the end of week 2. Start to review these and reach out, using a shared booking link with someone else from your region so they can back you up in the first few weeks. This is a great option to practice and fail.
Weeks 3-4
This is when you start working with your customers. Reach out, take the first calls, pick up the questions that come in, and start figuring out what each customer needs from you. You'll learn more about the product as you go, but the main thing in these weeks is starting to be helpful to your customers.
You're already reaching out to our customer base.
Focus on taking more and more ownership on calls so that team members are just there as a safety net.
Continue to meet with customers - very quickly, you should be doing these solo. The customers you are working with will mostly just be getting started, so you'll see a lot of very familiar patterns emerge.
Evaluate implementations as you go - is the customer set up well, are they getting value? The basic implementation review and health check are the structured ways to do this.
Set up a call with Daniel to get a "soft intro" to Vitally playbooks, segments, and our internal metrics. It's not a deep-dive - just getting familiar.
Keep working on your product knowledge. You can find a couple of exercises here.
How do I know if I'm on track?
By the end of month 1:
You continue learning from the received feedback.
You have a good grasp of our internal processes and workflows.
You lead customer calls on your own.
You should consistently craft a minimum of 10 outreach messages per day, without compromising on quality, style, or accuracy.
You don't let accounts fall through the cracks before their renewal.
You pass well-qualified opportunities to Sales via the Onboarding referral segment.
You shipped your first handbook PR. The point isn't the PR itself; it's that the handbook only stays useful if everyone adds to it. Not knowing something isn't a failing, but leaving it undocumented for the next person is.
You're sharing with the team. You're posting wins, learnings, opportunities for feedback, and anything else valuable in our shared channels. You were hired because we think you can improve our team, so don't be afraid to share opinions and approaches.
You've embraced PostHog's culture: You're the driver, you take initiative, prioritize your time well, and work independently.
By the end of month 2:
You're a PostHog power user - most questions you raise can only be answered by product engineers rather than the support team.
You should show steady growth in both call volume and outreach activity, with a minimum of 15 outreach emails sent per day.
You fully participate in team discussions and contribute to team projects. You raise the bar.
By the end of month 3:
You've implemented process and system-level changes to make your job better/more effective.
You surface ideas contributing to the growth of the team.
Customers are happy after interacting with you, and you meaningfully contribute to their success.
General expectations
Our customers are always central to our work. There’s time and space to work on fun projects, but that should never happen at the expense of our customers. Below are some non-exhaustive tips to help you stay on track during and after the probation period.
Core responsibilities
Make sure you’re on top of our customer base in Vitally. Don’t let renewals fall through the cracks.
It's not a race - quality over quantity, always. Spend time reviewing accounts, be accurate, and genuinely helpful in what you email to customers.
Listen to customers and respond to their needs. It’s a conversation, not a monologue with a set agenda.
Make sure your Calendly schedule stays available for customers. You’re the master of your own calendar, and we trust you, but be reasonable.
Do the Sales handoff where appropriate and always provide context on the customer.
Maintain the hygiene - follow the process in Vitally, add notes, or tasks when necessary. Remember that we share the workspace, so keep the order.
You’re the driver, so take initiative. Keep in mind improvements, optimization, process, or content updates as you go. Don’t be afraid to voice your ideas.
AI should never be a substitute for learning. Use it to increase efficiency, but don't follow it blindly.
Communication and ownership
Make sure you read the Handbook page on Communication. Always answer pings, even if it’s just to say “I’ll look into it later”. Emoji reactions can be helpful to indicate that you acknowledged or completed the task.
Read the Handbook page on Feedback) Share and ask for feedback, take it with grace. Remember that it should be kind and factual, not based on assumptions.
Publish your Sprint planning update on time. It should be done on Monday at the latest, so that others have time to read it before the Sprint planning call.
Be yourself and stay human. Don’t send AI-generated emails to customers.
Set an autoresponder in your inbox whenever you take a longer time off, and direct your customers to onboarding@posthog.com so that we can pick up your conversations.
Share your knowledge! Share what you learned, or found out - the whole team will benefit from it.
Don’t be late for calls. It’s rude, the same as eating on them.
Use the Time Off tool to communicate your absence in advance.
Keep your promises. If you promised to follow up with a customer or colleague, or work on a project, do it.
Stick to deadlines.
Staying up to date
Everything at PostHog changes really fast. That's how to keep up as a start:
Follow #tell-posthog-anything and #demo-posthog-anything daily for general announcements.
Follow #group-cs-sales-support channel daily - it's crucial for all folks in customer-facing roles.
Stay on top of the #incidents channel to know what’s going on and be able to inform customers.
From time to time, it’s worth taking a look at #sales, #customer-success, #team-new-business-sales, #team-product-led-sales to get inspired by new ideas that other customer-facing folks implement, and what’s going on in general
#changelog channel to stay up to date with newly released products and features.
#today-i-learnt set up by Daniel, great for sharing and learning new things.
Attend All-hands calls, and if you skip them for any reason, catch up with the recording. It lets you stay on top of the new features we release and our direction.
Set a Slack matcher for specific keywords (e.g, “onboarding referral” if you want to see leads we pass to Sales).
Slack also has a cool AI Recap feature - it might be helpful, same as using Slackbot to find relevant conversations.
Don’t let your product knowledge get stale - check docs, use the product.
Our customers are busy, self-serve by default, and allergic to anything that feels like a time sink. We deliver the most value when we can talk directly, so it’s worth being intentional and trying creative ways to earn that conversation.
That said, we’ve repeatedly seen customers implement our recommendations even when they never reply. That’s why we don’t gate value behind a meeting - we provide it regardless.
Check out the Getting people to talk to you page in the Sales Handbook and our learnings below. As you experiment, add more and share what worked!
Our guiding principles
Stay human. Be yourself, stay casual, open, and friendly. Aim for “talking to a friend,” not a script.
Be genuinely helpful. Reduce complexity. Offer simple next steps that save the customer time and effort.
Be prescriptive. Don’t just explain options - recommend the best path for this customer, and say why. You’re the expert. Here’s a good example.
Be generous. If a refund or credit is clearly the right call, make it happen. Use your good judgment.
Outreach
Your first message is your best chance to earn attention. It should feel like practical help from a real person - not a pitch. Lead with a specific observation, a clear benefit, and an easy next step.
Captivating subject lines
Avoid generic subjects (“Checking in”, “Following up”). Instead, experiment with short, specific lines and anchor them to a specific outcome.
Use the following product signals:
Billing / pricing signal - e.g. first bill coming up, increased number of billing page visits
“Your first PostHog bill is coming up - quick way to save $”
“PostHog bill coming up - quick way to reduce it”
“Noticed a spike in costs - 2 ways to bring it down”
“Cost check: a small tweak that can reduce event volume”
Docs signal - increased visits to the docs pages
“Noticed docs activity - need help with [topic]?”
Event spike / instrumentation signal
“Too many events? Let’s fix it.”
“I think you’re tracking more than you need”
“Event spike yesterday - need help figuring it out?”
General value offer (audit / review)
“Quick data audit from the Onboarding team”
“Tracking review: 3 improvements I’d make”
“Want me to sanity-check your events / funnels / flags?”
“Data audit: 3 tracking gaps I’d fix first”
“I recorded a 2-min walkthrough for your setup”
“A recommended dashboard for [their use case]”
“Worth a look before your next release”
"Are you trying to do [goal]? (I can help)”
Content
Keep it short. Don’t overwhelm the reader. It’s tempting to include every tip and best practice, but concise emails get read and replied to. Share the headline observation and the next step; save the deep dive for the call (or a follow-up).
Set expectations early. If you want consistent engagement throughout onboarding, be explicit about what the program includes and why it’s worth their time. When customers know what to expect and how to use our time, they’re more likely to participate. Setting clear boundaries also helps - what you can help with, and for how long we’re around.
Use prior context to be proactive. Before you hit send, take a minute to scan prior threads. If a customer spoke with Sales during an evaluation, check what came up and reference it (e.g., “I saw you covered X with [Name]”) so your email feels connected. And look for other loose ends too, e.g., an old support ticket, or a question from months ago. Following up with a real solution feels personal, and proactive delight gets noticed.
Good CTAs
"Want to take a look together?"
"Want to compare notes on what's working?"
" Worth a look before your next renewal?"
"Happy to help if the timing is right."
Vibe killers (never use) "circling back" · "just touching base" · "hope this finds you well" · "I'd love to connect" · "I'm genuinely curious" · "are you open to a quick chat?" · "let me know your thoughts" · "synergy" · "leverage" · "alignment" · "best-in-class".
Checking in
This is where we can have a real impact on product adoption and usage expansion. Think of it as a value-driven "soft cross-sell".
Don’t just repeat yourself. Avoid rehashing the same observations from your first message. If your earlier advice still hasn’t been implemented, send a small, friendly nudge. Otherwise, bring something new:
Look at what they’re actively using right now.
Infer what they might be trying to measure or achieve as a business.
Mainly, help them get to an “aha” moment, and/or suggest one or two features they’d benefit from, but may not have discovered or had time to try. PostHog features become more powerful when used together (e.g., funnels/error tracking + session replay + PostHog AI). Share a specific guide, an example, or a Loom video, so the customer doesn’t have to poke around to figure it out. You can take some inspiration from Use Case Selling handbook pages.
A very powerful way to engage the customer and provide value is to run an account audit prompt on their account and save the findings as a notebook for them. The prompt creates a readable, easy-to-follow guide on the areas the customer might not have thought about before. This also works really well as an additional post-meeting resource!
<summary>Account audit prompt</summary>
Audit this customer's PostHog account and write a notebook for the customer. Last 30 days. Switch to SQL mode.
Rules:
Batch independent queries, run them in parallel.
Discover schema on demand: SELECT * FROM <table> LIMIT 3, or system.information_schema.tables / columns.
Always verify: if a table errors or looks empty when you expected data, check system.information_schema.columns before concluding.
Filter bots: AND getBotName(properties.$raw_user_agent) = '' on every events query. Never isLikelyBot or $virt_is_bot: they flag every non-browser SDK and drop whole mobile and backend products.
Internal and test users: apply test_account_filters from SELECT * FROM system.teams (an array of {key, type, value, operator}; type: event maps to properties.<key>, type: person to person.properties.<key>). If empty, say internal traffic cannot be separated.
Count people with uniqExact(person_id), never distinct_id.
system.* entity tables return deleted and archived rows. Filter every count: deleted = 0 for actions, cohorts, dashboards, feature_flags; deleted = 0 AND saved = 1 for insights; archived = 0 for experiments; surveys have no flag, judge by start_date and end_date.
LIMIT 10 on any top-N. Apply bot and test filters to non-events tables only where those fields exist.
Where things live: events by default, except replay → raw_session_replay_events (on/off state); heatmaps → heatmaps; logs → logs; LLM prompt/response bodies → posthog.ai_events. Billing and delivery meters → app_metrics (app_source + metric_name + count). Ingestion problems → system.ingestion_warnings. Warehouse syncs → system.source_sync_jobs joined to system.source_schemas. Query volume → query_log. Everything the customer created → system.*.
SELECT
count() AS total_events,
countIf(event = '$pageview') AS pageviews,
countIf(event = '$pageleave') AS pageleaves,
countIf(event = '$autocapture') AS autocapture,
countIf(event = '$exception') AS exceptions,
countIf(event LIKE '$ai_%') AS ai_events,
countIf(event = '$feature_flag_called') AS flag_evals,
countIf(event = 'survey sent') AS survey_sends,
countIf(event = '$identify') AS identify_events,
countIf(event = '$set') AS set_events,
countIf(event = '$groupidentify') AS groupidentify_events,
countIf(event = '$web_vitals') AS web_vitals,
countIf(person_mode IN ('full', 'force_upgrade')) AS identified_events,
uniqExact(person_id) AS people,
uniqExact(properties.$session_id) AS sessions,
uniqExact(properties.$lib) AS sdk_count,
groupUniqArray(10)(properties.$lib) AS sdks
FROM events
WHERE timestamp >= now() - INTERVAL 30 DAY
AND getBotName(properties.$raw_user_agent) = ''
Analyze each area. Each carries a value read (getting the most from it) and a cost read (what it costs, how to cut). Prefix each finding subheading :large_green_circle: working well, :large_yellow_circle: worth attention, or :red_circle: needs action. If an area is unused, consider how it might be used in this project. State each finding only once. Always inline link to documentation:
Instrumentation: SDKs and versions (properties.$lib, $lib_version; old versions miss cost controls like replay minimum duration and flag bootstrapping); autocapture vs named-event share; identified vs anonymous (person_mode); identify()/$set/$groupidentify each about once per session (compare totals to sessions). Ingestion warnings (system.ingestion_warnings type and timestamp; cannot_merge_already_identified means identify ran on already-identified users, spending events for nothing). Custom events no saved insight references (they bill but are never analyzed; cross-check flags, cohorts, experiments before suggesting removal). Dev or staging leakage (properties.$host localhost or staging domains billing here means point them at a separate project). If autocapture is a large share with few named actions, name the potential specific actions or custom events to create that don't already exist (actions apply retroactively).
Product analytics: top events, paths, week-over-week retention, drop-off, spikes, DAU/WAU, dashboards, alerts, subscriptions, gaps in measurement. Which event names and libraries drive the most billable volume.
Web analytics: enabled, data flowing, conversion goals, core web vitals.
Session replay. Three-state read:
SELECT
uniqExactIf(session_id, min_first_timestamp >= now() - INTERVAL 30 DAY) AS recordings_30d,
uniqExact(session_id) AS recordings_all_time,
minIf(min_first_timestamp, min_first_timestamp >= '2015-01-01') AS first_recording,
maxIf(max_last_timestamp, max_last_timestamp <= now()) AS latest_recording
FROM raw_session_replay_events
30d > 0: recording now. all-time > 0 but 30d = 0: stopped, give the last date and name candidates. Both 0: never recorded. latest_recording will show if it was turned off and when. When replay is active, assess the minimum-duration lever from session_replay_events (session_id, dateDiff('second', start_time, end_time), console_error_count) if its count roughly matches the read above: a high share under 2 to 5 seconds is bounce recordings they pay for.
Heatmaps: group by type so the real values surface. See total, active vs stale. Run:
SELECT type, count() AS interactions, count(DISTINCT current_url) AS urls
FROM heatmaps WHERE timestamp >= now() - INTERVAL 30 DAY
GROUP BY type ORDER BY interactions DESC
Feature flags: total, active vs stale (created before the window with zero $feature_flag_called in it, but server local-eval flags may not emit the event, so caveat it), evaluation distribution by $feature_flag key and $lib, server vs client, at 100% for 30+ days, flag-shaped cases that should be experiments. Cost is per /flags request, not per flag: the lever is cutting request volume (local evaluation, polling cadence, bootstrapping), not archiving individual flags.
Experiments: running (system.experiments: start_date set, end_date null, archived = 0) and how long; one running for months is usually decided, ship the winner and stop it. Sample sizes, statistical health.
Surveys: running (system.surveys), response rate per survey (survey shown vs survey sent, grouped by properties.$survey_name), targeting, response limits. Always-on surveys quietly accrue billable responses.
Error tracking: capturing exceptions, grouping, assignment, alerts. Top exception types come from $exception_list, not $exception_type (that scalar is null ~80% of the time and fakes a null-type flood); extract the first with JSONExtractString(arrayElement(JSONExtractArrayRaw(JSONExtractString(properties, '$exception_list')), 1), 'type'). Ingested vs rate-limited (app_metrics, app_source = 'exceptions'). Suppression rules drop matches before they bill.
LLM observability: $ai_generation/$ai_span/$ai_trace/$ai_embedding volume, generations, traces, cost by model (properties.$ai_model, sum(toFloat(properties.$ai_total_cost_usd))), latency. Deeply instrumented agents emit far more spans and traces than generations. Confirm senders are real users, not PostHog AI usage by admins.
Data warehouse: external sources, sync health, joins with events. Rank schemas by total rows_synced over the window. Look for full_refresh vs sync frequency (system.source_sync_jobs: rows_synced, status; join system.source_schemas on schema_id = id for name, sync_type). full_refresh on a large table re-bills every row each sync.
CDP, destinations, transformations, workflows: enabled inventory (system.hog_functions: type, enabled, deleted). Destination deliveries and batch-export rows (app_metrics, app_source'hog_function' and 'batch_export'); the billed meter is metric_name = 'billable_invocation', not failed/succeeded/triggered (those are delivery outcomes), so size cost from that and read a 100%-failure rate as a delivery problem to fix, not a bill. Workflows (system.hog_flows, filter by status). Transformations act on future events only; a filtered delivery is skipped by its own filters, which is free and good. only metric_name = 'billable_invocation' bills; failed, filtered, triggered, and fetch do not (a 100%-failing destination shows zero billable_invocation). A dead destination is a delivery fix, never a cost saving: do not rank it as one.
Platform, queries and logs: query volume app vs personal API key (query_log, is_personal_api_key_request; an API spike usually means an automation polling too often). Logs GB ingested and dropped (app_metrics, app_source = 'logs').
Revenue: billing connected and joined to usage. If not, connect Stripe or Chargebee as a warehouse source and join to events in SQL.
Cohorts: count, static vs dynamic, usage. Dynamic cohorts with behavioral or lifecycle criteria can't target feature flags, experiments, or surveys; flag any that do and recommend a static duplicate or a person property to target instead.
What they're not using yet: one inventory across system.* shows coverage and the best untapped plays (saved insights, dashboards, notebooks, actions, cohorts, annotations, saved SQL views data_modeling_views, feature flags, running experiments, early access features, running surveys, recording collections session_recording_playlists, error suppression rules, warehouse sources, active batch exports, enabled hog_functions and hog_flows, insight alerts alerts and log alerts logs_alerts, integrations). Count with the right filter per table. A zero is an opportunity, not a failure.
Write the notebook
Renders only: h1-3 headings, bold, inline code (but not in bolded sentences), fenced code blocks, bullets, links, emojis. Anything needing alignment goes in a code block.
Open with an ## At a glance space-aligned table (columns: Area, Main Finding, Next Step). Each area is separated by underlined of ─.
Embed all relevant data as a table in fenced code blocks. Do not embed insights directly. Format every table as a simple table: space-aligned columns with the header underlined by a line of ─, never pipe-delimited.
Use headings for hierarchy. Each subheading states primary finding (":large_yellow_circle: Autocapture is 60% of your events, turn it into actions").
Recommendations: 5 h3 headings ordered by impact, each with the action, why, and a docs link.
Untapped opportunities: 3 to 5 h3 headings forward-looking plays. has to be something new that wasn't covered before.
Frame cost findings as efficiency and savings, not waste or blame. Rank recommendations purely by impact; give fewer than five rather than pad.
At the end of the notebook, add all the SQL queries used in separate code blocks for each area.
Sentence case, no em dashes or en dashes. Never use --- or any dividers between sections; separate them with 2 blank lines and the next heading only. Output as one continuous block.
After drafting the notebook, validate that all formatting rules in this section have been met. Fix, and only then save the notebook.
Lastly, if the customer is trending toward growth (usage, team expansion, increasing volume), it’s okay to mention pre-paid credits and the option of dedicated human support early. Framing it as “when you’re ready” gives them time to consider it and makes a future Sales handoff smoother.
No response?
Review the list of users on the account: who’s active in PostHog, what roles they have, and who is most likely to own outcomes (implementation, analytics, product, engineering) vs. commercial topics (billing/procurement). Choose a small set of the most relevant people (3-4 total) and avoid repeatedly emailing everyone.
A small, human touch can help here! Use what’s publicly obvious or clearly relevant (their product category, their website messaging, their goals). If you genuinely relate (e.g., you’re learning a language and they build a language app), one sentence can be enough to build rapport. That’s also a great tip for the first outreach.
Use Vitally and Metabase to understand the customer’s current setup. For easier access, you can pin the "Engagement Metric Dashboard" custom trait in Vitally, where you can take a closer look at power users in the organization, the usage of AI or error tracking, and more.
You can supplement Metabase analysis with the HogSpy extension to audit the implementation of identify, flags, and experiments.
Then zoom out to learn about their business, their product, and the rest of their stack. The better your context, the faster you’ll get to relevant recommendations.
Lead with their KPIs
Use the customer’s KPIs (usually captured in the booking form) to drive your prep. Ask yourself: what would “success” look like for them? Come prepared with 2-3 concrete use cases tied to those KPIs (e.g., a specific insight type, dashboard, funnel, experiment, etc.). This Handbook page can be a good source of inspiration.
Map the stack and spot opportunities
Check Wappalyzer (login details in 1Password). It’s not always perfectly accurate, but it’s usually good enough to understand the tools they rely on. Use it to identify integrations, suggest Sources/Destinations where it makes sense (e.g., HubSpot),
It might be a great moment to position PostHog as the place where multiple tools can connect under one hood.
Customers respond well when we’re proactive, especially when we show them a path they hadn’t considered. PostHog is most powerful when features compound, so part of prep is identifying the next adoption step that unlocks more value. You can take some inspiration from Use Case Selling handbook pages as well.
Use AI to broaden your angles
AI can help you sanity-check assumptions and surface ideas you might miss. Customer-facing teams at PostHog use PostHog AI, Claude (with PostHog + Vitally MCPs), Cursor, or Antigravity. Use it to generate questions, identify likely “aha” moments, and draft call checklists, then apply human judgment to keep it relevant.
You can also run PostHog AI on the customer instance (visible only to us, no cost incurred) to do the account audit. Prompt below.
<details><summary>PostHog AI prompt</summary> Analyze the organization across the following dimensions using the last 30 days of data.
Instrumentation health
What SDKs are sending data? (web, mobile, server-side, etc.)
What's the ratio of auto-captured events vs. custom events?
Are there any custom events that appear to be duplicates or redundant?
Are there events with very low volume that might be broken or deprecated?
Are person profiles being created?
What's the identified vs. anonymous user ratio?
Feature flag usage
How many feature flags exist?
How many are active vs. stale?
Which flags have the most evaluations?
Which have the fewest?
Are any flags being evaluated server-side vs. client-side?
Can you tell?
Are there flags that have been at 100% rollout for more than 30 days that could be cleaned up?
Product usage patterns
What are the top 20 most frequent events?
What are the most common user paths? (entry point to key actions)
What does retention look like week over week?
Are there obvious drop-off points in any user flows?
What's the DAU/WAU ratio (stickiness)?
Session replay
Is session replay active?
How many recordings were there in the last 30 days?
What's the average session duration?
Are there minimum duration filters set, or are very short sessions being recorded?
What's the rage click and dead click volume?
Underutilized PostHog features
Are they using experiments?
If not, are there flags that look like they could be experiments?
Is web analytics enabled and collecting data?
Are surveys being used?
Is error tracking / exception capture active?
Are any data warehouse sources connected?
Are cohorts being used?
How many exist?
Cost optimization
What products are driving the most usage? (events, recordings, flags)
Are there any quick wins to reduce noise? (short session filtering, dropping low-value events at ingestion, disabling stale flags)
Summarize findings with a prioritized list of recommendations:
what's working well
what needs attention
what untapped opportunities exist
Follow-up with: Now go look at their business and domain. What should they be doing to get more use and value out of PostHog?
On the call
Start with a quick discovery (3–5 minutes). What they shared in the booking form may not reflect today’s priorities or the goals of everyone on the call. Confirm what outcome they want by the end of the session.
Have the relevant docs ready. If you can anticipate the topic of the session, keep the key docs open so you can screen-share them quickly.
Show, don’t tell. Build things live. If you discuss funnels, dashboards, cohorts, or flags, create one. Save it so the customer can revisit it later.
Connect features. Show how features compound and check this Handbook page for inspiration:
Funnels → drop-off → jump into Session Replay to understand it better and create a cohort
Error tracking → watch related replays
Experiments → measurable impact → rolling out the winning variant
If you don’t know something, don’t guess. Open the docs or use PostHog AI during the call. It builds trust and teaches them how to self-serve.
Check the event schema (if relevant). If their KPIs require certain milestones, verify they’re capturing the right events/properties. E.g.:
Walk through their signup/purchase flow and compare it to events captured.
Use PostHog AI to watch Session Replays and suggest missing milestone events.
Spot unused events. Show what’s used vs. unused and where volume can be reduced. This is an easy way to explain optimization opportunities and cost control:
Activity → Event counts → last 30 days
Open an event → check if it’s used in any saved insights/queries
Introduce our beta features (if relevant). Encourage customers to use them and share feedback. It can positively impact adoption before the feature becomes a paid product.
If growth signals are strong, plant the seed early. If the account is on a positive trajectory, introduce the idea of prepaid credits coming with a discount and the option of a dedicated PostHog human.
Email & Notebook Follow-up
Given how successful Notebooks have been with our customers, we’re experimenting with creating a concise post-meeting Notebook that includes the same resources you would normally share in your follow-up email, along with the Gong recording.
The goal is to make the information accessible to a wider audience within the customer’s organization. You would send meeting participants a follow-up email containing the relevant resources and a link to the Notebook, while the Notebook would make the same information available to other users within their PostHog instance.
Send it the same day. Use the momentum!
Include the public Gong recording link.
Loop in everybody. If some folks couldn’t attend, include them anyway so they can catch up async.
Summarize the call and send resources. Include some extra resources if you feel it would be beneficial as well. For example, our YouTube playlist is great!
If relevant, give them one quick win. Encourage a small task they can do immediately after the call to lock in value and reinforce learning.
If you feel you have built a strong relationship, use your champion to introduce you to other teams that might be interested in PostHog and might be willing to jump on the call to be shown around.
Leverage the good relationship you've just established, and ask for direct feedback on the onboarding experience. Link to our survey in your email/notebook.
Share any feedback or feature requests with the relevant product team. Their responsiveness can help you deliver some customer happiness! It's always great to be able to send a GitHub link to follow in your email.
All Vitally traits accessible as ` traits.vitally.custom.traitNameFromVitally in PostHog queries, eg see the onboarding_accounts_timestamp_check` view)
JSON storage format (requires cleaning for arrays/complex fields)
Getting started with any new tool can be overwhelming, and PostHog is no exception. We want to make sure you're configured correctly, using the right features for your needs, and seeing real value.
That's why we offer personalized onboarding. Whether you need help with initial setup, want to optimize your billing, or are looking to align PostHog with your business goals, we're here to help.
What to expect
Our onboarding program spans 8 weeks and includes:
Account review and optimization tips - We'll review your current setup and share recommendations to help you get the most value while minimizing costs.
First call (30 minutes) - Let's get hands-on! We'll walk through optimization practices together and answer any technical questions about integrating PostHog into your stack.
Second call (30 minutes, optional but encouraged) - Ready to go deeper? This follow-up call focuses on using PostHog to achieve your specific business goals and KPIs. Bring your team — the more, the merrier!
Final check-in - We'll do one last review to make sure everything is working smoothly, share additional resources, and point you to ongoing support options.
Timeline
Here's a typical timeline, though we're flexible and can adjust to your schedule:
Week 1: Initial account review and outreach
Weeks 2-3: Ideally, a first call scheduled, or we can continue working async!
Week 5: We check in to make sure you're all set before your PostHog bill comes up
Weeks 4-6: Second call (if requested), and space for unanswered questions
Week 8: Onboarding graduation!
Your success is our success
Here's the thing: most teams struggle with knowing what to track, not just how to track it. The first call gets you set up correctly. The second call is where the magic happens. We'll help you decide on the metrics that actually drive your business decisions and create a roadmap for using PostHog strategically.
This is where customers see the biggest ROI, and it's completely free. We highly encourage you to take advantage of it.
First and foremost, we’re account-agnostic, which makes us different from other GTM teams. This means that we don’t have our book of customers, and our focus is on being fast, responsive, and available to a huge number of customers. This is precisely why we use, e.g., a Team Link for customers to book the call - they can choose a person closest to their time zone, and both the experience and value provided remain the same across the team.
Day-to-day, we collaborate closely with Account Executives and Account Managers, especially when a customer would benefit from a dedicated PostHog human, and the Support team on solving issues.
Onboarding sessions are a mine of information about our users and their needs, which makes us a fantastic liaison for the Product teams. We share product feedback whenever it surfaces.
Since the Onboarding team is still a relatively new addition to a wider GTM team, we're a highly collaborative and creative bunch who are not afraid to try new ideas, iterate, and build the foundation for the future Onboarding endeavors.
What does this team do?
The core job of an Onboarding Specialist (OS) is to ensure a successful start of the user journey with PostHog. That means making sure that our customers get the most value out of using PostHog, they are aware of best practices, their setup is solid, and they don’t pay for something they don’t need. Ultimately, we serve as the customer's sparring partner in achieving their goals, so we need to understand their needs, their business, and where they’re coming from.
The north star metric for the Onboarding team is 3-month logo retention at 90% from the first $100+ forecasted bill, which can be tracked in the onboarding team retention dashboard.
We also care about net dollar retention for this segment, but we treat it as an auxiliary metric.
Which customers get onboarding?
The segment consists of customers who self-serve PostHog and generate a forecasted bill of over $500. In practice, because billing is metered and in arrears, and we don't know what people will pay when they sign up (or when they first exceed a $100 forecast), so _most_ accounts > $500 forecast are routed to us. We also handle a couple of other segments:
YC program participants at the roll-off of the plan.
Startup customers rolling off, who have generated a first bill in the $500-$1500 range.
Startup plan customers with high credit usage (> ~$1500).
Hype startups we want to work with (despite being below $ thresholds), or longer-standing customers that have paid in this range and need billing or setup assistance.
Which customers are out of scope
Since we primarily focus on customers who've signed up and have a forecasted bill, in most circumstances, we're not the right choice to talk to customers who've:
Not signed up/generated a bill, but have contacted sales.
Are early-stage startups on the startup plan with no billing/low credit usage (<$500/mo).
Customers who paid over 3 bills
Merch store consultation
Customers who normally fall outside our scope still have a chance to get help! They can buy an Onboarding consultation via our merch store.
After making the purchase, the customer gets a link to book a meeting, and they can contact our Billing team if they can't find an appropriate time slot. The billing team handles issuing credits/refunds accordingly. However, since it's a paid service, we should prioritize these and try to make space in our calendars, if possible.
A few things to keep in mind:
The booking link has no expiry, so there's no need to follow up with the customer if they haven't booked the call instantly - they can do so at the most convenient time.
If someone did book the meeting but didn't show up at a consultation, issue them credits for the missed meeting, and follow up with the customer to offer a meeting at another time.
If they had a call with us and then need more help, we'll offset the onboarding call cost against a professional services package.
If the customer has a CSM, AE, or AM assigned, their dedicated PostHog human should run the call.
If the customer already belongs to the Onboarding bucket, prioritize meeting with them, and add credits to their account, as they would get the same service anyway.
Internally, when someone purchases a call, we get notified in our Slack channel. Check who completed the purchase, look them up in Vitally for more context, and check whether they booked a call. Change the status in Vitally to Paid Call purchased for tracking purposes, and add a note if needed.
Our role is pretty hybrid and lives at the intersection of other teams. As much as we love solving our own problems, escalations may happen. Here’s a brief guide on how to handle them:
Do your homework – check our docs, ask PostHog AI, and search Slack and PostHog Support for similar questions. You can also check GitHub to see whether we have a bug or enhancement logged. If that doesn’t bring you closer to a solution, ask in the team Slack channel.
Don’t be afraid to admit when you don’t know something. Note it down and circle back once you’ve found the answer! Honesty goes a long way.
Consider sharing a Loom recording in your reply to the user – It might be more efficient than a written instruction.
If the issue requires in-depth troubleshooting, you can direct the user to create a ticket from the app, or you can do so on their behalf. Just remember to let them know before you do, so they’re not surprised when they see it in the UI!
Before escalating the issue to Support, gather as much information and context as possible so your handover is informative and thorough. You can also share a recording of the call with the team, highlighting the relevant timestamp.
Ideally, after the meeting with the user, they should know how to seek further help. That includes using PostHog AI, consulting the docs, and reaching out to our Support team.
How to deepen your knowledge
Go through Sales docs, especially Contract Rules, Creating Contracts, and others from the SalesOps section. There will be some related conversations that you'll need to handle yourself, so come prepared.
Add yourself to some AEs' Slack channels to see what kinds of questions are being asked and how they’re solved.
The onboarding team operates a high volume, high velocity sales pipeline with all pay-as-you-go (or YC) accounts that are forecasted to spend > $500 and are not otherwise engaged by Sales/CSM. As such, Onboarding is a linear flow moving from initial outreach to confirming the product is configured properly, ending with customers who are happy paying multiple bills. We aim to keep engagements to ~8 weeks, or 2 full billing periods, but in practice, there is some spillover depending on responsiveness.
Principles
Our onboarding program was created to offer necessary help, increase the value our customers get from PostHog, and assist them in achieving their business goals.
The program is guided by a few key principles:
Help with initial configuration and billing, offer advice on usage.
Assist customers with any technical questions they have around fitting PostHog into their stack.
Act as strategic partners in achieving business goals.
Adapt to varied levels of engagement while ensuring value for everyone.
Encourage time spent in PostHog, trying things out. Adoption can be fun!
Share best practices to leverage PostHog tailored to specific use cases.
Internal process
Vitaly views
Daily view (link)
Sort your view by the “Next Renewal Date” column to reach out to users in a timely manner. Since our role is focused on proactively providing users with value and setting them up for success, we’ve found it’s best to contact them ~14 days before their bill renews. This gives them enough time to see our email, schedule a call, and implement potential improvements in their setup.
Keep an eye on “Onboarding Pipeline,” which indicates whether the account is New or Onboarding has been initiated.
In the view, you have other useful columns like OS Priority, OS Last Messaged, forecasted MRR, or who’s assigned to the account. All these help in prioritizing your work.
Maintaining good hygiene and attention to detail is key here. Keep labels up to date and make sure not to miss accounts that were recently added to the segment—they might appear at the top of the list among accounts you’ve already worked through.
Remember to add a short summary from meetings in a Note, and if you need to follow up at some point, create a Task with a due date.
Kanban view (link)
A supplementary view that’s great for getting a general overview of progress.
Onboarding program - logic and sequence
There are two paths for customers to progress through the onboarding process: those who engage with us in some way, and those who show little or no engagement.
User engagement is tracked behind the scenes with the time stamp in Vitally, thanks to which we can query relevant data.
For day-to-day operations, these are the statuses we use to track users in the Onboarding Pipeline property:
1. New Account - Where new customers land when they enter the Onboarding Lead segment. During the outreach, we audit the account and share observations on current usage and optimization tips. We point out any configuration issues affecting their bill or ability to use the product properly. Our main objective is oriented towards trimming unnecessary spending, and communicating our position that we are the cheapest for every product. This step can also involve refunding/adjusting bills for misconfigurations, per our policy.
2. Onboarding Initiated - Assigned as soon as we send out the initial outreach email.
3. Onboarded - The onboarding program has been completed. The status chances automatically after the Graduation email is sent, or we change it manually for some reason.
Sales Handoff - Assigned to customers that we hand over to sales. This can happen at any stage throughout the process.
Paid call purchased - Assigned when someone buys our consultation via the merch store. The status is applied automatically via this Workflow.
The last two are not numbered, as they happen "outside" of the regular pipeline.
Note: You may need to add this property to your views in Vitally. It's found under Custom Traits.
For higher-spend accounts ($500+), we have Check-inOnboarding Status property that's triggered between 15-21 day in the Onboarding Journey. It serves us as a visual helper and reminder to circle back to the account, see if our advice was followed, record a Loom video, or share some extra resources. It's a great opportunity to re-engage customers and show them some other PostHog's capabilities that they may not know about.
The complete Onboarding Journey looks as follows:
| Weeks | Actions | | -------- | -------- | | Week 1 | First outreach to a New Account| | Week 2 | | | Week 3 | Extra check-in for $500+ accounts| | Week 4 | | | Week 5 | 2nd outreach (automated) - all accounts| | Week 6 | | | Week 7 | | | Week 8 | Graduation (automated) - all accounts|
The last two stages of the Onboarding Journey are automated with Vitally playbooks. Second outreach prompts users to surface unanswered questions and book a session with us, and the Graduation email is a nice way to conclude the journey and point out other avenues where users can get help. It's also where we ask for feedback about our Onboarding.
Email link tracking
Every link in the automated onboarding emails carries UTM parameters, so we can measure what customers actually click and report on notebooks created and prompts clicked rather than calls booked. The scheme is utm_source=vitally, utm_medium=email, utm_campaign=onb_e1 through onb_e4 (one value per email in the sequence), and utm_content naming the individual link:
The main view is the Onboarding email link tracking dashboard (link): per-email sections, per-link breakdowns, and all-time totals.
App links (the audit prompts, PostHog AI) sit behind a login: a logged-out click bounces to the sign-in page and its UTM properties are lost. The executive Onboarding email link clicks (E1-E4) insight (link) therefore matches the campaign tag inside the page URL, which survives the redirect in double-encoded form, so every click counts whether or not the customer was logged in. A separate insight on the dashboard isolates the login-wall bounces.
Calendly clicks never reach PostHog. Calendly stores the UTMs on each booking instead, so filter the Calendly Meetings page by utm_campaign to attribute booked calls to emails.
The YouTube link in E3 is deliberately untracked (YouTube ignores UTM parameters, and we cannot read its analytics).
The live templates and their sending playbooks (the templates are the canonical copies of the audit prompts and the full tracked URLs; we avoid pasting the tracked URLs here so stray clicks from this page do not pollute the data):
E1: template, playbook
E2: template, playbook
E3: template, playbook
Account analysis for outreach and meetings
Take a look at the Metabase primer and follow the tips included there.
[[Onboarding Pipeline] 1. New Non-startup Account (Onboarding lead first payment due](https://posthog.vitally-eu.io/settings/playbooks/533794c1-e9dc-479c-925c-7e0487648661)
[[Onboarding Pipeline] 1. New Startup Account (Startup lead for onboarding specialist)](https://posthog.vitally-eu.io/settings/playbooks/8fd68f0d-0b86-4b16-876f-fb8097e7bf0d)
Setting timestamps for each stage
[[Onboarding Pipeline] 2. Onboarding Initiated -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/c58150a0-a6f5-43bb-a790-59fbdec6d262)
[[Onboarding Pipeline] 3. Engaged (Email/Call) -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/b082beb9-227d-45fc-a73a-5c694688e65a)
[[Onboarding Pipeline] 4. (Nurture) -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/d1ff7ceb-8b9f-418c-a354-be8e2325c472)
[[Onboarding Pipeline] 6a. Onboarded — No Engagement -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/6deca76c-7a96-4675-bfdc-b9ab7ec6f7e4)
[[Onboarding Pipeline] 6b. Onboarded — Engaged -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/1e95eb5b-a2ca-4f47-957f-acc193776a34)
[[Onboarding Pipeline] 6c. Sales Handoff -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/df072651-3f6f-409b-892d-74cdf099a77c)
[[Onboarding Pipeline] 6d. Churned -> set timestamp](https://posthog.vitally-eu.io/settings/playbooks/65d770f0-fe2f-48e9-9295-0cf632974c94)
Automations
[[Pipeline Automation — Stage 1 -> 2] Has been contacted by Onboarding Specialist](https://posthog.vitally-eu.io/settings/playbooks/754f037e-892b-435a-a189-9f3da9b922fa) - Accounts we reach out to — any with a convo started by Magda or Dan get set to 2. Onboarding Initiated
[[Pipeline Automation — Stage 2 - 3] Move status from Onboarding Initiated to Call booked](https://posthog.vitally-eu.io/settings/playbooks/bbce230d-ca70-40ef-a44d-c5d338fe80f7)
[[Pipeline Automation — Stage X - 5] Update status to Awaiting Final Outreach](https://posthog.vitally-eu.io/settings/playbooks/aa1d8ac8-a602-4906-8508-cd29e95abe60) - This status is assigned ~10 days before the next renewal date (after having gone through any other step in the pipeline)
Going forward, we only have one main segment: Onboarding Lead. We'll be retiring Onboarding - engaged as soon as we have worked through all the legacy accounts.
We also use the Onboarding Lead 100-500MRR auxiliary segment to provide us with more information about the account and help us prioritize the work.
Onboarding Completed segment corresponds with 3.Onboarded trait and it serves as a visual indicator for other teams that the Onboarding has been completed.
Alerts and revenue tracking
We occasionally shift our attention to help customers who may need more urgent assistance. For these, we have a few types of alerts (tasks) in Vitally, where Magda is a failsafe if the account doesn't have an assigned OS.
Failed payments alert - This is more of a safety net, as users are informed when it happens. It's a good moment to reach out and offer help in figuring out their volume/billing.
Upcoming large invoice alert - It lets us prioritize the customer to touch base and make sure the bill doesn't come as a surprise.
Event/Feature Flag/Replay/Error tracking spike indicator for OS - unusually high usage that may point to a misconfiguration and require our assistance.
To help our Revenue team get the forecasting right, we now have a Payment Risk Assessment field in the Vitally dashboard, where we can manually mark when we see that the customer is unlikely to pay their invoice.
Specific cases
How to stop automation
There might be some specific situations where you're actively engaged with the customer, and you don't want the email automation to fire off (e.g., the second outreach). You can easily spot when the email automation is scheduled by checking "Onboarding Pipeline Stage Times" widget in the Vitally dashboard.
To stop the automation, you can flip the account to the Onboarding Completed status. This change will block the second outreach, but will still fire the graduation email.
Failed payments
We may get a Failed Payment alert on a customer we still haven't engaged with. In this case, since we're unsure whether the customer is going to stay with us, we don't have to do a deep account analysis. It's enough to remind them to settle the invoice, offer help, and briefly point out obvious spikes and main drivers of the bill.
It's enough to reach out just once, as the finance team monitors the payments and handles the account deactivation.
Currently, we exclude some subject line keywords, like "payment", "outstanding", and "fail" in the "Set onboarding initiated" playbook in order to avoid the status change from New Account to Onboarding initiated. In other words, when you reach out regarding a failed payment, the account should stay as New Account and resurface in Vitally's queue before the next renewal, if the customer settles the payment. When that happens, do our regular outreach with a deep account analysis and enroll them in the program.
If you see that a customer is spending more than $1,000 monthly, evaluate whether their usage looks stable and legitimate, and make sure that MRR doesn't come from an unwanted event spike or misconfiguration issue.
If that's the case, you can pass the account to Sales even without speaking with the customer first, as long as you’ve confirmed that the high spend is intentional. The goal is to react quickly to healthy, high-spend accounts—but avoid passing through problematic ones.
Before you hand off, also consider month-over-month growth. A flat $1.2k account is a very different lead from a $1k account that doubled organically last month. Growth rate matters to the Sales person deciding whether to prioritise the lead, so call it out. Here is a useful doc on evaluating growth potential.
Be courteous and leave a note in Vitally with context on the account before handing off. Include what you spotted in Metabase, any relevant billing patterns, and your read on why the spend is legitimate. The Sales person receiving the lead should be able to pick it up without having to dig.
Handover during onboarding - engaged customers
While talking with customers or analyzing the account, do some discovery to understand the reason behind their high spend and assess whether there's potential for stable spend or usage moving forward. If they’re happy continuing with PostHog, you can mention our discounted pre-paid plan, which helps them save ~20%. However, if they prefer paying monthly, they are more than welcome to do so!
We typically hand the account over to Sales when a customer is interested in the annual plan, requires additional contractual or legal support, or we notice potential ourselves.
Make sure to include in Vitally our point of contact, i.e., the person you've been in touch with, while handing over the account to Sales.
Unresponsive customers during onboarding
Historically, there's still a good chance that they'll talk with Sales after passing them on! AEs have been successful in reaching out and securing long-term commitments. You don't have to wait for the customer to complete the onboarding program - you can pass them earlier on, if they didn't respond to our initial message, and if you see that the account matches criteria and the handover makes sense.
If there are any pending config issues that you raised before but the customer didn't respond to, just provide relevant context to the fellow AE/TAM in Vitally - sometimes it might be a good conversation starter!
Lead creation
If you come across an account with growth potential or stable high-level spend (especially if that high spend has occurred over the past two - three months and there are no pending issues to resolve), that might benefit from an annual plan or general sales engagement, you can add them to the Onboarding referral segment in Vitally. Within a few minutes, this will automatically create a Salesforce lead and assign it using round-robin logic.
After a few minutes, your lead will appear in the #sales-leads Slack channel, tagged as "Onboarding referral". As a good practice, leave a note in Vitally for the Account Executive with some relevant context on the customer. You can also ping an assigned AE on Slack, if any further follow up is needed.
The automation flips the Vitally's Onboarding pipeline trait to Sales Handoff so that we have not only data on the leads passed, but also a visual indication.
Proactively looking out for opportunities
If you see an account with a promising, positive growth trajectory, but they may achieve the $ threshold after finishing the onboarding program, set a task in Vitally assigned to yourself in order to circle back after some time and see if they're eligible for being passed on to Sales.
If you reach out to a high spender (+$1000), add a Vitally task to see if the first bill came through. If it did, we could pass them on to Sales faster, without having to circle back to the account before the second bill comes up. We currently have a playbook running that automates task creation.
Confusion about previous Sales engagement
Some pointers on what to pay attention to in Vitally while checking for prior Sales engagement:
Pin temporary owner trait in your Vitally sidebar - the trait is set when a Salesforce lead task exists (otherwise it's "null")
Segments (e.g. TAM/CSM Candidate, $20k MRR, Active Trial, Active Self-serve Trial, Annual Plan, etc.)
Slack channel (following the naming convention #posthog-[company name])
Key Roles (is someone assigned to the account?)
Trial Status widget in the Onboarding dashboard
Active Conversations and Meetings (any trace of a booked call or an ongoing conversation)
Notes
If Sales are already engaged, there's no need to create an Onboarding Referral.
If the account has engaged with the Sales team at some point and it's unclear where the conversation stands, ping your fellow AE to make sure you’re not overlapping efforts.
If it’s clear there’s a duplication issue and we shouldn’t be involved, ping Mine to double-check the logic.
What to do when Sales is involved?
If an account is in the Onboarding Lead segment, but there are recent Active Conversations in Vitally from a TAE/TAM (or scheduled meetings), and TAE/TAM confirms they are already actively engaged with the account, add a Vitally note saying: “Removing from Onboarding Lead segment — Sales already engaged.” Then remove the account from the segment and delete both the pipeline trait and the timestamp.
Outside of our generous pay and equity, we also offer several other exceptional benefits to our team. We want to provide exceptional benefits when it comes to things that help you do your job better, and in line with the market for well-funded startups for everything else.
If you have any ideas for how we can improve our benefits offering, then please let us know!
As we are fully remote, we provide all equipment you need to have an ergonomic setup at home to be as productive as possible. We provide all team members with a company card for this purpose.
If you ever need change of scenery, co-working or working from a cafe or WeWork All Access are available, just follow our expense policy e.g. we trust you to do the right thing.
Please message Kendal to get added to our company WeWork account.
Meeting up
We do regular team offsites - recent trips have included Mexico, Aruba, Iceland, and Portugal! Small Teams also have their own offsites at least once a year.
We also encourage people and teams to meet up in person _in addition_ to the offsites. If you are working on a problem that is better worked on in person, then you should do this. Our expense policy is about trusting you to make the best decisions. Travelling can be distracting so we expect you to exercise judgement when doing this.
Free merch
People like our merch. If you want more, here's how to get it!
As always, we expect you to use this with restraint and with your own good judgement. The merch store should not become your sole source of clothing for your wardrobe, nor where you go any time a friend has a birthday. But sure, go ahead and buy your mom (or yourself) a hat or a hoodie!
Please note that any free merch received outside of your birthday kit, work anniversary kit, or new hire kit is considered a taxable benefit in most jurisdictions and may be subject to tax. If you have questions about how this applies to you, we recommend checking with your local tax advisor. We will send the details of any free merch you have claimed to payroll once a year (usually in December) and any tax due will be deducted from that payroll (please note this is jurisdiction dependent, and also depends on your employment type at PostHog).
Support open-source projects
Everyone gets a monthly open-source sponsorship budget to spend as they see fit to support open source projects of their choice.
We'll be your first investor
We'll be your first investor and biggest cheerleader, if you spend two years at PostHog and leave to start a new company. We're looking for entrepreneurs and a strong Why not now?!
With everyone being distributed across the world, we do our best to provide the same benefits to everyone, but they vary slightly by country depending on the services that are available and local regulations.
US
401k contribution
In the US, our 401k plan is managed by Vestwell and we match up to 4%.
Health care
In the US, you'll enroll in benefits through BambooHR and manage your coverage through UnitedHealthcare for medical and Guardian for dental and vision. PostHog pays 100% of the premium of the Platinum plan for team members, and 75% for dependents.
We offer the option to opt in to a Flexible Savings Account (FSA), which is a tax-advantaged account that allows you to contribute pre-tax dollars up to $3,400 per year to be used on out-of-pocket medical expenses. The FSA is a "use it or lose it" benefit, so any dollars that are not spent by the end of the year return to the company.
There is also the option to choose a lower tier, high deductible health plan (HDHP), which will qualify you for a Health Savings Account (HSA) that has further tax benefits beyond what the FSA provides. At the end of the year, any unused money rolls over and the contribution limit resets.
UK
Pension
In the UK, we use Royal London. Team members contribute 5% and PostHog contributes 4%, but you can opt out if you like. You can also transfer out of the plan as frequently as you want, in case you would rather manage your own private pension. If you wish to increase your own pension contributions, you can download the Parallel Employee benefits app and submit the request.
Private health insurance
In the UK, we use Aviva for private healthcare (£100 excess per policy year) and Medicash as our cash plan for dental and vision. Children are included for free. Both of these are taxable benefits which will affect your Personal Allowance each tax year, and you can opt out at any time with 1 month notice.
Nursery
In the UK, we offer the workplace nursery scheme. This enables you to pay for your children's nursery using your pre-tax salary, saving you up to 45% in nursery fees.
If you are interested in this, first check with your nursery that they are part of the scheme, then message Kendal to get this set up.
In countries where you are employed under Deel's EOR service, we make pension contributions in line with legal requirements.
Unfortunately, we are currently legally unable to provide pensions to contractors.
Private health insurance
We offer private health insurance in countries where it is considered market to do so. For Ireland, Spain, Netherlands, Portugal & Canada the health insurer varies depending on market and offering via the Deel platform and can be subject to change. Please login to Deel to find the policy relevant to your market or reach out to the Ops team if you have any questions.
BookHog is PostHog's official book club. We meet once a month to discuss a particular book. Radical.
Michael is the organizer and picks the next book to read through a pseudo-democratic process. Previous themes have included 'unorthodox manoeuvres', 'short stories', and 'super mainstream beach reads'. All discussion and voting for the next book to read happens in the #books-and-films Slack channel. Previous books we have read:
The Panama Papers
Exhalation by Ted Chiang
The Spy and the Traitor
Pride: The Story of the LGBTQ Equality Movement
Soon I Will Be Invincible
Six Easy Pieces by Richard Feynman
Stories of Your Life and Others
The Order of Time
His Masters Voice
When Breath Becomes Air
Arnold: The Education of a Bodybuilder
A Billion Years: My Escape From a Life in the Highest Ranks of Scientology
Dune
Zen and the Art of Motorcycle Maintenance
Team of Rivals
The Richest Man in Babylon
Surely You're Joking, Mr. Feynman!
A Brief History of Intelligence
Meditations by Marcus Aurelius
The Chemistry of Death
Countdown to Zero Day
Drive Your Plow Over the Bones of the Dead
No Rules Rules
Books can be purchased using your monthly User Limit.
The best way to progress your career at PostHog is to understand your team’s _and_ PostHog's objectives, then:
Ship fast towards these
Give and receive direct feedback to help yourself and others do the same
Fix problems when you see them - early objectives are often wrong
You are what you do. Getting promoted in a company that is struggling, is very hard. However, if the company is succeeding, it'll be easy to justify, _and_ to afford, pay rises where people are performing very well.
Give a shit about your work, your team, and our users
These three are the inputs that lead to the output of career progression. If you focus only on yourself, no value is provided and you won't progress. If you only focus on your team, you won't build the right thing for our users. Having a consistently caring attitude will in the long term lead to progression - if you do this, PostHog will progress you.
When we IPO, you will literally walk into any job anywhere
While being able to talk about all the cool stuff you built will help you in your future career, being an early employee that took us from very early to public is a huge and an _exceptionally_ rare career achievement. That's how you leap multiple positions into an exec role, or whatever else you want to do.
Ways we help you progress
Hire and maintain a team of excellent people, all working transparently, that you can learn from
We are disciplined with maintaining a high bar. And since everyone works so transparently, you can learn from watching what everyone is doing - from how board meetings work, to why we picked a company strategy, down to why our frontend is the way it is.
Give you loads of autonomy
We don't limit you, and will push for much more than you may think is possible. It will feel hard, but rewarding. You will get used to not asking for approval.
Give you lots of interesting problems to work on
PostHog has a wide variety of challenges - from data, to entire new products and features, to design and UX tradeoffs. On the go-to-market side, we're wildly different - you'll learn about self serve, bottom up adoption, handling a community, and how giving things away for free leads to us making money.
We have small teams - we can move people around as we grow to provide variety and to let people switch up their focus if things get stale.
Lightweight management
You have someone to talk to, but without being micromanaged. Their priority is to support you, and we give them resources to make them a better manager. They will also do a regular career check-in with you as part of your 1-1s to ensure you're on the right track.
Build a huge open source portfolio
Better than a fancy title - you can show future employers or investors what you built and the problems you solved.
Your team around you see your everyday work more than a manager - get direct feedback from them
A checklist of things / a formal career progression framework
This is self-interested by its nature, so creates the wrong incentives. The benefits of frameworks only start to outweigh their drawbacks when you need to start coordinating 100s of people.
Fancy titles
We don't have a wide range of titles - we want people to be as equal as possible in order to enable autonomy versus micromanagement. Your open source work speaks for itself.
Getting a manager to progress you
This gives too much power to managers. No one else can really do this for you - your motivation to progress has to be intrinsic to be sustainable.
We have a set system for compensation as part of being transparent.
You can use our compensation calculator below to see what your compensation might look like when you're joining PostHog, and to see how it might develop over time:
We think the fastest possible shipping comes from a leaner and stronger team. We pay generously, so you'll work with the best people in the world.
Important:
If we are missing your country, it simply means we've not hired there before so we'd need to put together some data in advance of hiring you.
If you're considering applying to PostHog and the salary is the only blocker, then something is wrong with our model (as we aim to pay generously) for your circumstances in most cases. Please tell us as part of the hiring process and we will review things.
Level
Level does not correlate with increased importance, but with impact within PostHog. Your level is _not_ a title – we don't believe in having a huge hierarchy of roles, as everyone needs to feel like the owner of the company that they are.
Very broadly, we think of the various levels as:
Junior: contributes to small or function-specific projects (note, we rarely hire people at this level)
Intermediate: owns projects with small to medium impact
Senior: owns and drives high-impact projects or a whole product, decides what needs to happen and does everything necessary to get that done
Staff: same as senior, but also _consistently_ owns and drives large projects that impact the entire company, not just their product, team or even function.
Director: someone who is operating at the highest levels, usually a member of the Blitzscale team and usually a manager of managers
Principal (same level as Director): same as Staff, but with extremely rare skills or operating at a very high level.
It's important to note that this is not a checklist. These descriptions are indicative, and there will always be a degree of judgement by the to decide which level you're at, also based on other people within PostHog.
Step
Within each level, we believe there's a place to have incremental steps to allow for more flexibility. We define these as follows:
Learning: Starting to match expectations.
Established: Matching expectations.
Thriving: Exceeding expectations.
Expert: Exceeding expectations consistently.
With exception of team members at the very beginning of their career or where it is their first time in this type of role, we hire into the Established step by default. This will give everyone the opportunity to be set up for success and leave enough room for salary increases, without the need to move up in seniority.
In line with our compensation philosophy, the benchmark for each role we are hiring for is based on the market rate in San Francisco.
We use Pave as our main source for our salary benchmark and build a target range based on that data.
Because the engineering market is very competitive, and we think there is a 10x difference between an average and a top engineer, we pay near the top of market, which we define as being the 90th percentile, at the time of review. For other roles we still try to pay towards the top of market, which we define as 50th percentile + 20%.
Location factor
Most of our location factors are based on GitLab's location factors. Location factors are based on _cost of market_, not cost of living. This means that we look at how much it typically costs to hire a person in that role in that location, not how much it costs to live there. This is why, for example, our location factor for San Francisco is the highest, even though there are several other places that are more expensive to live.
We set a floor of 0.8 in the US, and 0.6 everywhere else, to avoid creating huge disparities in pay if someone happens to live in an exceptionally low cost of living country/state.
GitLab uses a combination of data from Economic Research Institute (ERI), Numbeo, Comptryx, Radford, Robert Half, and Dice to calculate what a fair market rate is for each location. Read more on how GitLab calculates this location factor.
The location factor takes your local exchange rate into account, so we don't have to keep updating exchange rates when they fluctuate. The floor also helps mitigate this. You will always be paid in your local currency, unless there is a very good reason not to (e.g. it is normal in your country to transact in USD).
Executive compensation
For hiring into executive roles, we use a separate database of compensation benchmarks rather than this calculator. The terms of access to this (paid) database means that we're not able to share it publicly.
The benchmark data is all we use for executives. As a rule, executives are paid above average but not top of market.
The reason for less sophistication here is that we have very few executives, and only one for each role by definition. It's irrational to create a system so that, within a given benchmark, people are paid equally when there is just one person to consider!
Pay reviews
We review pay proactively 2-3 times a year, and everybody on the team is reviewed at every pay review. Any change to your pay takes effect from the 1st of the month following your review, and isn't backdated. You do not need to do anything - our goal is to keep your compensation at an appropriate level without you having to ask.
As we do these much more frequently than regular companies, team members should definitely not expect these to result in a change to their Step or Level each time - mostly they will stay the same. Additionally, team members will find that their Step, or place within a Step's range, will change more frequently than their Level.
Finally, we may change pay without editing Step or Level if the market rates for the underlying benchmark have gone up. When we review pay we don't take inflation into account, as this is already accounted for by market data. Thus, you won't get a yearly "inflation raise" as is typical in many localities, though our review process and benchmarking ensures your salary will remain in-line with the market.
We do also regularly increase benchmark levels when we are making a deliberate attempt to raise the bar in terms of hiring. This means that, when a benchmark is increased, it's not unusual for your level and step to come down. You will still get a pay increase, just not always at the same % increase as if the benchmark alone went up.
How the review process works
To make sure everyone has an equal chance at getting a pay rise, we do not factor in how frequently someone requests one. When increasing pay we only look at our calculator and performance. This helps us to be as inclusive as possible, as underrepresented groups are statistically less likely to request a pay rise.
We want to increase pay as frequently as we can in a proactive way, rather than putting the onus on the team member to negotiate every time. We don't make any changes outside of these reviews - if you change role for example, any changes will usually happen at the next closest review.
Any increases will be communicated by the relevant Blitzscale team member, as compensation is not a manager's responsibility at PostHog. If you need to talk to someone about your compensation or how the calculator works, you should ask the relevant member of the exec team in the first instance.
You will only hear from them if there has been a change in your pay, not if it is staying the same.
If you recently accepted an offer at PostHog and the benchmark changes between you accepting and joining PostHog, your pay will be re-assessed during the next pay review. Often this just means adjusting benchmark, step, and level - it is unlikely that your actual pay will go up.
Relocating
If you're planning on relocating, your salary may be adjusted (up or down) to your new location. This will be done at the next compensation review. If this represents an increase in pay, _we need to approve this change in advance_ - we cannot guarantee it is always possible, as our budgets may not allow it.
If you are nomading, we will set your location factor for the place that you are spending the most time in over the next 6 months. Our frequent compensation reviews mean that we can make adjustments reasonably frequently, but again any increase needs approval in advance.
Please note that there are a few countries that we don't employ people in.
Equity
It’s important to us that all PostHog employees can feel invested in the company’s success. Every one of us plays a critical role in the business and deserves a share in the company's success as we grow. When employees perform well, they contribute to the business doing well, and therefore should share a part of the increased financial value of the business.
As part of your compensation, you will receive share options in the company. We do not have a strict calculator here, but broadly you receive equity based on your role, level and location. Our general philosophy here is average equity, with extremely employee-friendly terms and options for liquidity through secondary.
Whilst the terms of options for _any company_ could vary if we were ever acquired, we have set them up with the following key terms which we believe are industry-leading in their friendliness to employees:
Standard 4-year vesting with a 1-year cliff
10 years to exercise your options in the event that you leave PostHog
Double trigger acceleration, which means if you are let go or forced to leave due to the company being acquired, you receive all of your options at that time
Vesting starts from your start date (not after a "probation period" or similar)
It can take time to approve options, as it requires a board meeting and company valuation. We can clarify the likely time frame at the time we're hiring you. Vesting will always start from when you joined PostHog, not from when you receive your option agreement. While we can commit to a particular number, we cannot commit to a particular strike price when offering share options, as the valuations are done by a third party and can vary depending on where we are in our funding cycle.
Every employee will be eligible for equity refreshes each year you are working at PostHog. These grants are between 18%-25% of the value of a new grant for your current role. The percentage is based on your performance and can vary year by year.
These equity refreshes will be decided at our pay review cycles, and are communicated by the relevant #team-blitzscale member at that time. Grants are approved quarterly by the board, though vesting is back-dated begins on the actual anniversary date. You'll be made aware of your grant being approved when you get an email from Carta regarding the grant. These refresher grants will be on the same terms as your original grant with a 12 month cliff, they will likely be subject to a different strike price due to changes in valuations.
Funding rounds disrupt when we are able to issue new grants, so approvals may be delayed if we are actively fundraising.
Probation period
We are fully committed to ensuring that you are set up for success, but also understand that it may take some time to determine whether or not there is a long term fit between you and PostHog.
Subject to certain exceptions for sales roles and German employees mentioned below, the first 3 months of your employment with PostHog is a probation period. During this time, you can choose to end your contract with 1 week's notice. If we choose to end your contract, PostHog will pay you 4 weeks' base salary pay, but usually ask you to finish on the same day.
People in sales roles, such as Account Executives, have a 6 month probation period - this is to account for the fact that it can be difficult to establish whether or not someone is able to close contracts within their first 3 months, given sales cycles.
German employees also have a 6 month probation period - this is to align with market standard best practices and expectations for hiring in Germany, as it can be operationally difficult to part ways with German employees so we ask for as much information as possible to establish whether the hire is a good, mutual, long-term fit. During probation, either PostHog or the German employee may choose to end the employment contract with 1 month notice.
Your manager is responsible for monitoring and specifically reviewing your performance throughout this initial period. If under-performance is a concern, or if there is any hesitation regarding the future at PostHog, this should be discussed immediately with you and your manager.
At the end of your probation period, you won’t usually receive formal confirmation that you’ve passed probation, the default is no communication. By that point, you should already have a clear understanding of your performance and progress through your 30/60/90-day check-ins with your manager.
Severance
At PostHog, average performance gets a generous severance.
If PostHog decides to end your contract after the first 3 months (6 months for sales roles), we will offer you a total of 4 months of base salary (which includes any time we need to give you under the law). To receive these benefits, we will ask that you sign a standard post-termination certificate or release. For our German teammates who have completed their 6 month probation, we will follow the local legal requirements for notice and severance, in line with what is typical in Germany. In some cases, we might ask you to stop working right away and pay you instead of having you work through your notice period, or set up a "garden leave" depending on what is most appropriate for your location and contract. If the decision to leave is yours, then we generally just require 1 month of notice, though this can vary depending on your country's laws or the specifics of your contract.
If you are in a role with a commission/bonus component, you will be paid the amount you are owed as of your last day at PostHog.
We have structured notice in this way as we believe it is in neither PostHog's nor your interest to lock you into a role that is no longer right for you due to financial considerations. This extended notice period only applies in the case of under-performance or a change in business needs - if your contract is terminated due to gross misconduct then you may be dismissed without notice. If this policy conflicts with the requirements of your local jurisdiction, then those local laws will take priority.
Contracts
We currently operate our employment contracts in the three geographic regions where we have business entities:
United States of America
United Kingdom
Germany
This means, if you live in one of those countries, you will be directly employed by PostHog or the applicable subsidiary as an employee in one of our entities.
If you live outside the US, the UK or Germany, we use Deel as our international employer of record. This means you are technically employed by Deel on our behalf. This doesn't affect your rights or benefits.
In some cases, you may be an independent contractor, in which case you will invoice us monthly via Deel. Deel offers pretty much all countries and currencies. As a contractor, you will be responsible for your own taxes.
Payroll
In the UK and for international contractors, we run payroll monthly, on or before the last working day of the month.
In the US, we run payroll twice a month, on the 15th and on the last day of the month.
Deel runs payroll on the last working day of the month.
Sharing and receiving feedback openly is _really_ important to us at PostHog. Part of creating a highly autonomous culture where people feel empowered is maintaining the most transparent and open flow of information that we can.
This includes giving feedback to each other, so we know we are working on the right things, in the right way. While giving feedback to a team member can feel awkward, especially if it is not positive or if you are talking to someone with more experience than you, we believe that it is an important part of not letting others fail.
'Open and honest' doesn't mean 'being an asshole' – we expect feedback to be direct, but shared with good intentions and in the spirit of genuinely helping that person and PostHog as a whole to improve. Please make sure your feedback is constructive and based on observations, not _emotions_. If possible, share examples to help the feedback receiver understand the context of the feedback.
Keeper tests are not a substitute for direct feedback
Keeper tests are not designed to replace direct feedback, and the responses are not made visible to the person being assessed in the ops platform. We've always wanted people to give direct feedback to each other, across teams and in all directions – keeper tests do not replace the art and process of giving continual, direct, and 360 feedback.
The keeper test forms exist for a few specific reasons:
To surface feedback to the relevant Blitzscale team member so they can help where necessary.
To keep a record of feedback given, in case the person moves team or the team lead changes.
We also want people to fill these forms out totally unfiltered, rather than through the lens of "will this person see this feedback". If you have feedback for someone, give it to them directly – don't rely on the keeper test to do it for you.
Full team feedback sessions
We run full team 360-degree feedback session as part of every offsite. Some teams will do them during their own small team offsite, while others choose to do them as part of the whole company offsite. The session gives everyone the opportunity to give and receive feedback to everyone else. If your team works closely with another or is very small, you may combine with another team (but keep attendees to <8 if you can).
Ground rules
Everybody participates! You should have a think and write up your notes in advance – don't try and wing it on the day.
Preparation includes reading our handbook about how to be a good feedback giver and receiver.
As a guide the mix of positive and constructive feedback will vary. You should spend more time talking over the constructive even if you have a long list of positive things to share – this is an opportunity to help each other to grow.
Everyone is expected to give feedback to everyone, even if they don’t work together directly. It may be very short feedback, which is ok!
That being said, avoid piling on and repeating feedback others have given unless you have a different perspective or can add more context. It is ok to say "+1 to what X said about Y" and move on. Do not spend 2 min repeating the same point that has already been made by someone else.
Everyone is responsible for noting down and actioning their own feedback (ie. the people team won't do this for you).
What is discussed is for the benefit of those present and does not need to be shared with others who were not present. It is ok to follow up with anyone on feedback you received or gave after the session.
Use a notebook, or worst case keep notes on your phone. You will be much less present if you use your laptop, so we generally discourage these.
How to give good feedback
We know that giving feedback can sometimes be difficult, so here are a few tips on how to give good feedback:
If something went wrong, focus on what has actually happened, not on whose fault it is. Assigning blame is not productive.
Be as specific as you can with your feedback. An example can be helpful to give the recipient context.
Sometimes a question can be more useful if you feel you lack the full context. For example 'I've noticed that you sometimes do X. Can you explain to me what your thought process is when you are doing that?'
If your feedback is about behavior, focus on the behavior itself and its impact on you, rather than attacking the person's character. For example 'When you do X, it makes me feel Y. Would you be willing to do Z instead?'
Remember that positive feedback is really important – we should reinforce and affirm the things we want that person to keep doing!
We expect everyone to support each other by giving lots of feedback – it's not ok to stay quiet if you have something constructive to share.
How to receive feedback well
If someone is making the effort to give you feedback, you should reciprocate by receiving that feedback well. Being a good feedback receiver means that people will be more inclined to give you feedback in the future, which will help you to grow!
Here are a few tips to help you do this:
Assume positive intent on the part of the feedback giver.
Try not to hear attack - listen for what is behind the words.
It can be useful to paraphrase the feedback to ensure you have understood it correctly, or ask questions to clarify.
You do not have to accept all feedback! However, it's probably worth taking time to reflect on it, rather than reacting in the moment. There is a difference between acknowledging feedback and disagreeing with it.
README sessions
At small team offsites we may also run README sessions in addition to 360 feedback sessions. Typically we find it useful to run these README sessions as early as possible during the offsite and before 360 feedback, as they are a great way to get to know your team.
README sessions are an opportunity for you to help others understand more about your background, communication style, and interests. You can share as much or as little as you feel is appropriate. Some things which you may wish to consider include:
What you’re good at
What you’re bad at
What you like
What you don’t like
How best to work with/help you
It's OK to ask short, clarifying questions when someone has finished, but sessions shouldn't become Q&As.
Team surveys
We run team surveys every 6 months using the _Pulse Surveys by Deel_ Slack app. These are set up to run automatically, including reminder messages in Slack, so you don't need to chase people manually. Charles and Coua have admin access to the surveys in Slack.
The questions are based on the ones used by Culture Amp and cover categories such as Company Confidence, Culture, Growth etc. on a 1 ('strongly disagree') to 5 ('strongly agree') scale. The benchmark used is against Culture Amp’s ‘new tech’ companies with less than 200 people. We then take the average score out of 5 and multiple it by 20 to get a % number. A bit rough, but close enough so we can compare with the benchmark.
Only the People & Ops and Exec teams have access to the full list of responses, which are not anonymous.
We follow a template to report a summary of the results in an Issue. You can view the latest survey results here - just copy the formatting every time.
Current list of questions
I understand PostHog's goals and can see how my work contributes to them. (1 to 5)
At PostHog, we have open and honest two-way communication. (1 to 5)
I receive appropriate recognition for my work at PostHog. (1 to 5)
I believe that my total compensation (salary + equity + benefits) is fair, relative to similar roles at other companies. (1 to 5)
The leaders at PostHog keep people informed about what is happening. (1 to 5)
If you were to leave PostHog, what would be the reason? (Free text field)
PostHog is in a position to really succeed over the next three years. (1 to 5)
What motivates you right now? (Free text field)
My manager and team around me genuinely care about my wellbeing. (1 to 5)
I feel like I am learning and growing at PostHog. (1 to 5)
Generally, I believe my workload is reasonable for my role and I am able to arrange time out from work when I need it. (1 to 5)
The support I am receiving and processes we have in place allow me to do my best possible work. (1 to 5)
I would recommend PostHog as a great place to work. (1 to 5)
I see myself still working at PostHog in two years' time. (1 to 5)
We exist to make your life easier. You should spend time shipping great products, instead of wrestling with restrictive financial controls. We want to keep things distraction-free for you, and remove admin obstacles from your path. If you are spending your afternoon arguing with an expense system, we have failed.
We aim to build a system that works for you, and not the other way around. The deal is that we take on the messy, admin heavy-lifting behind the scenes. But we ask that you don’t skip the small steps (like uploading a receipt) because when you bypass the easy steps today, it snowballs into a painful cleanup job later.
When we design processes, our first question is “how can we make this disappear for the team?” or “will this ensure fewer Slack pings for us?” We don’t use restrictive approval flows. We operate on high trust and give you the context to make good spending decisions rather than block you with red tape. We consider your time very carefully, 15 minutes distraction per person is days of productivity lost across the company. Sometimes we do have to consider the lesser of two evils, eg. asking everybody to do a small task now, to unlock less distractions later.
We also give you financial insights to make PostHog even better - we don’t gatekeep the numbers. We want you to have visibility into monthly, quarterly, annual financial performance and SaaS metrics. We benchmark ourselves against public companies and peers in the industry so we know where we’re headed!
Finance principles
This is how we think about financing PostHog as a business:
We’re efficient because it allows us to build more products.
We want to _always_ be default alive.
Losing control means becoming inefficient, because we would need to raise more money from VCs, who would push us for more aggressive growth to meet _their_ goals. This means building fewer products and spending more on shorter-term bets, like large sales teams.
Being default alive means that profitability is always an option we can take, even if it is not a goal right now.
Going from inefficient to efficient is _really_ hard, so we always want to default to being efficient. When we think about our products, this means:
Hiring efficiency always matters.
New products start with just 1 or 2 people - we don't spin up a whole team on day 1.
Products at scale should stay efficient as they'll be able to ship faster without worrying about coordination costs.
COGS only matter at scale.
New products shouldn't have to worry about this - they should optimize for speed.
Products at scale have to be profitable - if they aren't, we won't stay default alive.
We trust the team to spend money sensibly in the best interests of PostHog, and not to waste money.
Finance runbooks
These can be found in the company-internal repo within the finance directory.
While these issues are hopefully an extremely rare occurrence, it’s important for us to have a clear process around how we do this stuff in order to ensure everyone is treated fairly and transparently.
A couple of notes before we get started:
Any outcome of these processes will _only_ be shared with the people involved, not the wider team. Likewise, we ask people involved to maintain confidentiality in these cases. This is to give the best chance of a team member being able to fix their behavior and to work together with the rest of the company in future. Any misconduct issue may be deeply personal and sensitive compared to, for example, a performance issue.
We will do our best to balance being thorough with coming to a speedy resolution for everyone involved. We’d expect a process to take ~4 weeks.
Our default assumption is that we can resolve disciplinary issues and grievances internally. However, if an issue or grievance is particularly serious or difficult to resolve, we may need to bring in external help.
This isn’t a court of law - we’re just trying to establish what is most likely to have happened based on the information we have.
These policies are deliberately short and simple, and use the Acas template as a model. If you have any detailed questions about how they work in practice, please ask Charles.
Disciplinary process
In cases of minor misconduct which cannot be resolved informally, we may issue a verbal warning.
In cases of serious misconduct, or multiple instances of minor misconduct, we may issue a written warning, and then a final written warning. If these do not resolve the issue, we may move to dismissal with or without severance, depending on the circumstances.
We may omit any of the stages of procedure listed above as circumstances require - for example, if the misconduct is exceptionally serious.
Serious misconduct includes things such as:
Discrimination, bullying, or harassment
Theft or fraud
Physical violence
Deliberate and/or serious damage to property
Drug or alcohol abuse at work
Causing loss, damage or injury through serious negligence
Intentional breach of confidentiality
A material breach of your employment contract
If you are a person being accused of misconduct, you will be advised in writing prior to any relevant meeting with you of your alleged misconduct, and will be given a reasonable opportunity to respond prior to a formal meeting. Meetings are usually held with Fraser. If you are in the UK (or other jurisdictions where the right to bring other people with you is a legal requirement), you are entitled to bring a colleague or trade union representative to these meetings. If this is the case, please let us know who you are bringing in advance.
We will send round written notes afterwards, which will be kept confidential.
Grievance process
All proceedings are confidential, and you will never be punished for bringing a grievance (unless it’s obviously malicious), even if no action is taken.
Victims of harassment or bullying should disengage from the situation immediately and seek support. You can speak to Fraser about your grievance and he can help you. If he is not available, talk to Carol (US timezones) or Tara (Europe timezones).
Most grievances otherwise can usually be resolved informally between you and the person involved - if it is informal and you're unsure what to do, talk to your manager. If it is about your manager, talk to _their_ manager or ask Fraser. If the matter cannot be resolved informally, you should put the details of your grievance in writing and send it to Fraser (or if the matter concerns him, please send it to James or Tim). There is no particular format to follow, and you can start at this step if needed.
To make sure we can investigate your grievance properly:
Try and raise your grievance as soon as possible - it's easier to figure out what happened that way.
Give specific examples of the behavior that you felt was misconduct. Try to avoid sweeping statements.
Avoid including hearsay or other people’s comments in your grievance.
While this process is confidential, our default assumption is that grievances are not made anonymously as this makes it harder for us to investigate or to report back to those raising the complaint.
Please be understanding with those dealing with your grievance. We take these issues very, very seriously, and likely any action we take is difficult in one way or another.
Fraser will hold a meeting(s) to discuss further. If you are in the UK (or other certain jurisdictions where the right to bring other people with you is a legal requirement - in which case we require you to confirm the other attendees in advance of the meeting), you are entitled to bring a colleague or trade union representative to these meetings, and we will send round written notes afterwards, which will be kept confidential to those in the meeting and those the complaint is being made about. The number/type of meetings held is flexible depending on the nature of the grievance. You are not obliged to attend a meeting with the person you have a grievance against if you don’t want to.
If, following investigation, your grievance is not upheld, then we will support everyone in rebuilding their working relationship to the extent it is possible. We may consider making arrangements to avoid the affected parties working together closely.
Whistleblowing
Whistleblowing is where you observe illegal or dangerous behavior, and is different from raising a grievance as it may not affect you directly. In this case, please email Fraser and Hector. This includes things like criminal offences, someone's health and safety being in danger, or damage to the environment. You can also whistleblow about someone trying to cover up information about any of these issues. We will broadly follow the same process outlined above for grievances.
If your concern is a personal one, it will usually not be covered by whistleblowing. In these cases, you should raise a grievance.
Appeals
If you disagree with the outcome of the above processes, you have the right to appeal if you can demonstrate why you believe a particular aspect of the investigation has materially affected the outcome. Appeals must be submitted within 2 weeks of receiving the outcome.
If an appeal is submitted, we’ll arrange a final meeting within a reasonable time period. Any decision made here will be final and there is no further right of appeal. We will aim for the meeting to be held by a member of the Exec team who wasn’t involved in the process previously.
Our design team is small and we don't hire into this team very often. Please check our careers page for our open roles.
What we are looking for in Design hires
Beyond the specific skills listed in the job description, we always generally look for:
Strong eye for design
Experience working with Figma
Ability to ship iteratively
Communication skills
Do they have writing errors in their cover letter? What does their online presence look like?
Moreso than other companies, all of our communication is written and public for the world to see. Good written communication is key.
Design hiring process
1. Culture interview
This is our standard first round culture interview with the People & Ops team.
2. Technical interview and portfolio review
The technical interview round is a 2-part interview, lasting up to 90 minutes in total.
The first half of the interview will be with the team lead and 1 or 2 team members, and it will focus on your Product and Design thinking. You can expect questions around your typical design process and how you prioritize.
The second part of the interview will be a portfolio interview, where you will meet a few other members of the team. You will present a deep dive into your portfolio, covering the end-to-end process from strategy to design to impact.
3. Design SuperDay
The final stage of our interview process is the PostHog SuperDay. This is a paid full day of work with us, which we can flexibly arrange around your schedule.
A Design SuperDay usually looks like this (_there is a degree of flexibility due to time zone differences):_
Kick-off session with the team lead
Meet the founders - Tim and James
Time to focus on the task - we can provide support via your personal Slack channel
On days when we have company wide meetings, we will invite you along to that and give you a chance to introduce yourself. On days without company-wide meetings, we will arrange for you to meet a few members of our team for a casual lunch/coffee break
In line with our values and culture, you might get short replies like "step on toes" or "bias for action".
Developer Relations are relatively new at PostHog. However, the team will be growing as the company grows and as we increase our engagement with developer communities.
Currently, we are hiring for the following Engineering roles:
Beyond the specific skills listed in the job description, we generally look for:
DevRel at PostHog is undertaken with an ethos of empathy and collaboration. Any DevRel hire must clearly demonstrate this.
Has built something from scratch, ideally with minimal outside help
You may have been the founder of a startup, or built an impressive side project. You may have also worked on a project at work where you were the only developer.
Communication skills
Are there any writing errors in their cover letter? What does their online presence look like?
More so than other companies, all of our communication is written and public for the world to see. Good written communication is key.
Community focus
Our DevRel team works very closely with our customers - they do community support, demos, and help with installation and integration. All potential hires need to be driven by delivering the best possible experience for their customers.
DevRel hiring process
1. Culture interview
The culture interview usually lasts around 30 minutes and will be with someone from our . This round is loosely structured into 4 different sections:
PostHog - mission, vision, team, way of working etc. If it was cold outreach, we provide a little more context up front.
Candidate background and mindset.
Talk about the hiring process and check if the candidate has seen our compensation calculator so we know we're roughly aligned.
Answer any open questions.
We are looking for proactivity, directness, good communication skills, an awareness of the impact of the candidate's work, and evidence of iteration or a growth mindset.
2. Technical Interview
Most developer relations roles will go into detail about the candidates experience and thoughts on:
API standards
API usage best practices
SDKs and libraries
Documentation
Tutorials
Video content
Data analysis and manipulation
General programming skills
DevRel SuperDay
The final stage of our interview process is the PostHog SuperDay. This is a paid full day of work with us, which we can flexibly arrange around your schedule.
We will share the task with you at the start of the day. The task is representative of the work someone in this role at PostHog is doing, and it is always the same for each candidate, so we can make clear comparisons.Day
This gives you the chance to learn how we work, and for us to see your quality and speed of work, as well as the way you communicate. It is a very demanding day of work, but we all want you to succeed!
An DevRel SuperDay usually looks like this (_there is a degree of flexibility due to time zone differences)_:
Kick-off and ideation session where we'll define the specific deliverables for the Super Day. These will most likely include:
GitHub repo with code and README (we'll create and setup a private repo)
Written or video tutorial
Time to focus on the task, we can provide support via your personal Slack channel
On days when we have company-wide meetings, we will invite you along to that and give you a chance to introduce yourself. On days without company wide meetings, we will arrange for you to meet a few members of our team for a casual lunch/coffee break
Depending on the time zone, we might arrange a wrap up session at the end of the day
You can expect to hear back from us within two working days of your SuperDay. We will also make the payment for your SuperDay as soon as possible.
If we decide to make you an offer, we will most likely arrange a call to discuss feedback and next steps.
If we don't make an offer, we will give you as much constructive feedback as possible.
Engineers make up around 60% of our team, and we are almost always hiring for Engineering roles. This page provides internal documentation on our engineering hiring process, including roles and best practices for interviewers. You can find all open roles at PostHog on our careers page, in case you want to refer someone.
What we are looking for in engineering hires
Beyond the specific skills listed in the job description, we generally look for:
Able to pick up a new stack quickly
This matters more to us than experience with the exact technologies we use. Our tech stack is public, so candidates can see what they will work with. Experience with something to do with big data is a bonus.
We don't care how many years of professional experience someone has, but depending on our current team structure we may be looking for more or less experienced people for a role - if that's the case, we will be explicit in the job spec.
Has built something from scratch, ideally with minimal outside help
They may have been the founder of a startup, or built an impressive side project. They may have also worked on a project at work where they were the only developer.
Communication skills
More so than other companies, all of our communication is written and public for the world to see. Good written communication is key.
AI-pilled
They have built things agents actually use. More and more of what we ship is used by agents, not people, and building for them is genuinely different. We want someone who has done it and has the scars: an API an agent can drive, an MCP server, evals, or docs written for a machine. Side projects count.
User-centric
Our engineering team work very closely with our users - they do customer support, demos, and help with implementation. All potential engineers need to be excited by the prospect of getting to work directly with users.
Engineering hiring process
Hiring is a team effort, and we need everyone to contribute to make the best new hires. Talent Partners handle all scheduling throughout the interview process, and support both interviewers, candidates and hiring leads.
You can find more information regarding the hiring process in the handbook, or reach out to @talent-folks in Slack.
Culture screen
The culture screen is handled by the Talent team. Normally this is a 20-30 min call where they make an initial assessment for the candidate's fit for the job, culture, communication style, and sort all logistics.
Technical screen
The technical interview is an hour-long technical interview with one of our engineers. This might be architecture design or diving more into past technical experiences in more of a workshop style. No whiteboarding or brain teasers. We share our guide to preparing for the technical screen with candidates so they know what mindset to bring.
Sometimes when you get part of the way into a technical interview it becomes clear that the person is not a fit. Because rejecting candidates needs to be done in a specific way, please continue the interview as usual and do not reject on the call. It's okay to end the interview a bit early - interviews often don't take the entire time, and it's okay to give this caveat ahead of every technical interview.
You should use the technical exercise guide when evaluating candidates at this stage.
You may be shadowed by another PostHog team member – a shadow is someone who listens in, but doesn't participate. This is something we do regularly among technical interviewers, as a way of improving the hiring process. During high season, we may ask some of you to record these interviews for training purposes to help us onboard and train new interviewers faster. The candidate will, of course, have the chance to opt out by either letting their recruiter know in advance or letting you know at the start of the interview - you should always ask the candidate for their permission before recording and this will never affect the outcome of the interview - there are many reasons why someone may opt out from being recorded.
Culture & motivation chat
A member of our Blitzscale team – Raquel, Ben, or Paul, depending on scheduling – will meet with the candidate for a 20-25 min chat to dive deeper into culture and motivation.
Engineering SuperDay
The final stage of our interview process is the PostHog SuperDay. This is a paid full day of work, which we can flexibly arrange around the candidate's schedule. We share our guide to preparing for the engineering SuperDay with candidates so they know what to expect.
For full-stack roles, the task involves building a small web service (both backend and frontend) over a full day. The task is designed to be _too much_ work for one person to complete in a day, in order to get a sense of their ability to prioritize (and ship!).
Each engineering SuperDay will have a SuperDay buddy, this person will conduct the interview halfway through the day, will be available in Slack throughout the day to answer any questions, they will also be giving feedback on the SuperDay output.
An engineering SuperDay usually looks like this (_there is a degree of flexibility due to time zone differences)_:
An invitation to a personal Slack channel for the SuperDay, which we'll use throughout the day
This will include:- the talent team, cofounders, exec, hiring lead, & the SuperDay buddy
Time to focus on the task
An interview with the SuperDay buddy
A chat with an exec
Wrapping up – at the end of the work day, they'll send us what they've built, along with a summary
Usually the Superday buddy will review the output, but they can ask other engineers for input when needed, and we'll get back to the candidate with our final decision ASAP (always within a few days).
Overall, candidates should spend at least 80% of their time and energy on the task and less than 20% on meeting people, as we base our decision on their output of the day. However, we encourage everyone to use the Slack channel as much as needed for any questions or problems.
How to become an interviewer at PostHog
As PostHog grows and our hiring goals get bigger and bigger, to achieve that we will need more people taking interviews and assessing people in those interviews. As we scale, it's important that we maintain a calibration across interviewers by onboarding each new interviewer to the interviewing process carefully.
If you wish to get involved in interviewing, you can request so by contacting the talent team using the @talent-folks handle in Slack in the #team-talent channel. Please note, that if you are in your first 90 days at PostHog, you should not be focussing on interviewing and focus on ramping up and onboarding successfully. Even shadowing interviews can be distracting, so consider even leaving these until after your first 90 days.
Once you have let the talent team know, you'll work closely with a Talent Partner to get you up to speed. This will involve them scheduling you to shadow at least two live technical screens with two of our most experienced interviewers. They will also share with you the relevant watching and reading materials that should be consumed before conducting your first interview. Your very first interview will be shadowed by one of our experienced interviewers and they will give you feedback, on both their assessment of the candidate interviewed and then how you did. Based on how this goes, either you can get another interview shadowed by another engineer for more feedback, or you can go out on your own.
Your first interview alone
Your first interview alone might feel daunting, and it should. So it is best to prepare as much as possible, read all the available materials on the candidate ahead of schedule. Prepare how you will manage your time based off the interviews you've shadowed and the feedback from our shadowed interview. Block out time at the end of the interview to ensure you have time to write up your notes and reflect on the candidate and provide the feedback. Eventually you will get into the habit of being able to rely on AI notetaker notes (or your own notes) to be able to come back to leave the feedback but on your first go, it's important to have all the information fresh and give yourself plenty of time to go through this process. You want to feel excited about a candidate once you've finished up with them, but amongst this is a new experience so it's important to give yourself the ability to feel excited and go into detail on how you rate them. You want to be able to feel beyond reasonable doubt that you are making the right decision.
You should try to have as extensive notes as possible, this is good hygiene for interviewers at later stages to dig into areas of uncertainty. Always make sure to make any flags or doubts you have very clear.
Your first 5-10 interviews
Once you have conducted your first 5-10 interviews you will want to reflect on how you are getting on. The best way to do this is to review how your candidates have got on. If you've rejected more than 6 or 7, then perhaps you might be being too harsh. You can ask other interviewers or a talent partner to assess your notes and see if they would have been more lenient. The technical screen has about a 50% pass rate, so keep that in mind.
For the candidates that you put through, it's worth keeping a close eye on how they perform at stage 3 & stage 4 and seeing how they have done. Did those flags that you have ultimately lead to them failing, should you have just said no? Where flags that you had actually not a problem, if so, how can you dig in to them better next time to understand them better.
You should try and keep your approach relatively consistent for the first 5-10 interviews so you can then introduce changes afterwards and see if they yield better or worse results. If anything is very obviously not working, change it immediately.
How to keep improving as an interviewer
Regularly shadow other interviewers, have other interviewers shadow you. Give each other feedback
Speak with Talent Partners, ask for their feedback
Ask exec's why they gave specific scores about candidates you interviewed
Keep track of how the candidates you have assessed get on in the later stages
If you've been invited to a PostHog SuperDay, here's what to expect and how to set yourself up for success.
What the SuperDay looks like
The SuperDay is a paid full day of work ($1,000 USD). You'll receive a project task at the start of your day and submit your work at the end. The project is the main focus -- you'll build something from scratch, tailored to the role you're applying for. Expect to spend the majority of your day on it.
Scheduled throughout the day, you'll also have:
A debugging session (45 min) -- a separate pairing session where you'll work through bugs and features in an existing codebase with an interviewer. This is a different codebase from your project.
A check-in call -- your SuperDay buddy (the same engineer available to help you in Slack) will review your project progress partway through the day, ask about your decisions, and offer feedback.
A short chat with a co-founder or exec -- a brief conversation about culture and motivation.
You'll also have access to a dedicated Slack channel with the team throughout the day. Use it -- share progress, ask questions, surface blockers.
The project
What we're evaluating
Shipping and execution
The scope of the task is deliberately broad, so you have room to make prioritization choices. You won't finish everything -- that's expected. We want to see how you decide what matters most.
Strong candidates ship a working core feature early, then layer on improvements. They make deliberate choices about what to build and what to skip, and they can explain why. A functional product that solves the core problem well beats a half-finished product that tries to do everything.
Technical depth
We care about the quality of what you build. This means thoughtful architecture decisions, clean code, sensible error handling, and attention to edge cases in the data you're working with.
The best candidates go beyond surface-level implementation. They notice patterns and anomalies in the data. They think critically about whether their solution is actually correct.
Product sense
PostHog engineers are product engineers. We want to see you think about the person using what you're building. Is the interface intuitive? Does the output actually help someone make a decision? Would you be proud to demo this to a customer?
Think about the utility of what you're building.
Problem-solving and creativity
The strongest SuperDay submissions show candidates who thought deeply about the problem. They adapted when something wasn't working and found ways to make the tool more useful beyond the basic requirements. For example, if the core task asks you to visualize data, a strong candidate might notice something interesting in the data itself -- an unexpected pattern, a segment that behaves differently -- and surface that insight in the product. That kind of curiosity matters more than adding extra UI polish.
We notice when someone asks "what would actually help a user here?" and lets that guide what they build next.
How to prepare for the project
Use tools you know well. You can use whatever technologies you're comfortable with. Pick tools you're productive in so you can move fast.
Think about data. You'll be working with a dataset. Before jumping into code, spend time understanding what the data looks like, what stories it tells, and where it might have quirks. The best candidates treat the data as a first-class part of the problem.
Get comfortable explaining your decisions. During the check-in call, we'll ask about the choices you made. Why this architecture? Why this feature first? What would you do differently with more time? Reflect on your decisions as you go.
During the day
Communicate proactively. Share progress updates and blockers in Slack. Ask clarifying questions early if something is ambiguous. Don't wait until you're stuck for hours.
Commit regularly. We'll review your git history. Frequent, meaningful commits show us how you work, how you think, and how you build incrementally.
Prioritize ruthlessly. Build the core feature first and get it working end to end. Then improve it. Then add more. Resist the urge to gold-plate any single piece before the whole thing works.
Take feedback seriously. At the check-in, your interviewer will offer suggestions. We pay attention to whether those suggestions show up in your final submission. This is a signal of how you'd work with teammates day to day.
The debugging session
What to expect
You'll join a live coding environment with an interviewer and work through a series of problems in an unfamiliar codebase. The problems range from fixing bugs to improving performance to implementing a small feature. You won't know the codebase in advance -- that's the point.
You're allowed to use Google for reference, but we ask that you don't use AI tools – we want to see how _you_ think about debugging. Treat the interviewer like a colleague -- you can ask them questions, think out loud, and discuss approaches.
How to prepare
Practice reading other people's code. Pick an open-source project you've never seen, find a bug report, and try to trace the issue through the codebase. Building a mental model of an unfamiliar system is the core skill here.
Brush up on debugging fundamentals. Understand how to trace request flows through a web application. Be comfortable reading error messages, stack traces, and logs. Know how to isolate problems systematically rather than guessing.
During the session
Read the README first. Take a few minutes to read the documentation and understand the system before touching anything. Candidates who jump straight into code without understanding the architecture tend to struggle.
Form a hypothesis before changing things. Resist the urge to start editing code immediately. Think about what might be going wrong, then go looking for evidence.
Narrate your thinking. Talk through your thought process, even when you're uncertain. Saying "I think the problem might be here because..." goes a long way. The interviewer can only follow reasoning they can hear.
Verify your fixes. After making a change, confirm it works and check that you haven't broken something else.
Ask questions. The interviewer is there to help. Treat them like a colleague you're pairing with.
What not to worry about
Perfection. We don't expect you to finish everything. We care about the quality of what you ship, the decisions you make, and how you work under constraints.
Specific technologies. Use whatever stack you're strongest in for the project. For the debugging session, you'll work with what's already there -- we're evaluating your problem-solving ability.
Getting stuck. Everyone gets stuck. What matters is what you do next. Ask questions. Try a different approach. Talk through what you're thinking.
A note on AI tools
You can use AI tools during the project portion of the day -- we know this is how many engineers work. But you need to understand what you've built. During the check-in, we'll ask you to walk through your architecture, explain your decisions, and reason about your code. If you can't defend and explain your solution, it won't matter how polished it looks.
For the debugging session, we ask that you don't use AI tools beyond basic autocomplete. We want to see how you reason about code.
What comes next
After the SuperDay, everyone involved will leave their feedback. We aim to get back to you with a decision within 48 hours. You can read more about the full interview process here.
If you've made it this far, good luck -- we're rooting for you.
If you've been invited to a technical screen at PostHog, here's what to expect and how to show up prepared.
What the technical screen looks like
The technical screen is a 60 minute architecture and design discussion with one of our engineers. You'll work through an open-ended problem together, and there are many reasonable approaches. We're primarily interested in how you think.
What we're evaluating
The session is intended to discover where your knowledge is wide and where your knowledge is deep. The best candidates tell us when they're communicating their direct experience, when they're talking about work they were close to but not part of, and when they've not done something but know that's how to solve that type of problem.
System design instincts
We want to see well-developed intuition for how systems work in practice – choosing the right tool for the job, understanding where complexity is warranted, and reasoning about what happens as requirements change. This is about technical depth and breadth, not just scale.
For example (not from what we'll discuss): how would you design a notification system that needs to reach millions of users without overwhelming downstream services? If you're building a deployment pipeline, where do you put the guardrails so a bad deploy doesn't take down production?
Strong candidates reach for these concepts naturally as part of their design.
The "why" behind your decisions
We want to hear why you'd choose a given technology. Saying "I'd use Postgres" is fine. Saying "I'd use Postgres here because the access patterns are relational and consistency matters more than write throughput for this part of the system" is much better.
Every design decision involves tradeoffs. We want to hear you articulate them – even when there isn't a clear winner. Knowing when not to use a technology is just as valuable as knowing when to reach for it. Showing that you understand the costs of your choices matters a lot.
Problem-solving approach
The strongest candidates slow down before they speed up. They ask clarifying questions. They scope the problem. They decompose it into pieces they can reason about individually.
We're looking at your process: do you clarify requirements before committing to an approach? Can you break a big problem into smaller ones? When you hit a fork in the road, how do you decide which way to go?
If you find yourself wanting to immediately start listing technologies, pause. Take a breath. Ask a question instead.
Product sense
PostHog engineers ship product, work directly with customers, make product decisions, and own outcomes end to end. In the technical screen, this shows up as thinking about the user of whatever you're designing.
Who is using this? What do they actually need? If you're designing an alerting system, do you think about what happens when someone gets paged at 3am for a non-critical issue? If a design decision trades off developer convenience for a better user experience, which do you lean toward and why?
You should be someone who thinks about your users, not just your systems.
Autonomy and independent thinking
PostHog is a company of small teams with high autonomy. We need people who can identify problems, figure out solutions, and drive them forward on their own.
In the interview, this shows up as taking ownership of the problem. Drive the conversation. Propose ideas. Change direction when something doesn't work. Treat the interviewer as a collaborator.
How to prepare
The best preparation is reflection. More concretely, here's what we recommend:
Think about systems you've built or worked on. What went well? What would you change? What broke, and why? The ability to reflect honestly on past work is one of the strongest signals we see.
Practice thinking out loud. Walk through your thought process, even when you're uncertain – especially when you're uncertain. The interviewer can only evaluate reasoning they can hear.
Get comfortable with ambiguity. The problem will be open-ended on purpose. There is no single correct answer. We want to see how you navigate uncertainty.
Brush up on fundamentals, not trivia. You should understand how the building blocks of modern systems work and when to reach for them. You don't need to know the exact configuration flags for any particular technology.
What not to worry about
Specific language or framework expertise. We care about your ability to reason about systems, regardless of which stack you've used.
Getting the "right" answer. There isn't one. A thoughtful wrong turn that you recover from tells us a lot.
Sounding polished. Genuine thinking beats a practiced presentation. It's okay to say "I'm not sure, but here's how I'd figure it out."
A note on the format
We want this to feel like a working session. The interviewer is there to collaborate with you, ask follow-up questions, and sometimes push back on your ideas. If something isn't clear, ask. If you want to change direction, say so. The best interviews feel like a conversation between two engineers solving a problem together.
If you pass the technical screen, you'll meet a member of our Blitzscale team for a culture and motivation chat, followed by a PostHog SuperDay. You can read more about the full interview process.
We deliberately keep our structure flat and we don’t believe in having a lot of fancy titles early on. However, as we grow, we will hire people into more senior-type positions.
With our senior leadership hiring, more so than normal, we are aiming for speed, and as always, quality. If a candidate is amazing but doesn't fit with a specific role need we have _right now_, we still aim to treat the hiring process with the same urgency as if posthog.com has gone down.
Hiring process
Preparation
Before we kick-off the hiring process for a role, we make sure to have everything we need for the role prepared:
James or Tim to write job description, Blitzscale team review
Post the role - share in our networks (we may not publicize this in all our usual channels as these types of roles can attract a very high volume of candidates who are not relevant)
Ask investors for referrals
Agree on salary benchmark and equity level - this usually doesn't fit in our compensation calculator
Decide on interview process - this might be bespoke (see below)
The People team will build a market map and share it with the leadership team, outreach ideally coming from the founders
Interview process
In order to ensure speed, we aim to finish the process within 5 working days (assuming the candidate has availability). This is a rough guide that can be adapted
Day 1: Candidate meets Coua - _30-45 minutes_
Culture
Important information: time frame, salary expectations (base/equity/bonus/other), visa, other open processes
Answer open Qs
Day 2: Candidate meets James and/or Tim - _45-60 minutes_
History, mission, vision
Role responsibilities
Role outlook (team, development etc)
Day 3: Technical Interview with James/Tim + respective team - _60 minutes_
Background and experience
Technical deep-dive
Scenario-based questions
Day 3: Meet rest of the team - Charles - _30-45 minutes_
Strategy and long term outlook
Culture fit
Day 4: SuperDay (_optional_) or meet the team (standup or informal lunch)
Day 4: Wrap up call with James and/or Tim - _30 minutes_
Answer any open questions, potentially talk about offer details already
Coua to follow up via email
Day 5: Offer out
Coua to send official offer and comp sheet with James/Tim/Charles in CC
James/Tim/Charles to drop a quick message how excited they are
🤞
Depending on the role, we might also schedule a call with one of our investors.
We take exceptional people when they come along - and we really mean that! Don’t see a specific role listed? That doesn't mean we won't have a spot for you.
In cases where a candidate reaches out without us having a role posted, we follow the same process as above, and work through all open tasks we would usually prepare for on day 1 and 2.
Reminder: hiring the right team is the most leveraged activity we can do. Whatever you do, focus on getting the strongest signal from a candidate in an interview. Do _not_ focus on scalability / efficiency.
Focus on themes
Many well-intentioned interviewers will create a long list of questions that they'll follow rigorously. This is likely to lead to shallow answers.
You're trying to understand how a human being operates, so go deep. It'll be more interesting for both of you, and will give a stronger signal.
Prepare the themes in advance you'll want to ask about. For a cultural interview, it might be something like:
scrappiness
low ego
ambition
able to write code
optimist
For each of the above themes, consider some good questions in advance. Use these as starting off points.
Ask permission to get what you need
Candidates' expectations of interviews vary wildly.
Less experienced candidates, or those in less competitive markets, often expect an intense questioning.
The reverse is true for more experienced candidates - who will want to understand if the company is performing well, aligned, and many more things to help them pick the right place to work.
At the start of the interview, "name it". Say to the candidate something like "hey, I need to go deep on how you work to do the best assessment of a good fit here, is it ok if I focus this interview primarily on that for the first 20 minutes? Then I'll leave 10 minutes at the end for questions. If we overrun, I can book more time with you." Other times, you'll need to explain the opportunity more - for example, if the candidate came through cold outreach. Have a clear idea before you start, and explain it to the candidate up front.
Work as a team
Focus your questions on the areas you're stronger at. If you're great at scrappiness, you're probably best suited to spotting it in others.
It's more important to validate a few things well, and to get others to dig deeper in other areas, than it is for you to do a shallow interview across everything. If you miss something, just create a clear ask of your next colleague to cover the area you missed, or to dig deeper on an area you felt uncomfortable with.
Don't bias yourself
When you do your final write up on a candidate, do this ahead of reading the feedback from others.
Humans are evolved to stick to their tribes - if you know that your colleagues believe X, you're much more likely to believe X. Reading others' feedback means you are less likely to say no to someone because of minor concerns or to push for a candidate with hidden talent. Both things we need to do.
Bonus points - writing your own independent decision in front of your peers, forces you to clarify your feedback properly.
Figure out why you're not excited
You will be asked to give a score out of 4 for each interview (where 4 is the highest). If you don't give a 4/4, please articulate as clearly as you can why, even if it's a minor concern. This helps (i) subsequent interviewers to dig further into a concern to validate/invalidate it and (ii) it may cause other people to spot/mention the same issue - which can stop us moving forward with someone that won't be a good fit.
Some of the hardest decisions are when lots of people are _fairly_ lukewarm on a candidate. This is particularly likely when a candidate has relevant experience but is a poor cultural fit.
Beware of how you're feeling through the interview, and adapt as you go.
If a technical interview makes you feel worried someone isn't fast, energetic, or intelligent enough, or whatever else - do some digging on those themes.
Write out mild concerns
Imagine any perceived issue being magnified 10x when the candidate starts. Mention in your feedback to others if you had a mild concern about something. Sometimes you'll find that everyone shares this concern, which means we shouldn't hire.
Get specific
Going into detail helps you figure out the difference between someone that _sounds_ good and someone that _is_ good at their job.
How did they solve the impressive sounding technical problem? Why did they solve it like that? Did they drive the project or were they a passenger? Who actually wrote the code?
In one interview, assessing organization skill, I've even found out how a candidate used to organize her fridge. "What's something you've done that is so organized, that it was weird".
Keep it on track
Some candidates, due to nerves, will go down rabbit holes. The ability to sum up information concisely, under pressure, usually isn't something that appears in our job descriptions.
Therefore, if a candidate goes way off track, it's in their interest for you to politely interrupt "hey I think I've got what I need here on this question, I'm going to move on so we cover everything - is that ok?"
Focus on slope
... and be very wary of getting seduced by companies rather than people. Candidates who've worked at places with strong product market fit will have had an easier time achieving results. Some of our best people have come from a string of very average startups.
As the interviewer, you should feel a little nervous
A short interview has a _huge_ impact on our company - either hiring the right or wrong person. There are lots of hard-to-reverse consequences of not getting it right.
Bring energy into the interview. Be engaged. You are part of our brand.
100% inbound by default – effectively a word of mouth strategy, like our marketing and sales model.
Supplement this with occasional, targeted sourcing to increase the pool of diverse candidates (if needed).
This has resulted in the highest number of qualified and motivated candidates reaching final stages with us compared to other methods, such as more generic sourcing. As a result, we invest most of our energy in:
Writing exceptional job descriptions, and re-writing them frequently
Ensuring our careers page and application experience are world class
Sharing our roles within our networks for exposure in unusual ways (as candidates are likely to be pre-qualified)
Where we can, giving candidates genuinely useful and direct feedback if they weren't successful with us
Running a smooth and incredibly slick recruitment process, from application to offer
We are all-remote, but we have a few limitations on the countries we are able to employ people in:
Our hiring is strictly limited to candidates physically based in GMT+2 through GMT-8 (following the sun's rotation). Unfortunately, we cannot hire people outside this range, even if they are willing to adjust their working hours. The only exception is for countries that are normally GMT+2 but move to GMT+3 during daylight savings (e.g. Bulgaria, Greece).
In some cases, we include a preferred time zone range for certain roles to help balance coverage and support across the team that is hiring. This allows us to distribute responsibilities more evenly while maintaining strong collaboration and responsiveness.
Due to US sanctions, we can't hire folks in Cuba, Iran, North Korea, or Syria.
We don't currently employ people via EOR in France, Italy, Sweden, Switzerland, Iceland, Belgium, Luxembourg, Uruguay, Bolivia, Denmark or Brazil, mainly due to the very high employer costs.
In some of these countries we _may_ consider hiring as a contractor, provided there is no misclassification risk. We have done this before successfully in Brazil and Uruguay.
Hiring Process
External recruiters
All of our recruiting is done in-house, and we do not work with external agencies for any of our roles. We frequently receive unsolicited messages from agencies – sometimes 20 in a week – who want to work with us. The best response is to simply ignore the message. If they attach any candidate profiles or résumés to their email, please _do not_ open the attachment. If you are ever unsure what to do, feel free to forward any unsolicited messages to careers@posthog.com.
Deciding to hire
‘You're the driver’ is one of our values here at PostHog. We think carefully about each new role and the complexity it introduces to the organization. We also have an extremely high bar for the people we do hire!
We use Pry to plan our hiring. We use the hiring forecast as a guide, but iterate on this pretty much every month, so we can stay super responsive to changes PostHog's needs. Typically we know:
3 months out – exact job titles we want to hire for, and in which month
6 months out – number of each type of job (e.g. 1x designer, 3x engineer)
12-24 months out – number of hires overall we want to add to the team
For each new role, please open a new issue on the Ops & People project board and add all the requested information from the new hire form. Everyone will have the opportunity to give their feedback on the proposed role before we publish it.
The role of the Hiring Manager
The hiring manager is a role assigned to the person who will work most closely with the People & Ops team to make a hire. Usually this is the person who will manage the new hire or is a Small Team lead.
If you are a hiring manager for a role, you will usually:
Give input into the job spec to make sure it's right
Give the People & Ops team feedback on candidates
Conduct the technical interview
Kick off the SuperDay and be the candidate's main point of contact on the day
How to write a great job description
The People & Ops team will then write up the full job description in Ashby.
We frequently iterate on our specs, but we have a template for a product engineer role that you can use as a starting point. Generally, the "About PostHog" and "Things we care about" sections should be used in all ads, and you can adapt the other sections to your specific requirements.
We find the following approaches work well:
Being extremely clear and precise about what this person will actually be working on (including linking to example PRs/Issues of similar work in GitHub where possible)
Sharing why this role specifically is exciting, and the impact they will get to have
Linking to as much useful contextual information as possible, including the small team they will be working on
Using the absolute minimum number of requirements needed - 5 'must-haves' absolute max
Ashby will automatically add the role on our careers page. It will also 'helpfully' publish it on a bunch of other free but irrelevant job boards - you should manually remove all of those except for Ashby and LinkedIn. Wellfound will need to be posted manually.
Ashby also had a partnership with YC's job board so all roles to YC's Work at a Startup will push out automatically. For certain roles, we also publish on other job boards:
Every time we open a new role, we will share the details and ideal profile with the team during All Hands.
What qualifies as a referral?
A referral must meet these criteria to be eligible for a bonus:
_No retroactive referrals_: You cannot claim a referral for someone who has already applied to PostHog. Referrals will only be applied retroactively if you can tell us how you've been involved in this person applying to PostHog, and you should provide the Talent team with this information as early in the process as possible!
_Must provide valuable context_: Your referral should include meaningful insights beyond basic resume information
_Be proactive_: Don't only wait for your network contacts to apply first - actively identify and reach out to potential candidates
Personal referral
If you know someone who would be a great addition to the team, please submit them as a personal referral. If they're successfully hired, you'll receive a $2,500 referral bonus! The bonus can be either paid to you directly, or towards a charity of your choice where we will match the amount! You can also split the amount between you and the charity.
What makes a strong personal referral:
You've worked directly with this person and can speak to their abilities
You can provide context about their motivations, work style, or how they'd fit with our team
You can help with closing them if they're interested (explaining PostHog culture, answering questions, etc.)
When referring cross-team, it is optional to first reach out to #team-talent and gather context before doing the work of referring (will save us all some work, and the candidate a rejection email!). If you feel confident that the referral is a match for that team, please go ahead and submit the referral directly. You can read below what the process to refer is like. Referring someone means we'll review them carefully. It doesn't guarantee they'll get an interview. We hold referred candidates to the same high bar as everyone else, and we'll let you know if they don't progress and why.
Examples of insufficient referrals:
"Worked with X at Y company, very nice person"
Basic resume forwarding without additional context
Generic LinkedIn connections you don't actually know
Please make sure the candidate has given their consent before putting them forward.
We occasionally open up short term contracts, and you'll receive a $1,000 referral bonus if you recommend someone here too! The contract just needs to be on a full time basis and at least 3 months long.
Unfortunately people who actively work on recruitment in the People & Ops team at PostHog are not eligible for referral bonuses, to mitigate the risk that they influence the process unfairly. If you would like to refer someone and are not sure if this applies to you, speak to Tim.
Help with your network
We recognize everyone is busy with limited bandwidth. If you'd like help identifying potential referrals from your network:
Reach out to the Talent team! We can go through your network and find interesting candidates.
We'll collaborate on outreach strategy
Together we'll decide who makes the initial contact
You'll still receive the referral bonus if they're hired
What's the process?
If there is an ongoing conversation, please cc careers@ into the email thread with the referred candidate, and we will take it over from there. Otherwise, please upload the profile to the Ashby referral page.
Important: If they have applied themselves already, you cannot claim them as a referral - this includes candidates who applied weeks or months ago.
Social referral
You will sometimes get people emailing or messaging you on LinkedIn asking to chat about a role or get referred in. If you have a chat with them and think they are worth referring, but you don’t know them enough to provide the talent team with valuable context, you can submit them as a social referral. If you don't know them, you can point them back to our careers page, or just ignore them. We get dozens of these kinds of messages every day, so don't feel bad about not engaging! If they are asking for advice, you can point them to this article.
The referral bonus for social referrals is $500, and we again match any amount you choose to give this to charity.
If you are consistently posting about jobs to your networks, please note that Ashby does not currently support referral links in a way that lets us reliably track those applications as social referrals. If someone reaches out after seeing your post and you want them to count as a social referral, ask them not to apply directly yet. Instead, submit them through the Ashby referral page.
Family referral
We welcome referrals of family members as long as they will not work on the same team or within the same reporting chain as the referring team member. To maintain a fair and balanced team environment, we do not hire spouses, as this can create interpersonal dynamics that are difficult to manage in a professional setting. This approach helps ensure that all hiring decisions remain objective and that team interactions stay healthy and unbiased.
Referral payouts
You'll get paid the bonus 3 months from the new team member's start date, and it will be processed as part of payroll so you won't have to physical do anything as Talent will notify our Ops team upon hire of your referral. If this date falls close to the payroll cutoff for that month, it may be included in the following month's payroll instead. Bear in mind that you might be liable for income tax on the bonus.
Non-team referrals
We also welcome external referrals, e.g. from:
From our investors
From the PostHog community (by posting on our social media profiles for our followers to see)
From the YC community (Slack / WhatsApp / Forum)
As a thank you, we will give you $50 credit for our merch shop.
Managing candidates
All of our candidates are managed in Ashby – all team members have access to the platform and Ashby will automate your specific level of access based on the role you play during the hiring process (i.e. hiring manager, team member, etc.). If you need additional access, please reach out to Coua or Charles.
We record all candidate-related comms in Ashby, so we can ensure we provide all candidates with the best experience we possibly can - even if they are unsuccessful, they should come away feeling like they had a great interaction with PostHog.
Ashby is a pretty intuitive platform to use, but here are a few helpful tips to get you going
Link your Gmail account in Settings if you are in direct contact with candidates. This means any emails you send directly from your inbox will automatically be captured on their Ashby record for everyone on the hiring team to see.
When emailing candidates from within Ashby, you can select a Template from the dropdown bar (and customize it if you want). If you find yourself writing the same email, it is worth saving as a template.
If you receive an application via email or some other non-Ashby channel like Slack from a candidate you think we should definitely interview, tell them to apply directly via the website and forward it to careers@posthog.com. You will get people reaching out to you over LinkedIn regularly - only forward the high priority candidates to the talent team.
Managing sourced candidates
For roles we're actively sourcing for, please make sure that an extra step is added to the interview process as "Sourced Screen" after "Replied". All sourced candidates need to be added to Ashby from the "New Lead" stage and should be moved through each stage until the end of the process. If a sourced screen goes well, the candidate can be moved to "Technical Screen" directly.
Booking interviews through Ashby
Schedule interviews through Ashby itself. Do not use Google Calendar, otherwise the event won't be populated with useful candidate info, and we won't have a record of the meeting anywhere.
When we book a meeting, we have the option of selecting a Google Meet or Zoom call which Meet should be the default.
If you are involved in interviewing it is important to keep your calendar up to date. Candidates can book directly into your calendar so having your calendar blocked when you are not available to interview is important. This includes things like personal appointments, travelling, attending off-sites etc.
If you have an interview booked in you cannot make, do not just respond "no" to the calendar invite, please let the ops team know asap, or even better find a replacement for your interview and let Ops know, and we can update the interview. We aim to provide a great candidate experience and moving interviews is one way to reduce the quality of that experience.
Hiring stage overview
Application
The Talent team reviews applications and resumes/portfolios carefully and leaves their feedback as a comment on the candidate's record in Ashby if relevant.
Blocked application for multiple open roles
Our Talent team reviews candidates across all relevant open roles company-wide. If our system shows that you’ve applied to multiple roles at the same time, your original application will be retained while the others may be temporarily blocked within your candidate profile. This helps us review candidates fairly and thoroughly. No action is needed on your end— your information is already in our system, and the Talent team will ensure you’re properly considered for other similar opportunities. Please note you will not receive multiple rejection emails for the roles that you have applied for.
If a candidate hasn't customized the application or resume to the role, it is a flag they aren't that excited about working at PostHog. Cover letters are definitely _not_ mandatory, but at an interview stage, it's important to note how passionate they seem about the company. Did they try out the software already? Did they read the handbook? Are they in our community forum?
Candidates who are unsuccessful at this stage will receive an automated rejection email. Due to the volume of applications we receive, we usually don't provide personalized feedback.
12 month cooling application period
To ensure a fair and consistent experience for all candidates, we ask that applicants wait 12 months before reapplying for the same or a substantially similar role. This time allows candidates an opportunity to build on their experience, develop new skills, and strengthen areas that may not have fully met the role’s requirements during the interview process.
After 12 months, candidates are welcome to apply again; however, reapplying does not guarantee that the application will be reconsidered or that the candidate will move forward in the process. Our teams and hiring needs are continually evolving, so the requirements of a role may change, and the candidate’s experience may no longer align with what we’re looking for at that time.
We appreciate your interest in joining our team and encourage you to continue growing your skills and experience in the meantime.
Interviews
As a rule, all interviews at PostHog are conducted in English. Whilst this might seem obvious to some, we are lucky to have people from multiple different countries, that speak multiple languages. We are hiring for people to be successful at PostHog, and at PostHog we conduct our business in English, so it is important the hiring process is also conducted in English.
If you are paired with an interviewee who speaks your native language, just politely acknowledge this and let them know all interviews are conducted in English. We also require these calls to be conducted as a video call, so a working webcam is necessary.
How interviews are scored
Scoring Scale (1– 4)
1: Strong No = This candidate is clearly not a fit for PostHog now or in the future
2: No = Not a fit now (maybe in the future)
3: Yes = This is a solid hire
4: Strong Yes = This is an exceptional person we need to hire. (we might go to extra lengths to hire them)
A good rule of thumb when deciding whether not to progress at any stage: if the candidate is between a 2 and a 3, then it's a 2. It's almost never worth putting through someone who is a 'maybe'! We provide lots of information about PostHog to enable candidates to put their best application forward.
When you have conducted an interview, you should leave feedback no later than the end of the day after the interview. Moving candidates through the process quickly is critical to us being able to hit our hiring goals, waiting more than one day for feedback can kill the momentum and leave the candidate with a bad experience. If for some reason you cannot give feedback before then, alert the talent team ASAP.
1. Talent interview with Talent
We start with an interview which is designed to get the overall picture on what a candidate is looking for, what experience and skills they bring, and to explain who we are. A template scorecard has been created for this stage in Ashby.
This is to allow both PostHog and the candidate to assess whether the candidate is a great addition to the team, and to dig into any areas of potential misalignment based on the application. We are looking for proactivity, directness, good communication, an awareness of the impact of the candidate's work, and evidence of iteration / a growth mindset.
This round is loosely structured into 4 different sections:
(If we sourced them) PostHog – quick intro about the company and role
Candidate background and mindset
Talk about the hiring process and check if the candidate has seen our compensation calculator, so we know we're roughly aligned.
Answer any open questions
This stage is usually a 20-minute video chat.
Candidates who are unsuccessful at this stage should receive a short personalized email with feedback.
2. Technical interview with the hiring manager
In this round, the candidate will meet a future team member. This round is usually 45-60 minutes and will focus on a mix of experience and technical skills. Please check the specific hiring process for each team for more details.
As a rule of thumb, everyone interviewing must feel a genuine sense of excitement about working with the candidate. Again - if it is not a _definite yes_, then it's a _no_. Ask yourself - does this candidate raise the bar?
For engineering roles only: during high-volume seasons, this round might be recorded for training purposes to help us onboard and train new interviewers faster. The candidate will, of course, have the chance to opt out by either letting their recruiter know in advance or letting the interviewer know at the start of the interview.
3. Small Team interview with an Exec Team member
This is a call with either James, Tim, Raquel, Paul, Ben, or Charles depending on which Small Team they are being hired into. They will probe further on the candidate's motivation, as well as checking for alignment with PostHog's values.
Candidates who are unsuccessful at this stage should receive a short email with feedback.
4. PostHog SuperDay
The final stage of our interview process is what we call a PostHog SuperDay. This is a paid full day of work with us, which we can flexibly arrange around the candidate's schedule. We are not able to bypass this stage so if the candidate is not interested in conducting this final round, unfortunately we will have to part ways and the candidate will no longer be considered for the role.
If it is difficult for a candidate to commit to a whole day in one go - they may not be able to get the time off, or have childcare commitments that make this difficult - we can be _very_ flexible. For example, we can split the SuperDay across two or more sessions, and can align timezones to suit the candidate, given we have a team that's globally distributed. A candidate will never lose out because they are not available to do a SuperDay right away.
The candidate will be working on a task that is similar to the day-to-day work someone in this role does at PostHog. They will also have the chance to meet a few of their potential direct team members, and if they haven’t already, our founders. This gives the candidate a chance to show off their skills, and for us to see the quality, speed and communication of the candidate.
As we grow, we find the need to hire engineers who are comfortable working with existing codebases to be increasingly fundamental. During SuperDay, Product Engineering candidates will also have a 45-minute debugging session. There is nothing to prepare in advance for this; you'll work with your interviewer in a pairing session to get through a bunch of bugs! It is a demanding day of work.
We pay all candidates a flat rate of $1,000 USD for their efforts on the SuperDay. On rare occasions, if we have to cancel a scheduled superday because we have filled the role with another candidate who was further advanced in the process, we will pay a $500 USD term fee to the candidate for their efforts up until this point.
If the candidate is unable to accept payment for the SuperDay, we will donate by default to Django Girls Foundation. Payment and donation for SuperDays are expected to process every Wednesday so it'll depend on what day your SuperDay falls on. Either way, please feel free to flag your talent partner if you don't see the payment deposit within one week of your SuperDay.
This day will be _the same_ task each time for a given role, to be shared with the candidate at the start of the day. The task is generally designed to be _too much_ work for one person to complete in a day, in order to get a sense of the person's ability to prioritize and get things done.
Overall, the candidate should aim to spend at least 80% of their time and energy on the task and less than 20% on meeting people, as we will base our decision on the output of the day.
For everyone on the PostHog team meeting a candidate, ask yourself – will this person raise the bar at PostHog? The answer should be yes if we want to hire them.
In advance of the SuperDay, we will need to do some additional prep to ensure that the candidate has a great experience:
Send the candidate, Blitzscale team member, (depending on the role), the talent team, and the SuperDay buddy (technical roles) or the lead (for all other non-technical roles) a Google calendar invite to remind the team when the SuperDay will take place (mark the invite free and all day or split days)
Send them an email in the first instance to schedule the SuperDay - we aim to do this as soon as possible, as candidates often will need to book a day off work. Use the Ashby email template for this. If the task involves them doing 'real' work for PostHog, we should ask them to check that their current employment contract permits this - we try to create fake tasks for this reason. For all US candidates there is a requirement we collect a W9 from the candidate for accounting and tax purposes (_this doesn't apply if the US candidate decides to donate the funds to one of our sponsored projects_)
We also send the candidate a follow-up email with details of the day, and ask them for their day rate and bank details right away, so the candidate can be fully-prepared for what to expect and who they will meet. There is a template for this email in Ashby, depending on the role - this will probably need customizing.
When scheduling in Ashby, please make sure to turn on the option to create a private Slack channel for the candidate and all relevant people - this will be where they can chat to us over the course of the day if they have any questions etc (#superday-[first-name]-[role]). Invite the candidate as a single channel guest. We might need to add the candidate to one of our systems depending on the role, e.g. Ashby for a recruiter SuperDay, but on the whole this should be minimized.
The last step will be to schedule the appropriate engineering task to go to the candidate's GitHub handle the day of their SuperDay. Sign in to your Vercel app and click on Manage SuperDays and fill out the form for the candidate's info. Please be aware the task is case-sensitive.
For the Clickhouse Engineer task, please follow this task and click on the "Code" button and hit download button and upload the zip file into the candidate's slack channel to go out the morning of the SuperDay by 8:00 am in the candidate's timezone.
(One day before the SuperDay) For non-technical roles, invite the candidate to a kickoff meeting with the hiring manager at the start of the day and send the candidate the task - aim to send this before the kick-off session so if the candidate has any questions they are able to go through them during the kick-off session. We encourage the candidate to ask questions throughout their SuperDay, but sometimes it is nice to have any questions answered in advance, so they can kick off their task appropriately.
It is important for product engineer candidates to be prepped for their check-in call to do a deep dive of their progress so far with their SuperDay buddy while other non-technical roles in Sales, Onboarding, and Customer Success, the candidates will be running a demo mid-point of their SuperDay.
(On the SuperDay) Give the candidate a warm welcome! Make it clear that the team is here to answer any questions, and they should feel free to reach out any time! Otherwise don't feel like we need to check in with them - let them get on with the task and trust that they will message us.
For some roles, we may occasionally set a task that goes over multiple days. For example, we have set Content Marketer tasks that last 3 days in order to create a piece of content.
Peer team interviews
During a SuperDay, it's common for a candidate to meet 1-2 colleagues they'd end up working with for a short (~30 minute) call. We call this a peer team interview. It gives the candidate a chance to meet the wider team and get a feel for the culture, and it gives colleagues a chance to ask questions and test cultural and technical fit.
The colleagues who join don't have to be from the immediate team the role sits in. For example, for a Product Marketer role it's common to have a peer team interview with another Product Marketer, as well as a Product Manager from the team the new role would join.
If you're joining a peer team interview, use the time to test cultural fit, technical knowledge, and taste. Arrive with some questions in mind that let you do this. Don't use the call just to check the candidate's overall vibes — that only leads to surface-level feedback, and leaving feedback that amounts to "this candidate seems nice" isn't useful.
Peer team interviews should also give the candidate time to ask their own questions and explore whether the team and culture are a fit from their perspective. It's a two-way conversation, not just an assessment.
Reviewing the SuperDay output itself is _not_ part of a peer team interview. That review is owned by the hiring manager and Small Team lead, who are the most calibrated on what good output looks like and who ultimately own the hire.
Peer team interviews are optional — hiring managers don't need to include them. We don't run them by default for engineering roles, for example, but we generally find them helpful for marketing, CS, and sales roles, where they're useful for catching red flags as well as testing fit.
Decide if we will hire
We aim to make a decision within 48 hours of SuperDay - being decisive is important at this stage, as great candidates will probably be fielding multiple job offers.
After a SuperDay, everyone involved in the day leaves their feedback on Ashby. This is hugely important to us in making a final decision so team members should make an effort in completing their feedback as soon as possible. If there are wildly different opinions, you should open an issue in company-internal to discuss.
If a decision is made to hire, the People & Ops team will open an onboarding issue once the candidate has accepted and James/Tim will share in our Monday All Hands Meeting a brief overview of the following:
Who we ended up hiring and their background: what they will be doing, and a summary of the recruitment process (how long open for, no. of applicants etc.)
Why we are hiring them: feedback from the interview process, both positive and areas to improve
Start date and location
Share the output of their SuperDay (if applicable)
If we don't make an offer, it's important to clearly outline to the candidate why that decision was made. Highlight what went well, but also mention specific points of improvement. Offer to schedule a call if they would like to discuss further. Make sure to leave the door open for the future so they can apply again in 12-18 months time as circumstances and people change.
Making the offer
Hooray!
The People & Ops team will prepare the offer details. James and Tim give final sign off. We then schedule an offer call with the candidate - this might be Charles, Fraser or a member of the people & ops team.
During the offer call, we'll share feedback from the interview process, and sell the opportunity here at PostHog. We will also briefly cover the offer details (salary, equity, benefits), and answer any open questions. Afterwards the person who made the offer will follow up with an offer email, outlining all the details. If a candidate is proving tricky to close, the team may escalate to James or Tim to help.
Once the candidate accepts, the People & Ops team will kick off the onboarding process and take the role offline, after rejecting all remaining candidates.
How Ashby works for interviewers
We pay Ashby per seat, so as an interviewer your access is limited to those candidates that you will interview, to save us some money. You will be able to see their application (inc cover letter), their resume and all previous feedback left about the candidate.
You will not be able to see every other candidate in the pipeline, this is because of the per seat pricing. However, we will keep a couple of seats aside so you can login to see other candidates in the pipeline and do a bit of profile/assessment calibration. If you would like to do this, please contact the talent team on slack and they can provision this for you. You won't keep this access forever but you can get it for a few days/ a week to get an overview of how some other interviewers are doing things.
Visa sponsorship
Building a diverse team is at the heart of our culture at PostHog, and we are proud to be hiring internationally. In some cases, this includes the need for visa sponsorship. We are currently only able to provide visas in the UK.
If the candidate is already in the UK on a visa (e.g. employed, youth mobility), or require a new visa to remain in the country (e.g. student converting to employed), we will cover the costs for any employee, new or current.
If they wish to relocate and need a visa, we unfortunately will not cover the cost for obtaining the visa or any relocation costs.
For employees where PostHog covers the costs related to obtaining a visa, the employee agrees to reimburse PostHog if they voluntarily terminate their employment prior to the completion of 12 months of service. The costs will be calculated on a monthly basis, so when the employee decides to leave after 10 months, they will have to repay 2/12 of the costs related to the visa.
If a candidate needs visa sponsorship, including sponsoring or transfer of H1B visa in the US, at this time, we cannot hire them.
E-Verify
We participate in E-verify for all US new hires which allows us to verify employment eligibility remotely and continue hiring in multiple states. E-Verify is not used as a tool to pre-screen candidates.
Location
For some teams, it's important to have a wide range of timezones covered by the small team. This allows us to have closer to 24 hour coverage in case of incidents, and is particularly relevant for infrastructure or pipeline teams.
For teams working on a pre-product market fit product with no users, it is preferable to hire people within a few timezones of each other, so it's easier to get together in person and to do synchronous meetings if people wish to work that way.
Currently, we are hiring a lot – aiming to go from ~96 people to ~185 by the end of 2025. Our pace of hiring is the biggest blocker to shipping all the tools in one and driving our growth, so we need to go fast while keeping the bar high. Therefore we should _not_ restrict hires to certain timezones, even if in the short run a small team would prefer to have everyone closer together. This is because over the next six months, we'll have enough new people, that we can later re-org our teams to group people back together by timezone if needed as we have higher density of talent everywhere in the timezones we cover.
Internships
We regularly receive enthusiastic requests from students about internships, which we're always flattered by. Currently, we don't offer internships, placements or work experience - we’re a bit too scrappy to do them well right now.
That said, if you're still studying, there are other ways to work with us. Through PostHog for Students you or your student org can apply to host a PostHog event on campus - we'll send a team member for a mixer and a Q&A, plus $2,000 in cash and merch to run it (currently Bay Area universities and UC campuses in California). If your school isn't on that list, our community incubator offers cash grants to start a co-working group of builders in your city, wherever you are.
Once you ~~escape college/university~~ graduate, you're welcome to apply to full time roles via our careers page. Your details will then go straight through to our hiring team (who _are_ real humans, not AI) and you'll hear back from us shortly after.
Post-mortems
We won't get every hiring decision right. So when we do let somebody go in their probation period, or shortly after, we need to try and figure out what went wrong. This is why we hold post-mortems, these are not massive inquests into who is to blame, these are figuring out one or two high leverage things that we can introduce to the hiring process to improve it going forward.
The Process
Pre-work
The process will be owned by the talent partner that was responsible for the hire. It will also include the blitzscale team member and the team lead involved, where the team lead was not involved in the hiring process we will include the other main person involved in the hiring process.
The talent partner should create a private slack channel (mainly out of respect to the colleague who has left, the main results will be shared publicly) with everybody involved and share all the feedback from the hiring process. The Blitzscale member will share all the relevant feedback the team member received that led them to failing their probation. Once this is shared the following work should be prepped before the post-mortem call. The talent partner can share a google doc so everybody has access.
each interviewer involved should review the signals that they saw in the process and they discounted, any why. ~3 bullets is enough
each interviewer involved should also write the signals that were missed in the process, if any.
talent partner prepares ~3 bullets for where in the process is meant to catch the reasons the person failed their probation.
The team lead should also take time to consider the onboarding process and how that went
Did the in-person onboarding happen? Was it successful?
What potential flaws in their onboarding could have been improved?
The pre-work here is the most important part, the call shouldn't happen without this being done.
The Post-mortem call
The talent partner should remind everybody that we are here to fix the process, not re-litigate the decision or apportion any blame.
The first 10-12 minutes are about discusssing the pre-work and trying to answer two questions:-
what did we see but discount?
what were we not even looking for that we should have been?
Once agreed the second half should be focused on agreeing one or two fixes to the process that can be shipped. Try to avoid creating long lists as this is harder to implement.
post post-mortem call
The talent partner should write up the post-mortem and share it in the #team-talent channel cross-posting to #tell-posthog-anything. They should then update any handbook pages about the process and be sure to share any findings with the relevant interviewing channels like #technical-interviewers.
Our is small and we don't hire into this team very often. Please check our careers page for our open roles.
What we are looking for in marketing hires
Beyond the specific skills listed in the job description, we always generally look for:
Communication skills
Moreso than other companies, all of our communication is written and public for the world to see. Good written communication is key.
Are they opinionated? Do they avoid generic marketing-speak?
T-shaped people
We generally look for people who are generalists with a spike in one particular area, vs. specialists
We avoid people who are interested in building and managing a large team
Marketing hiring process
1. Culture interview
This is our standard culture interview with the People & Ops team. We will at this stage also ask for work samples or portfolios, to get a better feeling for the work a candidate has done in the past.
2. Technical interview and portfolio review
The technical interview round usually lasts 45-60 minutes and usually involves two of our team members. They will ask questions around background and previous experience, as well as some scenario-based questions. At the end, they will leave time to answer any open questions.
If relevant, we'll go through a candidate's portfolio.
3. Marketing SuperDay
The final stage of our interview process is the PostHog SuperDay. This is a paid full day of work, which we can flexibly arrange around your schedule.
The task will usually be actual marketing work, involving creating a piece of content or talking to customers, though we don't actually publish the work. We usually give a fairly open-ended task, where it is up to you to decide how you want to prioritize and tackle it.
A Marketing SuperDay usually looks like this (_there is a degree of flexibility due to time zone differences):_
Kick-off session
Meet the founders - Tim and James
Time to focus on the task, we can provide support via your personal Slack channel
Informal session with a few team members
Meet a few members of our team for a quick chat
Overall, you should spend at least 80% of your time and energy on the task and less than 20% on meeting people, as we will base our decision on your output of the day. However, we encourage everyone to use the Slack channel as much as needed for any questions or problems.
In line with our values and culture, you might get short replies like "step on toes" or "bias for action".
People & Ops at PostHog covers legal, finance, people and culture.
This is our smallest team, and we don’t hire very often. That means that each new hire has a disproportionately high impact compared with other, larger teams. Please check our careers page for our open roles.
What we are looking for in Operations hires
Outside of the skills listed in the job description, we are generally looking for:
Warmth and positive energy - the kind of person that other people _want_ to ask for help
Proactive and organised, with a strong attention to detail
Ability to prioritize
You are not afraid to step on toes - you have a bias to action and lots of initiative
Top-notch communication skills, setting an example to the rest of the team
Willingness to dive in and learn technical concepts and engage with tools like GitHub
Operations hiring process
Culture interview
This is our usual first round interview with a member of the People & Ops team.
Technical Interview
The technical interview usually lasts between 45-60 minutes and you will probably meet a member of our as well as Charles. For this round, you can expect questions about your background, together with scenario-based questions.
Operations SuperDay
The final stage of our interview process is what we call a PostHog SuperDay. This is a paid full day of work, which we can flexibly arrange around your schedule.
We will share the task with you at the start of the day. The task is representative of the work someone in this role at PostHog is doing, and it is always the same for each candidate, so we can make clear comparisons. It will typically involve doing actual PostHog work, e.g. sourcing candidates or planning an offsite.
An Operations SuperDay usually looks like this (_there is a degree of flexibility due to time zone differences):_
Kick-off session
Meet the founders
Time to focus on the task, we can provide support via your personal Slack channel
Informal session with a team member
Meet a few members of our team for a quick chat
Overall, you should spend at least 80% of your time and energy on the task and less than 20% on meeting people, as we will base our decision on your output of the day. However, we encourage everyone to use the Slack channel as much as needed for any questions or problems.
In line with our values and culture, you might get short replies like "step on toes" or "bias for action".
Our Sales and Customer Success teams look after customers paying $20k a year or more for PostHog, as well as new customers who _may_ end up in that bucket. The job of the teams is to land and expand usage of PostHog in these customers. We have the following roles on the Sales and CS team:
Technical Account Executives focused on closing new business from inbound and outbound leads
Technical Account Managers focused on expansion from existing customers and closing new business from product-led leads.
Customer Success Managers focused on the retention of customers using all of our products already.
Onboarding Specialists focused on ensuring newer and smaller customers are set up for success with PostHog.
Forward Deployed Engineers focused on getting embedded with customers to fill the gap between what PostHog does and what the customer needs.
We've proven that the way we do sales works at a small scale, we are now growing the team in line with increased top-of-funnel growth for PostHog. Please check our careers page for our open roles.
What we are looking for in Sales and CS hires
Outside of the skills listed in the job description, we are generally looking for:
Technical aptitude - our team members are the primary person responsible for the customer relationship, and that includes solving technical problems.
Great interpersonal skills - we need people that our customers are excited to work with.
A genuine passion for helping customers be successful.
Prioritization skills - you'll be working with a book of business at different states and will have to prioritize your work accordingly.
People who are motivated by revenue growth.
How we evaluate candidates
We need to be particularly sensitive to culture at this stage. We can handle someone underperforming much better than someone who is a poor culture fit due to the impact on the broader team. We don't want to end up taking cold leads from BDRs so we can run MEDPICC from our car phone while promising 50% discounts if they sign before the next full moon. We want someone who is comfortable carrying a sales conversation while also possessing the technical chops to talk to engineers and get their hands dirty.
We want someone who can own technical problems and even if they don't have the answer, understand enough of the context to provide that to engineers. We want someone who sees themselves as the first line of defense for our engineers, because engineering time is valuable; it's a win when they can solve a problem without additional engineering lean in.
A great litmus test for a candidate is if they are comfortable instrumenting PostHog and can speak to how they actually implement it on a site. That's typically a good indicator that they've got the right technical prowess.
We want someone who is in it to develop customers for the long run, we don't want someone who is here for quick churn and burn to pump up quota attainment. Building a relationship with a product engineer requires actually knowing PostHog, not just knowing about PostHog.
Ultimately, we want someone who we'd want to buy from.
Sales and Onboarding hiring process
Culture interview
This is our usual first-round interview with a member of the Talent team.
Technical interview and demo
The technical interview with the relevant team lead usually lasts ~45 minutes. How we run it depends on the role you're interviewing for.
Technical Account Executive (TAE)
For TAE candidates, this session is structured around a consistent set of questions that we ask every candidate, so we can make clear comparisons. The questions are designed to understand your skills, your experience, and how you think about the role — including how you approach prospecting and closing new business, how you handle technical conversations with engineers, and how you think about building long-term customer relationships. After we've worked through the questions, we'll leave time at the end for you to ask anything that's on your mind.
Technical Account Manager (TAM)
Part of this session will be a demo role-play so that we can assess how you talk about your current product to a prospective customer who knows nothing about it. You can assume that the customer is a prospective buyer but otherwise knows nothing about your product, and you should approach the demo as if they were a real prospective customer. What we care about here is not the content of the demo, but seeing how you'd interact with a prospective customer. After a short introduction, we will jump into questions for 25-30 minutes, and then move on to the role play where you should aim to present and demo your product for 15-20 minutes with 10 minutes. After this, we will allow you to ask anything that's on your mind.
Culture and motivation interview
In this 30-minute interview, you'll meet with Ben, who will be trying to answer "Are they a good cultural fit for the Sales team at PostHog?".
Sales and Onboarding SuperDay
The final stage of our interview process is what we call a PostHog SuperDay. This is a paid full day of work, which we can flexibly arrange around your schedule.
We will share the task with you at the start of the day. The task is representative of the work someone in this role at PostHog is doing, and it is always the same for each candidate, so we can make clear comparisons. It will typically involve doing actual PostHog work, e.g. prioritizing customers, doing a demo, etc.
A Sales and CS SuperDay usually looks like this (_there is a degree of flexibility due to time zone differences):_
Kick-off session
Meet with Tim, who will be trying to answer "Would I buy from this person?"
Meet with Ben, who will be doing a culture and vibe check.
Time to focus on the task, we can provide support via your personal Slack channel (use the channel, don't slide into people's DMs)
PostHog demo role-play with the team lead
Meet a few members of our team for a quick chat
Overall, you should spend at least 80% of your time and energy on the task and less than 20% on meeting people, as we will base our decision on your output of the day. However, we encourage everyone to use the Slack channel as much as needed for any questions or problems.
In line with our values and culture, you might get short replies like "step on toes" or "bias for action".
Customer Success hiring process
Culture interview
This is our usual first-round interview with a member of the People & Ops team.
Small Team interview
The small team interview with the relevant team lead usually lasts 45 minutes. For this round, we will use scenario-based questions to assess your technical and customer skills, as well as your knowledge of PostHog. As part of this, we will ask you to give a quick pitch of PostHog (not a full demo).
Culture and motivation interview
In this 30-minute interview, you'll meet with Simon, who will be trying to answer "Are they a good cultural fit for the Sales team at PostHog?".
Customer Success SuperDay
If you've been invited to a PostHog SuperDay, here's what to expect and how to set yourself up for success.
What the SuperDay looks like
The SuperDay is a paid full day of work (1,000 USD). You'll receive some tasks at the start of your day and submit your work at the end. While you won't be working with real customers (which would be risky!), the tasks are meant to be as representative as possible of a day in the life of a CSM at PostHog. Expect to spend the majority of your day on them.
Scheduled throughout the day, you'll also have:
A kick-off call (30 min) - a session with Dana or Phil to go over the task for the day!
A product demo (30 min) - a session spent understanding your demoing style, your comfort with PostHog, and with ambiguous situations.
A peer team interview (30 min) - a session dedicated to team members to get to know you, and for you to ask as many questions as you have!
A short chat with a co-founder or exec - a brief conversation about culture and motivation.
You'll also have access to a dedicated Slack channel with the team throughout the day. Use it - share progress, ask questions, surface blockers.
Install and get familiar with PostHog - you'll be expected to have a good understanding of PostHog going into SuperDay.
During the day
Communicate proactively. Share progress updates and blockers in Slack. Ask clarifying questions early if something is ambiguous. Don't wait until you're stuck for hours.
Divide your time between all of the tasks (don't finish the day rushing to complete one because you thought it wasn't important).
Act as if you would with a real customer. We want to test how you engage with folks when you are their Customer Success Manager.
What not to worry about
Perfection. We don't expect you to finish everything to a super polished standard. We care about the quality of what you ship, the decisions you make, and how you work under constraints.
Not knowing something. You're free to make as many assumptions as you need, as long as you keep a record of them. You're also very welcome to ask questions in the Slack channel, but make sure to trust your skills and gut!
Getting stuck. Everyone gets stuck. What matters is what you do next. Ask questions. Try a different approach. Talk through what you're thinking.
In line with our values and culture, you might get short replies like "step on toes" or "bias for action".
A note on AI tools
You can use AI tools during the day - we know this is how many Customer Success Managers work. There is a line between using AI effectively and overusing it; we want to test that out as well.
What comes next
After the SuperDay, everyone involved will leave their feedback. We aim to get back to you with a decision within 48 hours.
If you've made it this far, good luck - we're rooting for you!
Hogpatch is our San Francisco coworking space, shared with a handpicked group of YC founders who are active PostHog users. Teammates in the Bay Area (or visiting) are welcome to drop in regularly to work, meet users, gather feedback, or join events we host in the space. Here’s a quick guide to how it all operates.
Judy Opperwall, our Office Manager, is on site Mondays to Thursdays from 9am–5pm. For any issues while she is not in, please reach out to the hogpatch channel or DM her directly.
---
Setup and logistics
Building access
PostHog teammates don’t need an invite to use Hogpatch – the space is open for you whenever you’re in town. If you know your SF travel dates in advance, it’s helpful to post in the sf-bay-area channel so we can make sure the space is ready for you.
If you are visiting for the first time, ring the black intercom doorbell on the front door.
Judy Opperwall will be notified and will remotely unlock the door for you.
Carol Donnelly and Scott Lewis also share intercom access so can open the door for you 24/7.
There’s no check-in or reservations needed, it's a very relaxed setup.
---
Parking
We have a garage in the building that allows up to 4–5 cars max.
This is for internal employees only, and spots are limited.
Please ask Judy Opperwall if you’d like a fob. If you're driving in as a one-off, let Judy know beforehand so she can let you in/out on the day you visit. Always remember to close the garage door when leaving the premises. If you're worried you have forgotten, Judy can double check this via CCTV.
---
Housekeeping
If you notice anything missing or that needs replenishing, reach out to Judy Opperwall on the hogpatch channel.
A cleaner is scheduled to come in once a week to tidy up and water plants.
A gardener comes in every two weeks to maintain the plants around the space.
---
FYIs
Please turn off the lights in the building if you’re the last to leave for the night. The phone booths have lights that will automatically turn off.
Remember to lock your laptop when you step away from your screen.
If you see unfamiliar faces (that don’t look like YC founders), raise any concerns with Judy.
---
Understanding how YC founders use Hogpatch
We’re able to curate the best experience for founders by making iterative upgrades with each batch that compound over time. We do this by understanding how the space is _actually_ used across each 12-week cycle. You can follow real-time usage on the internal tracker.
At the end of each batch, Judy Judy Opperwall wraps things up with a retro, documenting what worked and what didn’t. This proposes all the improvements that should be made ahead of welcoming the next wave of YC founders.
Hogpatch is our dedicated coworking space in San Francisco for YC founders in the current batch - a lofty, airy, light-filled warehouse just around the corner from YC. It's invite-only and open 24/7, giving you a reliable place to work whenever you need it. We've set it up because we know how valuable a quiet space is when you're bouncing between office hours, customer calls, and late-night sprints.
Hogpatch is a free space to help your batch experience a little easier. There's no catch! We're not here to sell you PostHog. We hope that this becomes a dependable home base in the Dogpatch neighborhood for when you need one.
What's Inside
24/7 coworking space: bring your cofounder and get heads-down in deep product work or last-minute demo day prep.
10 Gbps fiber internet: the fastest wifi in the neighborhood to help you build at lightning speed.
Private desks and high-res monitors: space to work comfortably and focus without distraction.
Comfortable phone booths: quiet spots for user feedback or investor meetings (and perfect for quick calls).
Events space: occasionally used for founder-focused gatherings, but most of the time open as extra room to spread out.
Snacks, coffee, and extra comforts: endless caffeine on tap.
Getting Started
Access
Hogpatch is invite-only, and isn't open to the whole batch. We keep numbers low so it stays calm, focused, and actually useful. When space opens up, we handpick a few YC companies to join. If we want to tap you on the shoulder with an invite, you'll hear from us directly.
We do maintain a waitlist, but you can't apply - we handpick founders when there's room to welcome more.
Each invite lasts 3 months. If you join at the start of your batch, that'll usually cover you through demo day. If you join later, you're still welcome to keep using Hogpatch after your batch ends.
Passes
Once you've been invited, Judy (our office manager) will send you and your cofounders a digital wallet pass. The pass gives you 24/7 self-service access to the space, ideal for late-night sprints or weekend hacking sessions. You can come in anytime, day or night. There's no check-in or reservations needed.
Location
Hogpatch is just 100 yards from YC's office, with the nearest Muni stop at 20th Street. You'll find us behind a discreet door off 3rd Street - the exact location is listed on your digital wallet pass. Scan your pass on the front door QR reader to get in, or buzz the intercom for help.
Support
You'll bump into our product engineers from time to time. They're in the space because they enjoy chatting with founders, and they're happy to give product feedback or help set up your dashboards ahead of demo day.
Judy Opperwall, our office manager, keeps things running smoothly 9am–5pm, Mon–Fri. Outside those hours, treat the space like it's your own. If anything urgent comes up, Judy's your go-to. Her details are in your welcome email.
Workspots & hangouts
Desks & phone booths - no booking system, no hassle. Just grab a spot when you arrive.
Visitors: you're welcome to bring in customers, investors, or anyone else you need to meet with, but the space is dedicated to working so we ask you not to bring friends or un-invited YC founders. The space is yours to use - just don't host a house party here.
Events: every few weeks we'll host something in the space. You're welcome to stick around or join in, but we'll always do our best not to disrupt your focus.
Are you trying to sell me PostHog?
Not at all. Hogpatch is a perk for select YC founders who already know us through the Bookface deal. We know you're focused on building your company, not listening to pitches - so think of this space as a convenient homebase whilst you're hopping around the Dogpatch area, not a sales funnel. We went through YC too, and wanted to create a space that takes off some of the stress whilst you're going through a batch.
Offboarding team members is a sensitive time. The aim of this policy is to create transparency around how this process works. This offboarding policy _does not_ apply to regular contractors who are doing short term work for us.
Voluntary departure
In this case, the team member chooses to leave PostHog.
We ask for 30 days of notice by default (unless locally a different maximum or minimum limit applies), and for team members to work during that notice period. This is so we have some time to find someone to hire and to enable a handover. Please assume by default we will expect team members to work all of this period.
If you are a current team member and you are thinking about resigning from PostHog, we encourage you to speak with your manager or the to discuss your reasons for wanting to leave. While we don't want to persuade anyone who is unhappy to stay, you may find that the best solution involves changing things here at PostHog, rather than going somewhere else. If resignation is the only solution after you have discussed your concerns, please send an email communicating your intention to resign to people@posthog.com. We will then start a discussion around what is needed for the handover.
Involuntary departure
In this case, we are letting the team member go.
This is generally for performance reasons or because the company's needs have changed and the role can no longer be justified. If the decision is down to performance issues, we will have already communicated feedback to the individual and given them time to take the feedback on board. However, performance issues sadly can't always be resolved, which means we might ultimately need to end someone's employment.
Tim and James are responsible for making any final decision to let someone go.
We use the following general process for managing people whose performance isn't up to the right standard. We modify this slightly depending on the specific nature of the role and how long they have been at PostHog, so the process isn't identical in every case:
Typically, a manager or member of the exec team will raise that a team member isn't meeting our performance expectations. They discuss what the issues are and a plan to improve. The relevant exec team member follows up with the person's manager.
The person's manager has a meeting with the team member to let them know explicitly that their performance is not meeting expectations, and that if it continues then they will not be able to continue at PostHog. This meeting may include a member of the exec team, depending on role.
If the person is a manager, we usually collect feedback from their team beforehand.
We outline to the team member exactly what good performance looks like. We collaborate with them to come up with a plan (e.g. specific things to ship), and a timeline for improvement. Usually this is a few weeks for someone new to PostHog, but may be longer if the person has been at PostHog for a while. We schedule a time for a follow up conversation at the end of this period.
If the person doesn't accept the feedback at the time and/or we don't feel like there is a realistic path to them improving, we may follow up to let them go sooner than this.
At the follow up meeting, we either confirm that performance has improved and they are on the right track, or that we have decided to let them go right away.
In cases where a team member's role can no longer be justified, we usually make a decision as an exec team and then let the team member know straight away - unfortunately it is not feasible to let someone know that we are thinking of getting rid of their role.
In either case, we will usually ask the team member to stop working immediately. Final pay and severance are calculated as below.
If a team member wants to resign but is deliberately trying to get let go so that they receive 4 months' severance, we may treat this as a material breach of your employment contract, which is gross misconduct. In such cases, team members are not eligible for any severance beyond the statutory minimum where they live.
Communicating departures
In the case of voluntary departure, we will ask the team member if they wish to share what they're up to next with the team. If you have resigned, please speak to the relevant team Blitzscale member to agree on who will communicate you are leaving. Please don't announce your resignation until the relevant member of the Blitzscale team has given the go ahead as they may need to prepare accordingly for the impact of your resignation.
In the case of involuntary departure, we will aim to be as transparent as possible about the reasons behind the departure, while respecting the individual's privacy.
Please be aware that PostHog cannot always provide context around why people are leaving when they do.
References and employment verification
At PostHog, we keep things simple: we don’t give personal or professional references for former team members. When someone asks about a past or current employee, the only information we share is their dates of employment.
Expectations for current employees: If someone contacts you directly about a current or former employee:
Don’t answer the request yourself — just forward it to the People & Ops team.
Don’t share opinions or details about someone’s performance or why they left.
Don’t speak (or appear to speak) on behalf of PostHog.
This helps us keep things consistent and protects everyone’s privacy.
The offboarding process
For team leads
If a team lead has resigned, the Blitzscale team should figure out who will take on the team lead responsibilities and have that prepared to let the team know just before the resignation is announced or as part of the announcement.
For involuntary leavers, we will schedule a call. During the call, someone on the ops team will be on hand to deprovisioning accounts. This is run through our access management tool Zluri. For any steps that require manual completion, team members will received a slack message from Zluri to complete the step and confirm when it has been done.
We will then send over an email covering the following points with the team member:
Final pay
Share options vested
Company property
Business expenses
Personal email to the company (optional)
Final pay
Final pay will be determined based on length of service and the reasons for leaving:
If the offboarding is voluntary, they will be paid up until their last day. We will look at the amount of holiday taken in the last 12 months and will pay any "unused" vacation pay assuming they would have taken 25 days (since we offer unlimited vacation periods).
If the offboarding is involuntary and due to performance reasons or a change in business needs, they will receive 4 months of pay. This includes any notice period we’re legally required to provide. To qualify, they must have been at PostHog for at least 3 months (6 months for sales roles). For our teammates in Germany who’ve been with us for at least 6 months, we’ll follow local laws and standard market practices for notice and severance. If they have been with PostHog for less time, they will receive 1 month of pay. If you are a US team member, PostHog will continue covering healthcare costs through the end of the next calendar month after your termination, regardless of your tenure or severance length.
If the offboarding is involuntary and for gross misconduct, including breach of contract, they may be paid the statutory minimum required only, and receive no notice. This is at our discretion depending on the circumstances.
We ask departing team members to sign a post-termination certificate, separation agreement or release in order to receive payments beyond their final day of work. If we do not receive this, then we will only pay in line with statutory and contractual requirements.
Please note that if there are local laws which are applicable, we will pay the greater of the above or the legally required minimum.
Share options vested
If a team member has been allocated share options, we will confirm how many have vested and the process by which they may wish to exercise them. We have a team-friendly post-departure exercise window of 10 years, and most team members who leave will be deemed a 'good leaver' unless they have been terminated due to gross misconduct.
Offboarding checklist
This is maintained as an issue template in GitHub. The People team will create a new offboarding Issue for each leaver.
Giving a new joiner a great onboarding experience is super important to us. We want new joiners to feel they’ve made the right decision to join us, and that they are excited and committed to what we’re doing as a company.
Our team is spread across the world, and so are our new joiners. In order to ensure the best possible onboarding experience, we aim for the new joiner to meet up with someone from their team in their first week. Depending on the new joiner's location, they might fly out to one of our team members, or the other way around. So the onboarding experience will look a little bit different, depending on where the new joiner is based and which team they will be joining.
Onboarding email
We send an introductory email to all new hires to welcome them to the team and ease them into some of the essential actions we need them to take. Once they've completed their items and signed their contracts, People & Ops will get them onboarded into their initial accesses and onboarding channel.
Once you've joined PostHog, we will not use email for communicating with each other. For example, James or Tim will never ask you to do something critical over email only – they'll always confirm it over Slack, and so will everyone else. Be extremely cautious of direct emails from James, Tim, or other people of PostHog.
The onboarding email is sent by the People team directly. We want to strike a balance between sending attractive, personalized emails and avoiding creating process or using overpowered tools, such as Customer.io or Mailchimp. So, we landed on a simple email with the necessary links.
<p>This doc is a suggested template with important actions specified, though we recommend personalizing it to the individual. We've linked to these as docs and direct images to make the formatting easier for you, but here is an accompanying image for use in emails.</p>
Image: onboarding image
Onboarding checklist
Once your accounts are set up, you'll get a welcome message in your onboarding channel with a link to the Ops Platform to get started. Everything you need to do, including the role-specific tasks your team adds, is tracked there in one place. When you first log in, you'll land on a welcome page with a short set of preboarding tasks, and your full checklist lives on your employee profile.
Onboarding buddy
Every new joiner at PostHog has an onboarding buddy, usually the team lead. If the team lead can't take it on (timing, leave, etc.), they'll arrange for another team member to be the buddy instead. Whoever it is, please make sure you don't have any leave booked in the week before and the two weeks after the new starter joins.
If possible, a new joiner will meet their onboarding buddy in person during their first week. In case in-person onboarding isn't an option, we will make alternative arrangements. They can help with questions that pop up and with socializing during the first couple of weeks at PostHog. Of course, everyone is available to help, but it's nice to have a dedicated person to help.
Each new joiner will have a dedicated Slack channel just for onboarding, named #onboarding-[who]-[team]-[month]-[year]-[where]. The team lead and the People & Ops team are automatically in there. Other team members who will be involved in the onboarding can choose to join or be added to the channel as well.
It's the best place to ask questions during your onboarding and first few days. Once you've signed your contract, we'll get you set up with everything you need to hit the ground running: your PostHog Google account and email, Slack, GitHub, a company card, access to the ops platform, and the tools specific to your role.
Your GitHub invitation may arrive separately from your Google and Slack invitations. Ask People & Ops in your onboarding channel when to expect GitHub access.
Guidance for onboarding buddies
Say hi to your new joiner in their onboarding channel and decide together where and when the in-person onboarding will happen. Request a budget through the Slack offsite app /offsite! For the budget and travel, see In-person onboarding.
Please make sure you spend at least 3 days together, working through the first week onboarding list and spending time working on any role-specific tasks that are outlined in the new joiner's personal onboarding checklist.
Make sure to add the details of the in-person onboarding to the In-person Onboarding Calendar so that other PostHog team members can join, if possible. Simply create an event in your calendar and then invite the in-person onboarding calendar as a guest.
You will remain the new joiner's main point of contact for the first few weeks, so please continue to check in with them at least once a week for the first month or so.
As onboarding buddy, you are responsible for making sure the onboarding is fun and effective, so you should make sure there's a clear plan for work _and_ social time. Great in-person onboarding is crucial for getting someone started at PostHog.
The plan doesn't need to be minute-by-minute, but do have a rough shape for the days you're together so the new joiner isn't left wondering what's next once the initial intro conversations are done. A little structure goes a long way, and still leaves plenty of room to explore and learn by doing.
Point the new joiner to the handbook early and talk through why it matters – it's how we default to sharing context at PostHog, and knowing their way around it is one of the most useful things they can pick up in week one.
Not run an onboarding before? That's completely fine – ask the People & Ops team or your team lead to pair you with someone who's done it before to support _you_. It's much easier to give someone a great start when you're not figuring out what "great" looks like at the same time.
In-person onboarding
Except under special circumstances, new joiners meet with members of their team in-person to go through the onboarding process. With very few exceptions (visa issues or excessive travel time), in-person onboarding should happen at Hogpatch in San Francisco or the Hedge House in London. Both are set up for it, remove most of the planning friction, and you'll always be in the same space as other PostHog teams — which is way more fun, and means you'll meet more people. Regardless of location, everyone should have their own bedroom.
To stay at the Hedge House London, book a bedroom through the @HedgeHouse London app via Slack; booking a room automatically reserves you a desk for the week. Message Kendal with any questions.
While there is no fixed budget for onboardings they should be relatively less expensive than a small team offsite, which is $2,000 per person. Some considerations to reduce the cost:
Avoid intercontinental travel or choose a location that limits it to the minimum number of people possible
Consider doing more casual social activities that are less expensive: dinners, drinks etc
You can request budget for the team lead +1 more team member as an onboarding budget using the Slack command /offsite. Any other team members joining can use their working together budget (be mindful that onboardings are distracting so the more team members you have join, the less productive the team will be that week, you also have offsites for the team to all get together).
The new team member already has their own onboarding budget to book their flights and accommodation, so do not include them in the budget.
See if there are any other onboardings at the same time you could pair up with
Aim to keep things sensible and cheap. As always, use your best judgement when spending money. There will of course be some exceptions to this, please just include the reasoning in your Brex budget request, and ensure to list who the budget request is for.
You should by default avoid combining in-person onboarding with small team offsites as they serve different purposes. The focus of onboarding is generally on making the new team member successful, but offsites feature things like hackathons and 360 feedback which aren't usually helpful for this and detract from useful onboarding time. However, it may occasionally make sense to combine the two - just use your judgement.
It is important that you make the most out of the sync time with the new joiner on your team. You should not spend the whole week sitting next to them doing your usual work. Having something planned each day is sufficient, some ideas include:
An intro to PostHogs values & strategy
A history of your team, your current quarterly goals and a product demo of the features you own (product teams only)
Interview feedback session between the team lead and new joiner
Deep dive into a specific feature where you walk through the code (product teams only)
Mock demo (sales team only)
"No stupid questions" where the new joiner is expected to come with questions they had since starting
Your first week
Your first week can definitely be a bit overwhelming at any new company, so here's what you can (roughly) expect!
You will meet (either in person or virtually) your team lead to discuss goals and aims over the next 30/60/90 days and beyond
You will get all your equipment set up and get access to all the accounts you need
You will receive your new hire kit (which includes No Rules Rules which we encourage everyone to read as it gives you a great insight into how we work as a company)
You should try and set up a few calls with a range of people to introduce yourself
You should try and speak to some actual users of your product. Your team lead or PM will help you set these up, and this can be a great source of things to work on in your first week.
You should dive straight in, fix a typo in the handbook, ship a tiny bug fix, anything to get you going!
If your laptop is delayed: In rare cases your PostHog-issued laptop may not arrive until several days after your start date. If that happens, you can begin non-sensitive onboarding tasks (reading the handbook, intro calls, etc.) on your personal laptop in the meantime. Treat a personal laptop as less trusted:
- Do not access production cloud environments (AWS, GCP, etc.) from it.
- Do not store or handle any secrets on it, including secrets used for local development.
Move anything sensitive to your company laptop as soon as it arrives.
Engineering
We hire engineers on a regular basis, running in-person onboarding practically every time. Over the years, we've learned a lot about doing this efficiently and there's much to gain from sharing the knowledge between teams.
Based on this ongoing learning process, here are our five rules for onboarding an engineer:
Ship something together on day one – even if tiny! It feels great to hit the ground running, with a development environment all ready to go.
Run 1:1 learning sessions with the new teammate every day. Give them all the context they need to succeed. By the end of the onboarding, each team member present should've run at least one such session.
<summary>Looking for learning session ideas?</summary> <p>Here's a non-exhaustive list:</p>
<li>The <a href="/handbook/engineering/databases/event-ingestion">lifecycle of an event</a>, from a client library all the way to query results</li> <li>How we turn all our TSX and SCSS files into a fast frontend served from S3</li> <li>The architecture of PostHog Cloud</li> <li>Trunk-based development - how we make use of feature flags</li> <li>Query nodes and how they're used throughout the app</li> <li>What the dead letter queue is for</li> <li>How PostHog experiment results are calculated</li> <li>What engineering planning looks like at PostHog</li>
Any of these chats can take as little as 15 minutes or as long as 1 hour, depending on the level of detail. You'll also find that some topics apply perfectly in some teams, but not so much in others. This is all up to you!
Do at least one brainstorming session on a topic important for the team, writing down actionable conclusions. Use the time together to discuss issues and involve the new joiner in decisions.
Pair whenever possible. You're all sitting next to each other, so pick work that can benefit from in-person collaboration.
Have fun, because life isn't all work! Do some sightseeing, go out for dinner, or find a fun activity – just hang out together any way you like.
Tools we use
We use a number of different tools to organise our work and communicate at PostHog. Below is a summary list of the most important ones - this list is not intended to be exhaustive
Everyone
PostHog ops platform (ops.posthog.dev) - onboarding, employee profiles and people ops
Google Suite - Gmail, Google Apps such as Docs, Sheets, Slides
GitHub - most comms and product work
Slack - we have an internal workspace and a users Slack as well
Brex (US, RoW) or Revolut (UK, EU) - company cards and expenses tracking
Shopify - powers our merch store
Time off by Deel (Slack App) - holiday tracking
Bamboo HR - payroll and benefits (US)
Deel - contractor & EOR payroll & HRIS
Engineering
AWS
Incident.io
Heroku
Grafana
Design
Figma
Ops, People & CS
Salesforce - customer CRM
PostHog Support - our support platform
Mosaic - financial modelling
Carta - cap table management
Fondo - US accounting
Deel - international payroll and contracts management
Product Internal - product-related issues that need to be kept internal, e.g. security issues, customer-specific issues (private)
Company Internal - company-facing issues, e.g. internal processes, hiring planning (private)
When you have a new Issue or want to submit a Pull Request, you do that in the relevant repo.
We use GitHub Projects to track the status of Issues in an easily viewable way. When you create an Issue, you can assign it to a Project - think of a Project as a way of organising and filtering Issues in a particular view. This makes it easy for Small Teams to easily track what they are working on without having to jump between different repos. Some Issues may be assigned to multiple Projects if they involve the work of more than one team.
You can also assign an Issue to a specific person, and tag it with a relevant label - use these to help people filter more easily.
Each Small Team has its own Project for tracking their Issues - full list here. Most teams run two week sprints - as part of onboarding, you will be invited to the relevant planning meetings.
Support hero training
Employees are occasionally called upon to act as support heroes, or need to deal with support tickets that are escalated to them. This most often applies to engineers, but can include any employee regardless of their team. For this reason, we need everyone to have a broad idea of our support processes and know how we deal with customers.
In this call the support engineer will be able to answer any questions, as well as demonstrate how we deal with support at PostHog. In particular, the support engineer should cover:
[ ] When to use private notes, and raising internal questions about a ticket in Slack
It can be especially helpful for new hires if support engineers demonstrate how to solve a few simple tickets from start to finish, through shadowing.
30/60/90 day check-ins
Team leads are responsible for helping their new members navigate the first 3 months probationary period. There is a strong importance on 1) providing feedback to the new team member, and 2) communicating with Blitzscale about unresolved performance issues, so that there is enough time for action. Team leads are, again, not responsible for hiring or firing, nor communicating these possibilities directly to teammates - this is handled by the Blitzscale team, and is frankly a very rare situation - the vast majority of people we hire do pass their probationary period!
Team leads will receive an automated feedback form at the 30, 60, and 80 day marks. It's a reminder these checkpoints have arrived and a chance to provide feedback and make sure everything is on track for the probationary period to be passed.
30-day checkin
Team lead provides 30-day feedback to the team member - especially if there is constructive feedback that needs to be given to ensure the person passes probation.
It's also a good time to reinforce the positive work that has been done by somebody on the right track.
60-day checkin
Team lead provides 60-day feedback to the team member - if things are going well, this is a good time to give an indication, which can ease any concerns the team member may have.
Blitzscale team will get involved as necessary to provide an additional layer of feedback to the team member.
80-day checkin
Final feedback checkin before probation ends - provide any extra feedback, though things _should_ feel like they're humming at this point.
Any outstanding concerns should be raised with Blitzscale team
90-day
We've made it! By default, there isn't a formal company side 'you passed' communication - by this point, the team member should already have a clear understanding through the prior checkins.
Feedback is a really important part of the onboarding process and as a team lead it's a good idea to ensure the new team member receives feedback from their peers - either from you collecting it or them receiving it directly from their peers. It won't always be possible or necessary to do a 360 feedback session within the first 3 months, so it's up to you as a team lead how best to approach that. As a team lead you can also have blind spots on performance, so checking in with their peers can be helpful and can be done during your normal 1-1s.
These check-ins are designed to ensure every new starter is set up for success. Every team lead will deal with these slightly differently, but it will hopefully be clear to everybody by around the 60 day mark how things are going and what needs to be worked on, if anything. It is important for a team lead to ensure that they do not wait for one of these check-ins to communicate with a Blitzscale team member that there could be issues with the team member passing probation. They should let them know immediately, so that a fair and reasonable plan can be put in action ASAP.
If you have any issues or any feedback on how to improve a specific intro just post in the #team-people-and-ops slack channel and tag the relevant people
Finding answers at PostHog
Need help finding something? We have a strong culture of self-sourcing answers - it helps you get unblocked faster and builds your intuition for where things live. Start with #ask-max, our AI that's read every handbook and documentation page. It'll point you to relevant docs instantly and is available 24/7.
Of course, if you're stuck or need context beyond what's documented, just ask in the relevant channel - people are always happy to help. The goal isn't to make you figure everything out alone, it's to give you the fastest path to answers.
Slack Channels
Below are a list of Slack channels you may find helpful:
Work-related channels
#ask-max - Max has access to all of our documentation and our handbook, and is a great place to start with many questions
#ask-posthog-anything - ask the team when you cannot find an answer in the handbook, the docs, or #ask-max
#tell-posthog-anything - company-wide announcements about our people, products, policies, and projects
#at-posthog-anything - tag ``@posthog`` to draft PRs, pull usage info, or surface content from the handbook
#general - see new starters, work anniversaries, birthdays and all-hands recordings
#changelog - keep up with all the cool things we're shipping across the team
#today-i-learned - where we share what we learn
#demo-posthog-anything - show the team something you built, or see what others are building
#phishing-attempts - report suspicious emails, texts, and messages here
#content-and-video-ideas - for suggesting ideas for the newsletter, tutorials, and docs to be written by the content and docs team
#flakey-tests - reports of tests that fail intermittently in CI
#incidents - incident declarations and post-mortem summaries. Set this channel to notify you about every message
#alerts - company-wide alerts. Teams also have their own #alerts-[team-name] channels
#support-infrastructure - deployment problems, infrastructure questions, and requests for cloud access
#aws-access - use the /awsaccess command here to get temporary AWS permissions. See cloud providers
#papercuts - small product annoyances that anyone at PostHog can report. Your team's support hero picks up the ones in your area
Every small team also has a #team-[team-name] channel and a #support-[team-name] channel, named after the team on the teams page. Join the channels for your own team, then add the teams you work with most.
Social channels
We encourage you to join and create channels focused around different types of hobbies and interests. We explicitly don't allow channels based on categories that we legally (and rightly!) can't discriminate against in the hiring process, such as gender, sex, political affiliation, religion, and age.
Join wherever you're based, plus anywhere you travel often - posting in these channels is the easiest way to find teammates for a coffee, a coworking day, or dinner while you're in town.
The Ops team's primary goal is to make PostHog an incredible place to work by removing distractions from other small teams. We keep PostHog running smoothly without implementing lots of unnecessary processes.
We are also responsible for growing the team by adding in world class talent to new and existing small teams. We want to do this while retaining our world-class team by making PostHog the most transparent company in the world, and the best place for people to work in general.
Ops provide all the tools, literally and metaphorically, needed for our team to come in and do their best work. Practically, this looks like:
A small ops team covering a wide range of disciplines that can react to any incoming items to allow the rest of the business to focus on what they do best - building products.
Nailing the basics of working at a start-up for our team members. Making sure things like payroll, onboarding, offboarding etc. all work smoothly and are on autopilot as much as possible.
Thinking slightly further ahead than the “here and now" to predict when we may need to make changes like hiring new team members, changing our spending patterns to manage cash, managing our comp structure, implementing a new tool etc.
Setting a very high bar for bringing people on board. We are always looking for the best people in their field, or people on their way to becoming exceptional at their jobs. This is so important to us, it's enshrined in our company values.
Manage compliance projects like SOC 2 or HIPAA to help us land larger customers. These projects require input from some small team members, but Ops will make sure everybody knows who and what is needed.
Partnering with the Exec team to work on people initiatives to build a diverse and inclusive culture at PostHog. We want to put a strong sense of belonging at the heart of everything we do.
Running any disciplinary or grievance process that may occasionally arise.
These are some things that Ops is _not_ responsible for which you might see at other companies
Resolving performance issues and creating things like performance management plans. This is the Exec team's responsibility, working with the relevant managers.
Booking travel or accommodation for when you travel. You have the ability to do this yourself and we trust you will spend money carefully. The exception to this is our company offsite where we book accommodation.
When something falls on the Ops team, we make it very clear we are the owners of that specific thing. We communicate clearly with other teams when we require their input and we make it as easy as possible for them to help us achieve the desired outcome. We are quick to triage things that don’t have a clear owner and we get them into great shape before we expect others to have to interact with it. This could be anything from a compliance matter to how our merch process works. We say 'here's how this could get done' rather than 'that's not my job'.
Be supremely reliable
If we say will take care of something, we take care of it - no exceptions. We are often trusted with big and small things, and we take all of them seriously. This also means we will keep you in the loop if something can't happen as we originally intended. We are trusted with a lot of sensitive information, from our team members' personal details to specific company info that we need to protect. When people trust the Ops team with something, they need to know it’s getting done properly.
Act with care & compassion
The Ops team has got your back. We treat everybody with respect - caring deeply about the success of the business means caring deeply about the success of every team member, irrespective of things like seniority. We want to be sure we will be proud of how we handled any situation. This doesn’t just apply to our team members but to anybody interviewing, the customers we deal with, and anybody else we interact with externally such as suppliers.
Philosophy club runs once a month, and Charles Cook organizes it. We spend each 30min session discussing one philosophical question in the Socratic tradition. A short text is shared in advance as light pre-reading from the Stanford Encyclopedia of Philosophy. These can be a bit dry, so feel free to use alternatives - the Crash Course videos are quite good.
If you're interested in joining, ask Charles Cook to add you to the recurring event in #team-people-and-ops.
Structure
Each session is 30min:
5min — framing: one person summarizes the pre-read in plain language
10min — clarification: we define the terms in the question
10min — probing: share examples from real life
10min — synthesis: each person states if their belief has altered or not
The only rule is no observers - if you join a session, you should expect to take part.
Topics
See below for the full roadmap, with a link to each pre-read. This is a 1 year commitment if you want to do the whole thing, but each question stands alone, and you can attend as many sessions as you want!
This is a rough guide to ramping up as a product manager in PostHog.
Timeline
Day 1
Outcome: Get started
Get set up and follow your onboarding checklist
Do your first analysis in PostHog (e.g. Who are our biggest customers? what's the most used feature?)
Set up time to meet everyone in your team and understand their current strategy, motivations and risks
Read up about the OKRs of your team
Attend the Company All Hands
Week 1
Outcome: Get stuck into execution
Join your teams' standups
Learn about their current projects
Arrange and host 2+ calls (through customer success initially) and get feedback from customers about ongoing projects
Use PostHog to gather data to support with executing existing projects
Share an interesting finding from PostHog in the demo section of the company all hands
Month 1
Outcome: Your teams are hitting their goals faster
Finding opportunities to reduce scope and increase impact of big projects
Giving the team the context they need to design and build really amazing solutions to customer problems
Enabling the team move faster by finding and removing bottlenecks
Quarter 1
Outcome: Hit your goals and set the strategy for the next quarter
Pull out the stops to get your team across the line with their existing goals
Work with leadership and your team to define ambitious goals for next quarter
Use data and customer context to rationalize priorities
Specialism
As well as your day job with specific teams, its important we have PMs having company level impact across the following specialisms too.
Analytics
You're performing analytics on how customers use our products outside of your team's scope
This analysis defines how the company priorities what to build across product
You push the limits of what's possible in PostHog to help us build more advanced tools and you work with SQL to get answers to the most complex queries
Customer Research
You're always talking with our customers, and you intimately know how their frictions with our products
You're giving customer insights to every team (in and outside of product) to help them prioritize better
You're the first to hear about new opportunities and problems that our customers need solved and you capture this information
Growth
You work closely with growth engineering and leadership to understand how we can accelerate activation and revenue growth
You know inside-out our funnels for growth and provide the context for to make quick changes to validate hypothesis and grow faster
It’s important to us that all PostHog employees feel invested in the company’s success. Everyone plays a critical role in the business and deserves a share of that success as we grow. When employees perform well, they contribute to the business doing well, and therefore should share in the increased financial value of the business.
As part of your compensation, you will receive an option to purchase stock in the company, subject to a standard 4-year vesting schedule with monthly vesting and a 1-year cliff. Broadly, the number of shares subject to your option depends on your Level. We may adjust this policy over time depending on our hiring pace – for example, if there is an extended gap in hiring, we may revise the allocation.
While the governing terms of the options may vary if PostHog is ever acquired, we have set them up with the following key terms:
10 year exercise window from the date of grant in the event that you leave PostHog.
Double-trigger acceleration, which generally means if you are let go or forced to leave in connection with the company being acquired, all unvested shares subject to your option will immediately vest.
Vesting starts from your start date, not after a “probation period” or similar.
For UK-based team members, eligible options are granted under an EMI scheme and/or a CSOP scheme, both of which can be tax-advantaged.
It can take time to formally approve and issue options, as it requires a board meeting and updated company valuations. We can provide estimates of the likely issuance timeframe at the time of hiring, but generally speaking, we try to get formal board approval a few times a year. In any case, you will not be disadvantaged by any delay in the approval process, as vesting always starts from your PostHog start date.
Frequently asked questions
We have written out a few of the most commonly asked questions about stock options below. Some of these questions are useful if this is your first time receiving options, while others provide more detail. If you have specific questions, please reach out to Hector. However, note that these questions are often highly individualized, and as such, we may suggest that you consult with your own personal tax advisor for tailored guidance.
What is a stock option?
A stock option gives you the right to purchase shares of PostHog's stock at a predetermined price set on the date of the grant, regardless of what the market value of the stock is in the future.
Stock options can be financially very lucrative, because PostHog will give you the opportunity to buy stock at the grant-date fair market value, which may be lower than what investors or an acquirer may be willing to pay in the future at a liquidity event. As we continue to grow the company, we hope that the value of our stock will exceed the exercise price on your options, which could result in substantial financial upside to you and the rest of our option holders.
What does it mean to "exercise" a stock option?
This simply means you decide to buy the underlying stock covered by your option at the price set out in your option agreement. The price you pay is called the “exercise price” or the “strike price”; both terms are widely used and mean the same thing here. When you exercise a stock option, the exercise price is paid to PostHog as consideration for the stock you're buying.
You should be careful here, as exercising stock options can have personal tax consequences. We always recommend you consult with your own personal tax advisor before making a decision to exercise any options so that they can provide you with individualized tax advice based on your specific circumstances.
What are my stock options actually worth?
Because there is no public market for our stock, and because the stock is subject to standard private company restrictions on transfer, rights of first refusal, and consent requirements, it is not possible to assign a true “value” to the stock.
Although we can tell you what the last-round preferred stock investors paid and what our 409A (US) or HMRC (UK) appraisers assigned as the most recent “value,” there is no guarantee that any buyer or investor would pay those prices – even in the event of a sale or acquisition.
That being said, you can use this handy calculator to model what your options might be worth in the future, under certain assumptions about liquidity, sales price, dilution, etc. You'll need to make a copy first, and be signed in with your PostHog email address. You can also find estimates in your Employee page in the PostHog Ops platform.
Since these numbers are based on assumptions, we cannot promise you that value, but in any case it can give you a sense of what the stock may be worth.
What should I do if someone contacts me about buying my PostHog shares?
Don't engage. This is coming up increasingly – LinkedIn ads, cold outreach from platforms, and direct messages from individuals all claiming to be able to buy your PostHog shares or options. Unless PostHog has explicitly communicated a secondary sale opportunity internally, none of these companies or platforms have been approved by us, and any transaction you enter into with them will not be legally valid.
PostHog's company documents prohibit any transfer of our stock without prior board approval – and "transfer" covers a lot more than just an outright sale. It includes forward contracts, futures, and any arrangement where you're effectively passing an economic interest in your shares to someone else, regardless of how the deal is structured or what it's called. Any transfer without board approval simply isn't valid. There's no clever structure that gets around this.
These platforms know about the consent requirement and usually claim they've found a workaround. Some offer to advance you cash now, with an informal agreement that you'll hand over the shares when you eventually can sell. Others claim to be buying a right to your future proceeds rather than the shares themselves. Neither approach works – they still fall under the same restrictions. The bigger problem is that these companies put all the risk on you. Because the transaction was never valid to begin with, it will be void – PostHog won't update the cap table to reflect it, and we won't recognize the third party as having any interest in your shares. That creates a genuinely awkward situation: if PostHog is acquired or goes public, you're still the lawful owner of record, which means the proceeds flow to you, not to whoever you made the informal arrangement with. You'd then be on the hook to repay them – or find yourself in a legal dispute with a company that had no legitimate claim to your shares in the first place. PostHog has not authorized any of these companies or platforms, and we have no relationship with any of them. If they've implied otherwise, that's not accurate.
This applies to former employees too
Leaving PostHog doesn't change this. The same restrictions apply after your employment ends, and any sale of your shares or options still requires board approval. If you're a former employee who's been approached, the answer is the same: it's not possible without our involvement.
When will I actually get to sell?
We try to run regular secondary sales to give the team real liquidity opportunities. When one is available, we'll let the whole team know at the same time. Any legitimate opportunity to sell will always come directly from PostHog – not from a cold message or a LinkedIn ad.
If you've been approached by one of these companies and have questions, reach out to Hector in Slack.
What if I leave PostHog before this exit event happens?
Happily, we have set up terms that are industry-leading in their friendliness to team members! If you leave PostHog, you will have 10 years from the date your stock option was _granted_ to exercise any vested portion. Note that the exact deadline you have for exercise is whatever is written on your stock option agreement under "Expiration Date".
The industry standard is to give only 90 days to exercise after leaving, which we believe is overly restrictive.
Are there any tax issues I should be aware of?
You should always consult with your own tax advisor before making decisions about exercising your options. That being said, there are a few important tax issues we want to highlight here that may apply if you live in or are a taxpayer in the US or the UK.
US stock options
To the extent legally possible, we grant stock options to our employees as Incentive Stock Options (ISOs), which can be tax-advantaged assuming the following two holding period requirements are met:
You must not sell the underlying stock until at least 1 year after exercising; and
You must not sell the underlying stock until at least 2 years after the grant date.
If you do not exercise the option within 3 months of leaving, you still keep the stock option to the extent vested, but any non-exercised portion will legally convert into a Non-qualified Stock Option (NSO), which does not have the same tax advantages. Generally, no tax is payable upon exercise of ISOs (except for potential liability under the Alternative Minimum Tax (AMT)), whereas income tax is payable upon exercise of NSOs. US taxpayers may therefore wish to exercise stock options within 3 months of leaving to retain ISO tax benefits, though this requires paying the exercise price out of pocket and may reduce optionality.
After 3 months, if you _exercise_ (not sell) your stock options, you will be liable for income tax at exercise on the difference between the market value at exercise and the exercise price. Within 3 months, no tax is payable upon exercise (other than potentially AMT) – you will only pay tax upon _selling_ the shares (generally at a lower capital gains rate, if ISO holding period requirements are met). We can't give you personal advice here, so please consult a tax advisor to see if exercising your ISO options makes sense for you.
UK stock options
If you are an eligible UK taxpayer, you will be granted stock options under either an EMI scheme or a CSOP scheme, both of which can be tax-advantaged. We aim to grant employees the most tax-advantaged options possible, subject to eligibility rules. Since EMI options are generally seen as more favorable than CSOP options, we will default to granting EMI options if we are eligible to do so at such time. In the event we do not have EMI eligibility, grants will be made under a CSOP plan instead, and if we are not CSOP eligible, the grants will instead be non tax-advantaged.
EMI Options: EMI Options are similar to ISOs in that they are tax-advantaged in the UK, but the tax advantage is lost 90 days after you leave PostHog. <p>After 90 days, if you _exercise_ (not sell) your EMI options, you will be liable for income tax and potentially national insurance contributions on the difference between the market value at the time of exercise and the exercise price. Within 90 days, no tax is payable upon exercise – you will only pay capital gains tax upon _selling_ the shares (which is generally a lower rate than income tax). In addition to that, EMI's also have the added benefit that if you sell after holding for 2 years from the grant date, you may be eligible for more favorable capital gains rates due to business asset disposal relief. Again, we can't give you personal advice here, so please talk to a tax advisor if you're not sure whether exercising your EMI options makes sense for you.</p>
CSOP Options: CSOP Options are similar to EMI Options in that they are also tax-advantaged in the UK, but there are a few key distinctions:
Unlike EMI Options, there is no requirement that the CSOP options must be exercised within 90 days of leaving PostHog to maintain tax-advantaged treatment. However, there is a separate and distinct requirement that a CSOP option must generally be held for at least 3 years from the grant date in order to be eligible for tax-advantaged treatment (this requirement does not apply to EMIs, though as noted above, holding EMIs for 2 years may also allow you to benefit from a more favorable capital gains rate). Although you technically will have the ability to exercise any vested CSOP options prior to this 3 year date, because we allow options to be exercised up to 10-years from the grant date, absent some sort of liquidity opportunity or statutory allowance, it probably doesn’t make sense for you to do so to lose out on tax-advantaged treatment.
Please check with your tax advisor if you plan to exercise your CSOP Options (especially prior to 3 years) as you may be losing out on critical tax benefits if this is done incorrectly!
Unlike EMI Options which come with a £250,000 limit, there is a lower £60,000 limit on CSOP Options that can be granted (valued at the time of grant). The CSOP options count toward the EMI cap as well, so if you already have outstanding EMI options close to the £250,000 limit, your particular effective CSOP cap may be lower than the £60,000 maximum.
When eligibility conditions are met for CSOP options, the tax paid upon sale is typically capital gains tax, whereas EMI options may also be eligible for additional favorable business tax disposal relief.
As with everything here, this is highly facts and circumstances specific, so please consult with your individual tax advisor to make sure you don’t lose out on any key tax benefits.
Other countries / non-tax favored options
At the time of grant, we check for eligibility factors and do what we can to provide tax-advantaged treatment where possible. However, not every option will necessarily be eligible for tax-advantage status (whether due to lack of company eligibility, ineligible tax jurisdiction/residence, employment requirements, caps on issuance amounts, or otherwise). Any option that is not eligible to be issued as either an ISO, EMI, or CSOP will be granted as an NSO.
Historically, we designated all non-US and non-UK grants as "ISOs" for consistency, though in practice, none of these grants were ever eligible for true ISO beneficial tax treatment under the law since they were made to non-US taxpayers. As of July 2025, we revised this practice to avoid confusion and to align with recommended best practices, and now all grants we make to non-US and non-UK service providers are issued as NSOs. NSOs are not tax-advantaged, and generally speaking, income tax will be due upon _exercise_ of the option.
In all of the above cases, your exercise price remains fixed at the time of issuance no matter what.
Does it make any difference how I leave PostHog – what if I am fired or made redundant?
We have taken a very broad, market-standard and team-friendly approach to what we consider for and not for "cause" in the event of departures:
If you decide to leave, i.e. resign, your stock options stop vesting, but you maintain all vested options and you will continue to have 10 years from the grant date to exercise them (subject to the potential differences in tax treatment depending on when you exercise, as mentioned above). This departure is not considered for "cause".
Even if unfortunately you are let go due to performance issues, fit, redundancy, etc., you still maintain your vested stock options, and you will continue to have 10 years from the grant date to exercise them (subject to the potential differences in tax treatment depending on when you exercise, as mentioned above). This departure is also not considered for "cause".
Only in the unlikely event you are let go due to gross misconduct, fraud, causing material harm to the business, or similar issues would you forfeit your stock options (including vested shares). In such a situation, your departure would be classified for "cause".
The concept of “cause” is similar (though not identical) to the concepts of “good leaver” and “bad leaver” under UK law. We aim to align our option agreements across jurisdictions in an employee-favorable way, but note that local law classifications may not perfectly match the contractual provisions in your option agreement. As such, you should check with your tax advisor to confirm your individual circumstances.
We also have a special provision in place in case PostHog is acquired by another company and, in connection with such acquisition, you are let go without "cause". In this case "double-trigger vesting" applies, which means 100% of your unvested options immediately vest. This benefit is usually only offered to executives at startups (if at all), but we thought it was fair that everyone should benefit from this.
While we cannot guarantee that an acquirer will agree to assume these provisions without issue, including them in our option agreements gives us a strong position to advocate for maintaining them at such time.
What if I move jurisdictions but stay employed by PostHog?
As a remote company with global hiring practices, we often get questions about what happens to outstanding options if an employee moves to a different country. Generally, provided that your option does not cease vesting upon move due to legal requirements, you should expect them to continue vesting on the same schedule and keep the same strike price. However, the tax treatment of your options may change depending on your new jurisdiction. Not all countries recognize the same tax-advantaged schemes, so your options, or a part of them, may lose favorable tax status even though they continue to exist and vest.
You should not assume that PostHog can accommodate cancellations, re-grants, or restructurings based on personal tax circumstances or decisions to relocate. For example, if you were granted NSOs and later move to the UK where you might otherwise be eligible for EMI, your existing NSOs will generally continue as-is. We would not cancel and re-grant them as EMI options.
Given the flexibility we offer around work location, it is not operationally feasible for us to tailor equity treatment to each individual’s circumstances and decisions to relocate. If you already anticipate a move at the time of hiring, let us know. We may be able to delay your grant until after your move. However, this comes with the risk that your strike price may be higher at the time of such grant.
As always, jurisdictional moves are highly fact-specific. Please reach out with questions, but note that in many cases we may recommend seeking independent tax advice.
Exceptions
There are a few notable exceptions to the general approach described above:
EMI options and moves to EOR arrangements
If you hold EMI options and move out of the UK while continuing employment at PostHog via an Employer of Record (EOR), unfortunately this is treated as a cessation of continuous service under EMI rules. In this case:
Your options will stop vesting immediately
Any unvested portion will be forfeited
To retain favorable tax treatment, you must exercise the vested portion within 90 days
In such a circumstance, since the option ceases to vest due to legal requirements, PostHog will re-grant the unvested portion as NSOs after your move, on the same vesting schedule. However:
The strike price may differ from your original grant
In practice, it is often higher, since UK valuations (for EMI) are typically lower than US 409A valuations, and valuations generally increase over time
We do not have flexibility on this point, so this is an important factor to consider when deciding whether to relocate, as the total number of options you ultimately retain won't change, but the economic impact to you of the change in strike price or tax treatment could be significant.
Broad-based changes (not individual requests)
In some cases, we may make changes that benefit groups of employees, such as canceling and re-granting options or changing option types due to regulatory or eligibility changes.
For example, if we previously issued CSOP options due to lack of EMI eligibility and later became EMI-eligible again, we might evaluate whether to make a broader change. These decisions:
Are made at a group level, not individually
Depend on the overall impact and trade-offs, and the pros and cons are carefully weighted
Will not be driven by individual jurisdictional, tax or other circumstances
If a change in tax treatment or eligibility applies only to you, you should assume we will not make an exception.
What is "vesting"?
Vesting means that you don’t receive all your stock options immediately; otherwise, you could work at PostHog for a week, leave, and still receive a significant portion of your options.
Instead we follow the standard industry vesting schedule over 4 years:
After 1 year, you will hit a "cliff," and 25% of your total grant will vest.
In each subsequent month following the cliff, 1/48th of your total grant vests, so you are fully vested after 4 years.
Vesting starts on the day that you started at PostHog, not the date that your stock options were granted.
How did you decide the strike price that I should pay to exercise my stock options?
PostHog doesn't decide the price – we get an external company to conduct a valuation and determine the "fair market value" (FMV) of the stock. Note that this is different (and often lower) than the price from the last funding round, due to the way that the price is calculated, and due to the fact that the stock options you receive will cover common stock while investors instead buy preferred stock.
For UK grantees, similar criteria is used to determine the valuation by HMRC.
In either case, we don't have any flexibility here – if we set an exercise price lower than the FMV, this would create serious tax issues for both you and PostHog.
These valuations are typically valid for at most 1 year (US) and 90 days (UK), so we have to redo them periodically.
Why do we allocate stock options in batches?
Two reasons – because valuations (mentioned above) need to be re-run, and because each time we allocate stock options we need to get them formally approved by the board.
As a result, it is normal for companies to grant stock options at set intervals (e.g. 1-2 times per year), rather than individually at the exact time of hire.
Why don't you just give me the shares?
Under most countries' tax laws, including the US and UK, a direct issuance of stock would be considered income, and you would immediately have to pay income tax on the stock received. This would mean you getting hit with a tax bill of tens/hundreds of thousands of $$$ with no direct cash compensation to help you pay the tax liability due to the illiquid nature of the stock. Stock options are a much more tax-efficient way to compensate team members, as you don't pay tax today when you are granted the stock options, and as mentioned above, you are often able to take advantage of tax-favored schemes that can further reduce your liability.
Can PostHog help me figure out what tax I will have to pay in the future though?
We cannot give you personal tax advice – you need to talk to an accountant. We're happy to ask around our network for recommendations.
I received stock options under the EMI and/or CSOP plan as I'm based in the UK – how are these different from our regular stock options?
EMI and CSOP options have various additional tax benefits associated with them that we're able to offer because PostHog Inc. has a UK child company, Hiberly Ltd. The option is still for stock of the parent company, PostHog Inc., even though you are employed by Hiberly Ltd. Please see the section titled “UK Stock Options” above for some key differences, but as always, please make sure to consult with your own personal tax advisor for any specific questions about tax treatment.
It is worth noting that you will lose EMI and/or CSOP tax benefits if you stop being a UK tax resident.
How do I track my vesting and manage my options?
We use a tool called Carta to virtually manage our cap table and stock options. You can sign in to the platform using your PostHog email, and you will be able to see all of the option grants you have received, the start date and how much you have vested thus far, the strike price of your options, and how much it would cost to exercise a certain amount of options.
Non-UK employees can exercise options via Carta by sending PostHog the exercise price via ACH. Due to additional jurisdictional specific requirements in the UK, EMI and CSOP holders cannot exercise via Carta – if you are in the UK and would like to exercise, please reach out to Hector or the ops team.
I have a question that is not covered here!
Ask Hector or Fraser – ideally in a public Slack channel (if appropriate) for better visibility.
May I suggest a change to our stock option plan or my stock option documents?
Unfortunately this isn't possible – we have a standard set of agreements that we use with everyone which are pre-approved by the board and our investors. Making any changes would not be feasible, unless you spot an obvious error in your option agreement.
That being said, we do not include any terms that are not either completely standard or (in many cases) as team-friendly as possible.
PostHog looks for passion in the people it hires. This often correlates with people who have side projects as a hobby. For example, we view pre-existing open source work as a strong qualifier that you're good enough at programming that it's fun to do rather than frustrating and hard!
These side gigs may sometimes earn you money. Sometimes, you may one day want your side gig to become your main gig.
We have deliberately called them "side gigs", as we are ok with you earning money on the side. We are not ok with this being your main focus and PostHog being just a paycheck. Quite simply, we are too small for PostHog not to be your main motivation. For this reason, we also currently don't offer part time work as an option at PostHog.
Managing time
The key distinction to something being a side gig, and thus it being appropriate, is its impact on your work and the amount of time involved.
A few hours a month on a paid side gig is acceptable. In any case, side gigs should by default be something you work on in your personal time, and they should not impact the work you do at PostHog.
In a few cases, you may want your side gig to become your full time work one day. That is ok - please just let us know, so we can create a plan. We know the key to motivated people is to help you achieve your long term goals, and to align this with what PostHog needs, whether or not you eventually achieve them with us.
Above everything else, if you are going above and beyond for PostHog and you're still able to look after yourself properly, side gigs (whether paid or unpaid) are totally fine. We don't think that's possible beyond a certain level of time/energy commitment to them, but we are very happy for you to spend a little time on them each week.
Intellectual property
Just to reassure you, PostHog won't try to claim ownership of any intellectual property (IP) you create in your personal time, e.g. if you are contributing to another open source project as a hobby. Side projects built on your own time using your own resources do not require permission, review or approval from PostHog. Go forth and build. However, you need to be _really_ careful that you do not introduce any of PostHog's non-open source IP into any project that you work on - this can cause serious legal headaches. As a rule, anything from PostHog that is explicitly MIT-licensed is fine to use, anything else is not.
Projects that start at PostHog
If a project is born from work you have done inside PostHog – that is, using work time, PostHog code, PostHog data, or other PostHog tools and infrastructure – these projects belong to PostHog and should live in PostHog repos. If you want to develop these projects further on the side, you will need explicit permission.
If you are ever worried about this, please talk to Fraser and he can help you figure out the best solution here, especially if what you are working on directly competes with something PostHog has built or is on our roadmap.
Getting signoff
We ask you to please just check in with the relevant Exec team member for your team (ie. James, Tim, or Charles) to get their confirmation before going ahead with any side gigs.
If your side gig existed before you joined PostHog, this will usually be covered as part of the onboarding process.
There are many occasions when you will need to spend company money. PostHog is a lean organization - the less we spend, the more time we have to make sure the company takes off. However, it is more important you are productive, healthy, and happy.
Guiding principles
We have a context-based expense policy inspired by the book 'No Rules Rules'. We're empowering team members to make good decisions while maintaining transparency and accountability.
Ask yourself:
Can you clearly explain why this expense is in PostHog's best interest?
Would you be comfortable explaining this expense to the entire team publicly?
If the answer is yes, it is likely the expense is in the best interest of the company and supports your productivity.
If not, think again.
The goal here is to empower you. However, when in doubt, ask your team lead for context, not permission.
All company expenses (offsites, software/tool subscriptions, merch, etc.) will have common company-wide budgets.
You'll be assigned a single User Limit of $5,000 per month in Brex from which you can spend money on individual subscriptions, coworking/collaboration, equipment (except laptops and Mac Studio Monitors - ping #team-people-and-ops for these), training, etc. If you need an increase in the limit, request it on Brex.
The $5,000 is a ceiling, not a target or an allowance to use up – only spend what you can justify as being in PostHog's best interest.
Transparency & accountability
All expenses are visible company-wide
If we have questions about an expense or need documentation, we'll reach out for clarification
Team leads get monthly reports showing all direct report expenses
Logistics
UK employees
Use your Revolut if the expense is over £75 _and_ has UK VAT on it. If not, use your Brex.
The company can claim back VAT on these larger purchases - the more money we claim back, the more money we have to #DoMoreWeird
Please make sure that the invoice is addressed to Hiberly Ltd and our registered address (this can be found in the Important Company Details sheet).
Receipts
All expenses over $75 or £75 must have itemized receipts attached and memo updated within 14 days of the charge, as this is what our auditors require.
Revolut: email your itemized receipts to ukinvoices@posthog.com along with a memo in the body of the email
In extreme cases, expenses with no receipts above $75 or £75 may be deducted from your pay if we can't verify the business purpose - this is mainly for repeat offenders where someone's clearly ignoring the policy.
We need an _itemized receipt or invoices_ because Brex auto-verifies these using the information on the file. For example, this means the full booking confirmation email for flights/hotels, detailed bill from the restaurant for a team dinner etc. Please do not upload cropped images that show just the amount or just the credit card machine confirmation slip - without context, the receipt is pointless
Template for a thorough memo
- What: [item/service purchased]
- Why: [business reason - how this helps PostHog/your work]
- Context: [relevant details - who attended, what project, etc.]
Reviewing expenses
Finance reviews:
All expenses over $1000 (Brex)
Random sampling of expenses under $1000 (Brex)
All Revolut expenses
Team Leads
You'll get monthly expense reports for your direct reports. You have context Finance doesn't, which will help justify spending decisions to the auditors. How much you dig into these is up to you - the goal is catching patterns, not micromanaging.
Why documentation matters
Missing receipts and memos create extra work during audit season - auditors will need to dig into those expenses, which means hours of back-and-forth with you about charges from several months ago! A quick receipt upload and memo update now saves everyone time later.
We're legally prohibited from paying personal expenses on behalf of team member, and are at risk of penalties/fines if this happens.
The flexible, trust-based policy we have only works when everyone maintains proper documentation. If team members consistently fail to upload receipts and add memos, we'll either need to implement rigid pre-approvals for all spending, or treat repeated violations as performance management issues. Which we really don't want to do!
Budget structure on Brex
We're not going to police your spending with hard limits but we will continue to use budgets and limits on Brex for audits, and because categorizing this stuff properly is essential for things like Board reporting, tax compliance, and seeing how we're doing against our budget.
All subscriptions/tools used at a company level - (Janani should be default admin for all of these, so she can handle receipts etc.
User Limit of $5,000 per month, per user
This covers all co-working/collaboration costs, training, individual software subscription, etc.
For subscriptions and other recurring monthly expenses, we recommend using the virtual card under your User Limit to ensure it gets categorized to the correct budget by default
Joining an offsite? _Only use the offsite budget_, not your User Limit - it helps the People & Ops track travel spend accurately against budgets. Let Kendal know in #team-people-and-ops.
High-value & ongoing vendor contracts
Some of what we spend money on isn't a personal subscription or a one-off purchase - it's a platform a team runs to do its work, on a contract that bills continuously and at scale. Think infrastructure like Kafka, or certain security tooling. Spend here can run into the thousands or hundreds of thousands, so it deserves more care than "I subscribed to XYZ" - the guiding principles above still apply, they just matter more.
This section is about _living with_ a contract we've already got. Deciding whether to adopt a new tool in the first place is covered separately in Adding tools.
Who owns it? The team that operates the vendor owns its quota and spend - in practice, the person with the most context about the contract, usually whoever proposed or operates the tool. That includes keeping an eye on usage against the contract's limits (the usage terms and limits you agreed when you signed it) so nobody is surprised by the bill. The easiest way to stay on top of this is to fold it into the vendor's own periodic review (e.g. a quarterly business review), so quota and spend get looked at on a regular cadence rather than only when something goes wrong. Loop in your exec early - they should have enough context to support and guide you.
Need help getting at the financial data or the tools to track your spend? Ask in #project-infra-tools. We want everyone to be able to work with their spend easily, so this doesn't get in the way of shipping.
If a contract is running into overages or about to induce extra spend, flag it early. Act as soon as it's clear an overage is likely to persist over a longer time, or to have significant consequences on the bill - don't wait for it to land repeatedly first. The whole point of watching usage is to catch it before the money is spent. Concretely:
The person with the most context on the contract drives this. Keep your team lead and the responsible exec aware - they own the area and help decide whether the extra spend is worth it or whether we right-size.
Ping @finance-folks in Slack as soon as the overage looks material, and take it from there. That's usually enough - it keeps Finance in the loop so they can forecast it accurately.
Pull in #legal if this is a _new_ contract, or if the legal details have changed and need a second look. Straight re-commits or renewals usually don't need legal, but a new contract always does (see Adding tools).
For company-level tool billing, Janani in #team-people-and-ops is the default admin, so billing stays owned and categorized correctly. The billing email for any vendor contract is finance@posthog.com.
There's no fixed dollar amount that trips a formal approval - we stay trust-based and lead with context, not permission. Use your judgement for what counts as material. But spend at this scale isn't comparable to a personal subscription, so be proactive and transparent about it _early_ rather than once the overage has already landed.
Past a certain spend, it's worth challenging the tool or contract itself, if feasible - and it's up to you to decide what feasible means here. Software keeps getting cheaper, and at some point it may be cheaper to build than to buy. Pull in your exec to discuss this - it's exactly the kind of trade-off they should be weighing in on.
Renewals are the same process. A renewal isn't a rubber stamp - do the due diligence and see where you can optimize. Vendors can usually help here, so ask them. Pull in your exec and Finance for help negotiating the terms.
Frequently asked questions 🤨
Can I use my personal card for a work-related expense?
No, you must use your Brex or Revolut for all work-related expenses.
The company earns points which we use towards billboard campaigns. The Finance team also doesn't have the bandwidth to process lots of reimbursement requests.
What if I accidentally used my personal card for a work-related expense?
Claim a reimbursement with an itemized receipt on Brex within 90 days of incurring the expense, with a memo (context on what was the expense for and why your Brex wasn't used).
We cannot process any reimbursements without a receipt.
Can I use my Brex/Revolut for a personal expense?
Obviously not.
What happens if I forgot to assign the right spend limit before using Brex?
What do I do if I have a new tool/enterprise software subscription for the team to use?
Add Janani as the Billing Admin to manage payments.
If I'm asked for a billing email – for bill payments or when signing a vendor contract – what do I use?
Use finance@posthog.com
A vendor contract we rely on is running into overages / about to cost more – what do I do?
Flag it early - see High-value & ongoing vendor contracts. Whoever has the most context on the contract should drive, keep your team lead and the responsible exec aware, and ping @finance-folks in Slack as soon as the overage looks material so Finance can forecast it. Use your judgement to assess what counts as material.
What if I'm driving for work-related purposes?
You can claim a mileage reimbursement through Brex. Do not separately expense fuel.
What if I accidentally used the company card for a personal expense?
Login to Brex > find the charge > click on 'Repay'.
US and Canada: Brex's auto repay function works, so it'll pull the money from your connected bank account for you.
International: auto repay isn't available, so the 'Repay' button only tracks the expense. You need to manually transfer the amount from your personal bank account to PostHog's bank account, using the details provided in our banking runbook.
For Revolut charges, repay to the bank account details provided in our banking runbook
What if I've received a bill I need Finance to pay?
Submit the bill using the 'Bill Pay' feature on Brex, with context on what it is for, and which budget the bill should be coming out of, once you have verified it.
Finance processes all bill payments on Wednesdays.
How do I upgrade my flight ticket to premium or business using my personal points/card?
Book an economy ticket using your Brex, then upgrade afterwards using your personal points/card.
If you can only book premium travel using personal miles or points/card then request a reimbursement for the cost of the economy fare in Brex, along with a screenshot of the cost of the economy fare at the time of booking.
How we handle inappropriate spending
Expenses that could be construed as personal will be flagged as non-business expenses by auditors, as they will be considered a taxable benefit that PostHog has provided to you.
Examples of inappropriate spend include:
Personal expenses during business travel (for example: gym sessions/fitness classes, groceries)
Entertainment subscriptions for personal use (for example: Spotify, Netflix, Amazon Prime, etc.)
Expenses that benefit you personally rather than the business
Anything you wouldn't feel comfortable explaining publicly
If the inappropriate spend was due to a misunderstanding, e.g. you genuinely thought an expense was in PostHog’s best interest, but we disagree, we’ll provide clarification and context. If you knowingly and deliberately spent money in ways that are not in PostHog’s best interest, or tried to intentionally circumvent the guidelines, we will probably treat this as serious misconduct.
Expense guidelines
Equipment
Laptop & monitor
Talk to Tara who handles Macbook and Apple Studio Display purchases - ping her on #team-people-and-ops.
Having equipment purchases centralized helps ensure accurate accounting and tracking of fixed assets for the audit.
We expect you to ship the Macbook and Apple Studio Display back when you leave PostHog.
Apple Studio Displays are only for Product Engineers (high density screen), PM's and Sales/CS/Onboarding teams (built-in high quality webcam and microphone). For all other teams that feel they could benefit from an enhanced monitor, there are some really great competitors to the Studio Display at a fraction of the price - like the Clarity Pro 27" or another solid option is this LG screen You can purchase these using your personal limit.
If you order a Studio Display during your probation period but end up leaving PostHog, we can recover the cost of the display and you won't need to return it.
Laptop guidelines
For engineering roles (product, platform, & support), we buy the Macbook Pro 14-inch M5 Pro 14", with the 18-core CPU, 20-core GPU upgrade and 64GB of RAM.
For sales & CS roles, we buy the Macbook Pro 14-inch M5, with 10-core GPU, 16-core and the 32GB RAM upgrade.
All other roles, we issue Macbook Pros. Wherever possible we will redistribute engineering models (Macbook Pros) no longer in use to allow you to have a more powerful machine for running PostHog Desktop.
We only purchase laptops with an English keyboard configuration (US, International or British is fine) - this enables us to easily pass your laptop on to someone else if you upgrade or leave.
In the unlikely case that you need to purchase your own laptop:
Check if Amazon has sales before purchasing through Apple
US only: use your Brex since we earn cashback
Do not get AppleCare since it doesn't have great value for money
You can request a new laptop in #team-people-and-ops if it is over 4 years old, (for engineering machines) has less than 48GB of RAM, or is significantly impacting your productivity. We do ask that you do some diligence to make sure it's not a setup issue though - i.e. other applications aren't hogging the memory, etc.
Phones and iPads are only provided if they're integral to your role (e.g. mobile team or content purposes). Reach out to Tara in #team-people-and-ops and she'll get one ordered for you.
Other equipment
Keyboard/mouse/laptop stand: Check Amazon and Apple for discounts. Refurbished items usually work just fine. Nextstand make great value laptop stands that are portable. You can use your personal budget for this.
Desk & chair - again, refurbished is a great way to get high quality for less. If you live in the UK, Office Resale offer a range of like-new refurbished designer furniture. You can use your personal budget for this.
As a guide, here's what we'd consider reasonable spend:
Desk - up to $500
Chair - up to $500
Keyboard - up to $250
If you want something more expensive, you can pay personally and submit a reimbursement request on Brex for up to the amount above.
Software
We are _strongly opposed_ to introducing new software that is designed for collaboration by default. There needs to be a very significant upside to introducing a new piece of software to outweigh its cost.
The cost of introducing new collaborative software is that it creates another place where todo items/comments/communication can exist. This creates a disproportionate amount of complexity.
Individual software is down to your personal preference, and we encourage you to share cool software.
There are some tools used by team members individually - if they become more widely adopted, it makes sense to have a company account. Talk to Tara on #team-people-and-ops
You can ask for access to team/company tools by submitted a request in Slack. Find the Zluri app in Slack. type: /accessrequest and press enter. You'll get a pop up that allows you to search for the app you'd like access to. Add any specific information about license level/type if necessary. The request will then be sent to the team member who owns/manages access to the plaftorm. Once they have provided access to the platform, they'll confirm via the Zluri task and you'll also receive confirmation. You should then receive an email invite, or be able to login via SSO depending on the tool. If you do not see a tool in the app that you believe is centrally managed, drop a line in the [#team-people-and-ops] channel
Some tools that you might find useful to know about:
Loom: you'll be added as a _Creator Lite_ which allows you to record 25 videos/mo at up to 5 minutes in length. If you need a full Creator account (unlimited videos, advanced features), specify in your Zluri access request
Zoom: we use Google Meet by default, but you can use Zoom for free (up to 40-minute calls). Should you need longer meetings, please specify in your Zluri access request (But does anyone _really_ need longer meetings?)
Superhuman: everyone has their own favorite email app, but Superhuman users will make sure you don’t forget theirs. We have a team plan to keep those folks happy with inbox zero and inner peace.
Granola: It’s absolutely okay to use AI note-takers so you can stay engaged in meetings without writing everything down. Feel free to choose your own but please be aware of who the sub-processors are to ensure they do not use a competitor for analytics.
IDEs: Visual Studio, VIM and PyCharm are the most popular within our team. IDEs range widely in cost; best in class IDE suites can cost up to $700, which is not a great value proposition for most engineers.
AI coding tools (Cursor, Claude Code, etc.) are encouraged, but usage-based pricing can climb fast. Most engineers' monthly spend lands around a single max-tier subscription (~$200/month). If yours is running several times higher, that's usually a misconfiguration or inefficient workflow rather than a genuine need – compare setups with your teammates and ask in #team-people-and-ops if you're unsure.
Claude (including Claude Code): log in with SSO and you'll be added to our team plan. If SSO doesn't add you automatically, request access with Zluri in Slack or ask in #team-people-and-ops.
ChatGPT (including Codex): use the company workspace instead of a personal account, and ask in #chat-gpt-team for a seat. Each seat has a small weekly allowance and then runs on workspace credits – see your usage in Codex analytics, and ask in the channel if you need a higher limit.
Coworking
If there's a WeWork where you are, use it – we have a company All Access account, so default to that rather than paying for another coworking space. Ask Kendal in #team-people-and-ops for access.
Travel
We travel in economy by default and do not pay for business class
If you're unsure of your travel plans and believe you may have to cancel, it may be worth spending a bit extra to book flex tickets that allow a full refund to your Brex
It may be worth occasionally upgrading to Premium Economy if you're travelling a lot for work and the cost is not unreasonably high, particularly if you're working the next day
Consider signing up for programs like Global Entry if you are regularly traveling to countries that offer it, using your Brex; this saves you time, particularly when traveling to the US.
When traveling internationally, use your Brex to expense a reasonable eSIM. PostHog does not cover roaming charges for your phone.
When using your Brex internationally, use the local currency since Brex generally offers a better exchange rate.
PostHog has international insurance for our work trips, so do not buy travel insurance when traveling on behalf of PostHog.
It's fine to book your outbound / return flights for a different day to when you are required to be there as long as the flight is a similar price or less.
Any other costs outside of the days you are required to be at an event are of course _not_ covered.
If you find yourself needing to do extra travel outside of the regular things listed above, e.g. you've been asked to take a last minute trip to work on an emergency project, we may pay for a nicer seat here, especially if you are traveling at very short notice or long haul. Ask on #team-people-and-ops if you think this may apply to you. This is intended for genuine one-offs, not where you've decided you'd like to come along to an extra offsite!
We strongly encourage team members to try and work together in person when practical. This isn't limited to just working with people in your team, but we expect that you have a reasonable reason you need to work together. You should default to doing this in SF/London, so you'll run into other PostHog people too.
If you're in the same place as other team members, even if you aren't directly working together, PostHog will cover the cost of a dinner or a fun activity
When visiting customers (or potential customers), we should look for opportunities to connect with them over a meal. These don't need to be extravagant, but they should be appropriate to the size and expectations of the customer. If you would be comfortable justifying the spend publicly in All Hands, you're probably fine.
For a normal customer visit (yourself or a couple of people), just use your personal budget and request an increase through Brex if you need more. If the visit grows into something offsite-like (the whole team, multiple days, etc.), post in #team-people-and-ops and tag Kendal so she can create a separate budget for it.
Hub travel budget
We encourage people to visit our hubs in SF (Hogpatch) and London (Hedgehouse). These places generally have a high density of PostHog employees around, so you'll get to meet people from other teams, which makes cross-team work much easier and more successful. SF also has the benefit of being the epicenter of everything happening in tech, and we have lots of YC founders working out of Hogpatch who you can meet and learn from. It's good to get exposure to this, especially if you don't live in SF or haven't been recently.
There is no specific travel budget, this can come out of your general employee budget. We strongly encourage you to use your budget for this reason!
If you do decide to come, we ask that you make the trip worthwhile - attend a conference, speak at an event, gather a few colleagues to come with you at the same time and work on something specific together. Don't just pop in and put your headphones in while there - make it worth your while.
Sponsorships
If you believe an open-source project is fundamentally important to the success of PostHog then we should set up a recurring sponsorship. In this case, see the open-source sponsorship Marketing initiative.
Open-source sponsorship for individuals
You can also sponsor open-source projects that have helped you personally, using your monthly User Limit. You don't need approval - just apply the guiding principles above, as you would for any other spend.
The talent team is uniquely placed at PostHog to have an outsized influence on the people that join the company in comparison to the rest of the business. This is why we ask our talent partners to think like owners.
PostHog's business model requires us to build and automate more products, to do that we need more engineers. Once we have more products, we require commercial team members to market those products and to look after the customers that sign up. We also need to support those customers and support the growth of the business. This means that the people that join PostHog directly impact our growth, hence why we invest so heavily in finding and retaining great people.
At some companies the Talent team are seen as a support function, at PostHog we view them as a growth function, so we need our talent partners to be thinking about the growth of the business as a whole, not just as a headcount.
This means taking ownership of understanding what products we need to build, the types of people we need to build those products, understanding how our commercial team make our customers successful and what types of people fit into those commercial roles. Talent partners should also understand how our funnels are working and what is needed to solve any problems within them.
Talent partners at PostHog do not just interview candidates and put them through, they own the process from beginning to end and should use all their skills to make that process successful.
Removing distractions from the rest of the team
As a talent partner, part of the role is to ensure we are removing distractions from the rest of the business where we can. Practically, what this looks like in talent is that other team members really only need to concentrate on assessment and shouldn't need to concern themselves with other areas of the process.
Throughout the recruitment process there are different ways that talent partners can remove distractions.
Sourcing Talent
Our default recruitment strategy is 100% inbound. We are not an outbound-first recruiting style organization and don't want to become one. That said, there are times when sourcing is the right tool for acquiring new candidates. This section explains when to reach for it, how to do it well, and how to know if it's working.
When To Source
We should source when inbound alone isn't generating enough qualified candidates at the top of the funnel for a specific role. This can happen for many reasons, including:
The role requires a niche skill set, and the addressable talent pool is small.
When headcount for a particular role is very high.
A role has been open for 4+ weeks and we're not seeing enough quality applications.
How We Source
Be targeted, not generic. We don't do high-volume spray-and-pray outreach. We'd rather send 15 highly personalized messages than 150 templated auto-messages. Sourcing at PostHog should feel like a curated referral from someone who's done their homework, not a LinkedIn InMail blast.
Practically, this looks like:
Research before you reach out. Look at what they've built, shipped, written, or contributed to. If you can't find a specific reason to reach out to them beyond "their title matches", don't reach out.
Lead with what they'd work on, not who we are. Most sourced messages open with "we are an amazing company..."; this comes across generically and doesn’t always grab attention. Make sure they know it’s a personalized message. Open with the problem they'd solve, or the product they'd help build. Link to the specific small team page they’d work with, a recent GitHub issue, or a shipped feature that's relevant to their background.
Be transparent about who we are and how we work. Link to the handbook. Link to the compensation calculator. Link to relevant blog posts. PostHog's transparency is one of our biggest differentiators in recruiting: use it!
Use the right channel. LinkedIn is usually our default, but for engineers, consider reaching out via GitHub (if they're active contributors), Twitter/X (if they post about relevant topics), or relevant community forums (HN, specific open source communities). Match the channel to where the person actually is. This can also occasionally be via email.
What A Good Sourcing Message Looks Like
Here's the kind of thing that usually works:
Hey (name), I was taking a look at your work on (specific project/contribution). We're building (specific thing) at PostHog and it really seems like the kind of problem that needs someone with your background in (specific skill).
If you haven’t heard of us at PostHog, we're fully remote, pay transparently, and our entire company handbook is public; you can read exactly how the team you'd join operates before you even start day 1: (link to small team page).
If this seems even 1% interesting to you, let me know, and I can set up a call for you with one of our talent partners handling the role!
And here's what doesn't usually work:
Hi (name), I came across your profile and was impressed! PostHog is a fast-growing product analytics company backed by Y Combinator. We're looking for world-class talent to join our world-class team. Would you be open to a conversation?
The first message is specific and gives the candidate real information. The second is generic and could be about any company hiring any role.
Sourced Candidates In the Process
Sourced candidates follow a slightly different path at the start of the process. See Managing sourced candidates for the exact mechanics.
The key difference to keep in mind: sourced candidates didn't come to us; we went to them.
Some context related to this, to end this sourcing section:
You'll need to invest more in educating sourced candidates about PostHog. Inbound candidates have usually read the handbook and tried the product on their own. Sourced candidates haven't always done this (but ideally should before their call). This can look like sending more content-heavy emails (linking to the handbook, blog posts, team pages, etc.) and generally doing more "educating" throughout the early stages of the process, to bring sourced candidates up to the same level of context that inbound candidates arrive with naturally.
Expect lower conversion at later stages. Sourced candidates haven't self-selected the same way inbound candidates have, so their drop-off rates will naturally be higher.
Track it separately. We should always know what percentage of our hires came from sourcing vs. inbound vs. referrals.
Top of the funnel
Talent partners should be speaking to hiring managers before a job goes live to understand the types of candidate that they should be looking for at the top of the funnel, this part should continue to be honed as you learn more from feedback at the various stages of the process. We want to avoid passing through inappropriate candidates, that waste time. It is a talent partner's responsibility to screen applications at the top of the funnel, here we are looking for signal that people can be effective at PostHog. We look for things like:-
have they worked at companies that have scaled like PostHog wants to
have they been a founder before
have they led on projects
have they written a personalized cover letter explaining how they fit the role
Once you’ve screened the application and moved them forward you will have a culture screening call. We also want to ensure that we are putting relevant and motivated candidates through to the next round. At the screening stage it is important to make sure your notes are well organised and clear, not just for the next stage. These notes will be reviewed at SuperDay and will be taken into consideration if we are going to hire this person so make sure to have these in good order.
Post-screen, pre-SuperDay
Talent partners are responsible for moving candidates through the next two stages, we rely on automation from Ashby to allow candidates to book directly in calendars. Talent partners are responsible for the candidate experience so if a candidate or an interviewer can't make that time, then you need to step in and resolve the issue. It is important that interviewers know that they need to maintain an up to date calendar, however sometimes last minute changes do occur.
SuperDay
Talent partners are responsible for scheduling these, you can read more in the hiring process SuperDay section. The people involved should be focused on assessing the candidate so talent partners need to be alert for helping with any logistics to make sure the SuperDay runs smoothly.
Speed v quality
At PostHog, we have two major forces playing against each other when it comes to hiring. We want to move quickly, when we want to hire somebody, usually they should have started last week. The reason for that is we always want to hire for quality, and this takes time. This makes life as a talent partner a constant balance between these two things. The way we try and balance these things is try and move as quickly as possible with the things in our control. We aim to review applications ASAP, usually within 48 hours of application. Then we want to make sure that candidates can book their first round call with us within 2 business days. This keeps the momentum going from a candidate deciding to apply, to speaking to somebody. Our aim is to get back to every candidate by the end of the day after their interview, this is difficult, so whilst it's an aim we don't always hit it. We should be pushing interviewers to get feedback to us ASAP. The longer we leave canddiates without a decision the slower we will move.
Speed is a team effort, we should always keep things moving for each other. This means that if we see something that needs arranged and you can do it now, do it. No need to wait for the person who was last in contact to come online, just give them a heads up that it's done. This shared ownership mentality of speed is what will help us succeed.
When it comes to quality, we are always looking to be impressed. We use a rating system out of 4 and it is rare that we would hire somebody without receiving a 4 from somebody in the process. We know that exceptional people are usually spiky, they don't have an evenly distributed skill set so people can have reservations about a certain area and they can still be exceptional. Talent partners need to be aware of when to push and pull when it comes to hiring decisions. There will be circumstances when there are hard decisions over whether we should hire somebody or not and talent partners should be prepared to offer opinions. This could be vouching for a candidate that is similar to other successful team members who we might be hesitating on and conversely stepping in when it looks like we might be making a hiring that isn't appropriate.
When a hiring process is moving slowly, or we seem to be rejecting lots of candidates at SuperDay, it is up to the talent partner to realize and own this. They should review what is going on, understand the problem and aim to fix this. They should get in front of this as soon as possible.
Maintaining quality is also about ensuring that our interviewers are assessing candidates in a consistent way, so spotting when there are inconsistencies are coming up in feedback and doing something about that is important.
Evaluating success
A talent partner will be judged on how many excellent candidates they can get into the business and how those candidates manage to impact the business' performance. We would much rather we had consistently great people coming in and moving the business forward, than if we had lots of people joining but it's not helping us grow. We want talent partners to be able to just assess a candidate on a screening call but be able to figure out how we continue to scale the growth of PostHog, with great people at the heart of it.
We offer our team unlimited time off, but with an expectation that you take _at least 25 days off a year_, including national holidays. This is to make sure that people can take time off flexibly while not feeling guilty about being on vacation.
The reason for this policy is that it's critical for PostHog that we hire people we can trust to be responsible with their time off - enough that they can recharge, but not so much that it means we don't get any work done. The People & Ops team will look into holiday usage occasionally to encourage people who haven't taken the minimum time off to do so. The 25 days is a minimum, not a guide.
As general guidance, we don't care about a few days here and there. If you are taking significantly more vacation time than most - for example, 40 days - we would be very surprised if you aren't causing a strain on the rest of your team as a result.
Permissionless time off
We care about your results, not how long you work.
You do not need to get approval for time off from your manager. Instead, we expect everyone to coordinate with their team to make sure that we're still able to move forwards in your absence. You should avoid things like:
Having an entire Small Team off - this means we can't provide support to customers
Having the only X people who can do some totally critical task at PostHog off - if this is unavoidable, try to make sure one of you can at least check in if something goes horribly wrong
How to book time off in Time Off by Deel
Before you start, make sure that:
You have authorized the Time Off by Deel app in Slack to connect to your Google Calendar
If you don't do this, your holiday won't show up in the team time off calendar.
To book a day off:
Book it on the Time Off by Deel app in Slack. There are various types of time off you can select. It will be automatically approved and added to the team time off calendar (with the exception of longer term leave.) It will also be added to your manager's personal calendar.
Do not book directly on deel.com as it does not sync with Slack, and the team will not know you are out. Yes, it is confusing that Deel have two separate systems here.
There are four types of time off you can select
PTO - this will be the majority of the time for vacation or any other time off that doesn't fit below
Out Sick - this is when you're sick and will take time off unexpectedly
Medical Leave - this is planned time off for you personally, on medical grounds - if it is a family member who requires support meaning you will be off, this is PTO.
Block out your own personal GCal to show that you are out. This is because Time Off by Deel _only_ books in an all day event in your calendar to show that you are out. If you don't do this, automated meetings such as interviews or demos might still get booked into your cal.
Set an out of office message on your email and have it point to someone else on the team, or hey@posthog.com. Time Off by Deel will automatically set your Slack status to out of office and will autorespond to Slack messages.
Please manually book in public holidays you plan to take off as well. We have team members working in countries all over the world, so it is not practical for us to book these all in on your behalf. Some people also prefer to work on certain days even if they're considered a public holiday in the country they are living in or visiting. In the Time Off by Deel app, you can use the Bulk Add by Region feature to quickly identify and add the public holidays you want off.
The same rules as above apply regardless of the holiday length and type. Sick leave and any other types of time off should also be booked in the same way.
How to cancel time off
If you decide to cancel your holiday, drop a message in #team-people-and-ops and a member of the team will cancel the holiday for you, as only admins can delete holidays.
Flexible working
We operate on a trust basis and we don't count hours or days worked. We trust everyone to manage their own time.
Whether you have an appointment with your doctor, school run with your kids, or you want to finish an hour early to meet friends or family - we don't mind and you don't need to tell us. Please just add it to your calendar and, if you are doing anything that could require you to be immediately available (ie support hero / or any customer-facing role), please make sure you have cover.
When you should have time off
You are sick
If you are sick, you don't need to work and you will be paid - the upper limit for paid sick leave for your country will be specified in your contract. This is assuming you need a day or two off, then just take them.
Please let your manager know if you need to take off due to illness as soon as you are able to and add it to Time Off by Deel. You shouldn't pre-emptively book a bunch of days off sick, as you can't know how long you will actually be sick for and you may trigger the need for a doctor's note (see below). Just book the day or two off that you are sick then add more if you still feel unwell.
For extended periods of illness (5+ work days), or if you are going over the limit in your country/state, please speak to Fraser so we can work out a plan. In most countries, we will need a doctor's note from you.
If you have a medical condition you know will take you away from work regularly, please let Fraser know so we can work out accommodations with you and your manager.
Bereavements / Child loss
We do not define “closeness” and we won't ask about your relationship to the person or what they meant to you. Please just let us know up front how much time you would like to take.
Our bereavement policy also covers pregnancy and child loss for both parents, with no questions asked. Please take at least 2 weeks of paid leave.
If you need extended time for physical or mental health reasons, we will treat it as extended sick leave - just chat to Fraser.
There are lots of situations where life needs to come first. Please let it - just be communicative with your team and fit your work around it as you need. We trust you will do the right thing here.
If you are summonsed for jury duty, please let Fraser know right away - we can often get an exception granted if we have enough notice.
Parental leave
Parental leave is exceptional as it needs to be significantly longer than a typical vacation. Anyone at PostHog, regardless of gender, is able to take parental leave, and regardless of whether you've become a parent through childbirth or adoption.
This table explains the amount of paid time off, depending on how long you've been at PostHog
| Time at posthog | maternity leave | paternity leave | | - | - | - | | under 6 months | 3 weeks | 2 - 3 weeks | | 6 - 12 months | 12 weeks | 2 - 3 weeks | | over 12 months | up to 24 weeks | 6 weeks |
Parental leave at PostHog is designed to be more generous than your local jurisdiction's legal requirements. This means that in most cases you will receive the PostHog policy, if you live in a country with more generous parental leave, then you will receive that. This PostHog policy is not designed to be _in addition_ to your specific state/country policy. PostHog uses the "top up" method to administer paid leave. This means that if you receive any statutory leave, PostHog will top this up to your full pay.
We only pay the enhanced parental leave in one continuous block.
Parental leave isn't supposed to be combined with our unlimited PTO policy here - we aren't prescriptive and will trust your judgement. If you need a longer break after childbirth or a staggered return, log it in the Ops platform or speak to your manager. But please note that we usually won't allow you do a combination of parental leave plus a long holiday in addition to that to extend your time off.
Please log parental leave in the Ops platform as soon as you feel comfortable doing so, and in any case at least 4 months before it will begin. The People & Ops team will follow up on any logistical arrangements around salary etc. and any statutory paperwork that needs doing.
Maternity leave
The above is in reference to Paid Time Off (PTO). Maternity leave can be extended using unpaid time off, please work with your team to find a reasonable solution for both your family and your team, and log the total amount of time you expect to take off in the Ops platform as soon as possible.
For quota-carrying Sales roles taking 12 weeks or longer, your OTE will be calculated by averaging your sales quota attainment for the prior two full quarters (capped at 100% OTE).
Paternity leave
We do not offer unpaid leave for Paternity leave.
Birthday and anniversaries
We celebrate all the big and little milestones at PostHog, including birthdays and work anniversaries. We celebrate each team member as a reminder of how much we appreciate them. Kendal is currently responsible for organizing these.
Birthdays
We organize our birthday gifts through Micromerch. They are sent out usually a week prior to the big day! We try to switch up what goes into the birthday boxes every so often so you won't receive the same thing twice.
Anniversaries
All our anniversary gifts are created with Micromerch. On your first anniversary with PostHog, you will receive an exclusive cap and pin. On your second anniversary you'll be gifted custom tee and pin, and on your third anniversary, you'll receive a custom sweatshirt and pin... try to collect them all!
All anniversary gifts will be sent by Kendal, but if for whatever reason, you need to send one yourself, you can do this by creating an order in Shopify.
4th year anniversary
On your 4th anniversary at PostHog as a big thank you for sticking with us, we give you a choice of 3 gifts:
Sage Barista Touch coffee machine or Aiden Precision coffee maker
Apple 27-inch 5K Retina Studio Display with standard glass and tilt-adjustable stand
On the run up to your anniversary, our Ops team will send you a link to the gift options questionnaire and order your 4 year anniversary gift once we receive your completed form. Thank you for making PostHog great!
5th year anniversary
To mark five years at PostHog, you can get a brand new hedgehog profile illustration drawn to replace the one taken when you joined. Send an updated photo to our Graphics team and they'll get it over to our illustrator. Once it's ready, the new illustration will be sent to you.
The better you are at your job, the better PostHog is overall!
Books
Everyone at PostHog is eligible to buy books to help you in your job.
The reason we think books can be more helpful than just Googling stuff, is that the level of quality has to be higher for them to get published.
You may buy a couple of books a month without asking for permission. As a general rule, spending up to $50/month on books is fine and requires no extra permission. You can use your books budget towards audiobooks and podcasts as well, if you prefer.
Books do not have to be tied directly to your area, and they only need be loosely relevant to your work. For example, biographies of leaders can help a manager to learn, and can in fact be more valuable than a tactical book on management. Likewise, if you're an engineer, a book on design can also be particularly valuable for you to read. Additionally, we host a monthly book club called BookHog, and the budget can be used for those books as well.
Training budget
We have an annual training budget for every team member, regardless of seniority. The budget can be used for relevant courses, training, formal qualifications, or attending conferences. You do not need approval to spend your budget, but you might want to speak to your manager first, in case they have some useful feedback or pointers to a better idea.
We strongly encourage all non-technical team members to take some kind of entry level programming course - it's part of our 'you're the driver' culture that everyone can at least understand very basic concepts around software development. Codecademy is a good place to start and they cover many of the technologies we use, such as Python and React.
The training budget is $1000 per calendar year, but this _isn't_ a hard limit - if you want to spend in excess of this, request an increase to your budget in Brex and it should usually be granted.
If possible, please share your learnings with the team afterwards!
Conferences
You can use your training budget for time spent talking at conferences and user groups, including coaching others. It is expected that you would spend up to half a day a month on these activities. Like the training budget, this isn't a hard limit. If you think you need more than that talk to your manager in the first instance.
We track a short list of metrics in each per-product growth review. The idea of a standardised list of metrics is that each product team has roughly the same metrics they care about, and we can compare metrics across products and across time, such as revenue growth, to see how we compare.
Our growth review metrics strike a balance between depth, efficiency and "measuring what matters". We want to make sure our metrics alert us of potential negative (or positive!) developments, giving us enough signal to dive deeper into lower-level metrics.
If as a new product manager or team lead you want to look at a wider range of metrics, please do! These can either be incorporated in the growth reviews, or in ad-hoc metrics reviews you or your team are doing.
Metrics we use in growth reviews
Revenue
These queries are written and owned by the . They are standardised across products, and match the combined PostHog revenue queries. If you are intending a change, please chat to the billing team first.
Link to combined revenue dashboard
Link to per-product revenue dashboard
Note that currently, refunds are not removed from per-product revenue, which is something to note in a growth review if there is a sizable refund that month.
| Metric | Notes | | --- | --- | | Monthly recurring revenue (MRR) | | | Annual recurring revenue (ARR) | | | MoM growth rate | For more mature products, we want this to be over 9%, for newer products between 15-20% on average | | New revenue growth rate | | | Revenue expansion rate | | | Revenue contraction rate | | | Revenue churn rate | | | Revenue retention rate | | | Total paying customers count | | | Paying customers growth rate | | | Quarterly net revenue retention (NRR) | Instead of a rolling metric, we use the quarterly values and report on it once a quarter. The rolling metric is available on the dashboard too, as it can be helpful for debugging | | Annualised NRR | Same as above | | Revenue share | For revenue products like data pipelines or product analytics, it makes sense to calculate CDP/batch exports/anonymous-only share of revenue, to understand individual product contribution better |
Usage
Product usage metrics are defined by the PM or small team lead. When setting up metrics for a new product, it’s recommended to start with a longer list and trim it once user behavior is better understood. We recommend adding all relevant product metrics to one dashboard that is accessible, kept up to date and reviewed by the whole small team. For better discoverability, some of us use the appendix ™ to mark the primary usage dashboard.
This dashboard can also include NPS & support metrics (see below).
Link to session replay usage metrics dashboard (example)
| Metric | Notes | | --- | --- | | Unique monthly users - count | As defined by a key product action we also use in the activation definition, such as “flag created” or “recording analyzed” | | Unique monthly users, growth rate | | | Unique monthly organizations - count | Same definition as unique monthly users | | Unique monthly organizations, growth rate | | | Activation | Guide how to define activation for a new product; Dashboard that contains all per-product activation queries | | Usage retention (1, 3, 6-month) | Report on it once a quarter. Retention changes slowly, it will be easier to see changes zoomed out |
NPS
We have a NPS survey set up for each product. They need regular updates due to some survey limitations. If you want to set up a new NPS survey, speak to the Surveys PM (Cory Slater), he can help you set one up and keep it updated.
We track a 4-week NPS score, but we don’t have the volume of responses we need to get reliable results. This is why we include the open-ended feedback in the growth reviews, as this is usually more actionable.
Link to session replay NPS survey (example)
Link to session replay 4 week NPS score insight (example)
Link to session replay list of feedback insight (example)
| Metric | Notes | | --- | --- | | NPS score - last 4 weeks | Include constructive feedback as a comment in the spreadsheet for context |
Support
Similar to our revenue metrics, we are reusing queries the support team has set up, broken down by product. If you need to make a change or want to understand how SLA reporting works in detail, speak to the support team.
Link to overall support dashboard
Link to per-product ticket count insight
Link to per-product SLA insight
| Metric | Notes | | --- | --- | | Created tickets | | | Escalated tickets | | | Escalated tickets - SLA | The insight also tracks non-escalated tickets SLA, which is useful to be aware of, but we don’t need to report on it in every growth review | | Ratio no. of users vs. no. of tickets | Formula dividing no. of tickets / unique monthly users |
Metrics outside of growth reviews
If there are any other metrics you want to track to understand how well your product is doing, or which areas need improvement, go for it! Just make sure you are not tracking too many metrics, causing you to lose sight of what matters.
Tips for increasing metrics awareness in a small product team
If you are a PM at PostHog, you will be more successful if your whole team is aware and keeps track of your per-product metrics, instead of just you summarising growth review insights once a month. Here are some tips we found are working well:
Speak to your team what they care about and are interested in tracking, and add those metrics to your dashboard
Link the revenue & usage dashboards in your team’s Slack channel, so they are easy to find for your team
If your team has shipped a new feature, encourage them to set up an event, and track the new feature’s usage on the usage dashboard. For example you could have a “feature usage” section on the dashboard that tracks multiple features
Some teams do a “metrics Monday” where they review the usage dashboard together in the Monday standup, looking for trends and anomalies that may help you make "mid month adjustments". These sessions are usually led by an engineer, not the PM
You will likely have to try a bunch of things to find what sticks with your team. Ultimately, you want to make sure you and your team are looking at the same metrics, and everyone in your team knows how to find the relevant dashboards. It’s a team effort!
Understanding your product's infrastructure costs helps you make pricing decisions, contextualize growth reviews, and catch problems early. This guide covers how to build per-product cost allocations.
Why this matters
As products scale, margins matter. A product with healthy margins can afford aggressive pricing; one with tight margins needs to be more careful. You can't know which you're in without understanding costs.
Cost visibility also helps you:
Spot inefficiencies (why is this component 3x more expensive than expected?)
Measure engineering wins (did that optimization actually save money?)
Make pricing decisions (can we afford a price cut?)
Catch cost spikes before they become problems
When to do this
This makes sense for:
Products with product market fit
Products with meaningful revenue
Products with non-trivial infrastructure (storage, compute-heavy)
Products where you're considering pricing changes
For early-stage products, don't bother. Ship first, optimize later.
The process
1. Map your architecture
Before talking to infra, sketch out what your product actually uses.
Write path: How does data get in?
What services process incoming data?
What queues buffer it?
Where does it get stored?
Read path: How does data get back to users?
What services handle queries?
What databases get hit?
Storage: Where does data live?
S3 buckets
ClickHouse tables
Redis/caches
Postgres
You don't need to be perfect. The infra team will validate. But a rough diagram saves time.
2. Understand the cost buckets
Infrastructure costs fall into two types:
| Type | What it means | Examples | How to allocate | |------|---------------|----------|-----------------| | Direct | Tagged specifically for your product | Product-specific k8s nodepools, dedicated S3 buckets | 100% to your product | | Shared | Used by multiple products | Load balancers, reverse proxies, shared caches | Proportional (e.g., 20% of traffic = 20% of cost) |
Direct costs are easy. Shared costs require estimating your product's share of usage.
3. Work with infra on tagging
Reach out to #support-infrastructure to kick off the process – they can help you estimate your product's traffic share and navigate the tooling.
We use a FinOps tool for cost allocation. The infrastructure team sets up allocation tags that group AWS resources by product/function.
What you bring:
Your architecture diagram
List of services that should be allocated to your product
An engineer who can validate the list is complete
What infra does:
Verifies which resources are already tagged
Identifies gaps (resources that should be allocated but aren't)
Sets up allocation rules
Creates reports you can pull
Expect iteration. First allocations are rarely complete. Common gaps:
Inter-AZ data transfer (network costs between availability zones)
Shared infrastructure not proportionally allocated
Read-path resources missing (easy to focus only on write path)
ClickHouse costs (separate process)
If your product queries ClickHouse, you'll need to work with #team-clickhouse to get query cost attribution. This is separate from FinOps tagging.
ClickHouse costs are attributed by analyzing query_log to see which queries belong to your product. The ClickHouse team can help set up a query or dashboard to track this. Note that query attribution may require code changes to tag queries with a product identifier — this isn't just a dashboard exercise.
For some products (like Session Replay), ClickHouse query costs are a small percentage of total – queries are lightweight (list/fetch metadata). For analytics-heavy products, ClickHouse costs will be a much larger share.
We run ClickHouse in multiple regions (e.g., US and EU), make sure you account for costs in each.
4. Interpret the tags
The FinOps tool organizes costs using allocation tags. Here's how to think about them:
Product-specific tags (direct costs)
These capture resources dedicated to your product
Example: a "session replay" tag might include capture services, message queues, and S3 storage
Use these as-is – 100% goes to your product
Shared infrastructure tags (need a proxy)
These capture resources used by everyone
Example: an "ingress" tag might include load balancers and reverse proxies for all products
You need to estimate your product's share (e.g., "my product is ~20% of traffic, so allocate 20% of ingress costs")
Network transfer tags
Inter-AZ transfer costs show up separately from compute
Filter these tags to your product's services to get direct network costs
When pulling reports, make sure you're not double-counting. If you select multiple tags, check whether they overlap.
5. Build the cost model
Once you have the cost data, build a simple model for unit economics.
Get the totals:
Total cost from FinOps tool (direct + allocated share of shared)
Total volume from billing tables (recordings, events, whatever your unit is)
This helps you understand what drives costs. For storage-heavy products, storage will be significant portion of costs. For compute-heavy products, compute dominates.
Test your assumptions. Key inputs like traffic share, retention period, and storage rates are estimates. Check how sensitive your margin is to these — if your traffic proxy is 20% ± 5%, what's the range? If effective retention is 60 days vs 90 days, how much does storage cost swing? If the answer changes materially, document the range rather than a point estimate.
6. Document your assumptions
Every cost model has assumptions. Write them down so future-you (or someone else) understands what's in vs out.
Common things to document:
What's included in "direct" costs
What proxy you used for shared costs (and why)
How you calculated volume (billable units? ingested units?)
Retention assumptions for storage costs
What's explicitly NOT included
7. Set up monitoring
Once your allocation is stable, set up alerts:
Total product cost: alert if week-over-week change > 15%
Individual components: alert if WoW change > 25%
You want to catch:
Runaway cost increases
Broken tagging (cost dropped 50%? probably a bug)
Optimization wins (did that change save money?)
8. Add to growth reviews
Include margin metrics in your growth reviews:
| Metric | Notes | |--------|-------| | Total cost | From FinOps tool | | Cost per unit | Total cost / volume | | Gross margin | (Revenue - Cost) / Revenue | | Cost trend | MoM change |
Healthy products have stable or improving margins as they scale. If margins are declining, investigate.
What to expect
Timeline: 2-4 weeks to get a reliable allocation, depending on how well-tagged your resources are.
Accuracy: First pass is typically 80-90% complete. Shared resources and edge cases take time. Directionally correct is fine; perfect is not required.
Keeping it current
Cost models rot. The two main causes:
Architecture changes. When your product adds new services, storage backends, or processing pipelines, the cost allocation needs updating. Build this into your launch process — when shipping a new component, close the loop with infra and your FinOps team to get it tagged before you lose track of it.
Tagging breakage. Warehouse syncs, allocation rules, and report configurations can break silently. If your cost dashboard suddenly drops or flatlines, check the data pipeline before assuming costs actually changed. Set up a staleness check (e.g., alert if latest data is more than 3 days old).
Review your cost model quarterly at minimum, or whenever you ship significant infrastructure changes.
Common mistakes
Ignoring shared infrastructure. Your product uses load balancers, proxies, and other shared resources. If you only count dedicated resources, you're understating costs.
Forgetting network costs. Inter-AZ data transfer is easy to miss. It can be 5-10% of total costs.
Expecting precision. This is cost allocation, not accounting. You're trying to understand rough margins and trends, not get to the penny.
- Double-counting within shared infrastructure tags. An allocation rule may already bundle multiple resource types together. For example, an ingress tag might include both proxy compute and load balancers. Verify what's inside each tag before adding components separately — otherwise you'll overcount shared costs.
Not involving your FinOps vendor. If you use a FinOps tool, loop in their support team to validate allocation rules. They can confirm what's bundled inside a tag faster than you can reverse-engineer it from reports.
For products that have product-market fit and are generating revenue, we are doing monthly per-product growth reviews. We recommend to do the growth reviews at the start of the month, to review the previous month. Most growth reviews happen asynchronously with the PM reviewing key metrics, analysing anomalies and sharing an overview with the team in Slack.
Objectives
The objective of the growth review is to review key product metrics and understand changes that have occurred over the preceding four weeks. By reviewing metrics on a schedule, we can spot issues faster than when reviewing them only sporadically.
Looking at the same metrics regularly will increase our understanding how they relate to each other, whether metric changes are expected or exceptions, and will make efforts to improve them more successful.
The growth reviews should focus on analysing anomalies instead of expected metric behavior, especially as teams become more familiar with their data.
Outside of the regular monthly reviews, it’s the job of the Product Manager to regularly monitor these metrics, becoming an expert in their nuances. Should a metric deviate from the norm, they are responsible for presenting a well-researched explanation during the review.
Contents
Recurring analysis
During these reviews, we assess both input and output metrics. Input metrics, serving as leading indicators, significantly impact output metrics like revenue and retention.
Here are some examples:
Input Metrics: Things customers care about and factors in our control, like onboarding, key product actions (such as recording analyzed), and performance
As mentioned before, we aim to analyse the same set of metrics month over month, so we can see trends and anomalies. However, there can be cases where we decide to change a metric if it’s a better indicator of long-term success, particularly for product activation and key product actions.
We’ve found that the best way to review what is a quite long list of metrics is to combine all numbers (revenue as well as usage) in one spreadsheet with a new column for each month, and only open individual graphs where required. Below is a screenshot that shows a part of our growth review document. View the internal growth review spreadsheet for internal users.
Image: Growth review template
Monthly focus areas
To make growth reviews more actionable, each of the three growth reviews per quarter should have a slightly different angle:
If we have answered this, have we answered the biggest unknown for the product?
Are there any other topics / research we could work on as a secondary priority?
Second growth review of the quarter (5 weeks in):
Has our research yielded anything useful so far? What do we need to focus on understanding before planning in a few weeks?
From the things we've shipped so far this quarter, did we learn anything?
The outcome should be a list of open questions we should answer before the next quarterly planning
Third growth review of the quarter (9 weeks in):
What impact did the things we have shipped this quarter have on our metrics, and overall success of the product?
Looking back over the quarter so far, was growth healthy or are there issues we should address in the next quarter?
This session will be the least actionable, since it is happening around the same time as the quarterly planning, so it's a good time to do an overall health check
Deep dives
In each growth review, we usually do a couple of deep dives. Topics can be proposed in a preceding growth review, by team members, or it is simply something the Product Manager finds worthwhile. Here are a couple of examples:
Why was churn so high last month? Can we identify any reasons?
Where in the onboarding funnel do new users struggle?
Can we find leading indicators that predict long-term product usage? (e.g. Facebook’s 7 friends in 10 days)
Are there any difference between high ICP and non ICP customers in how they use the product?
Are our 10 biggest customers happy users of the product?
In-sync or async?
While monthly metrics reviews are important, they are not always actionable. Or, sometimes a metric might be suboptimal, but we decide not to focus on it, because we have more important topics to work on. Since PostHog's culture leans towards no meetings by default, we are not meeting every month to review the metrics in-sync. For in-sync growth reviews, the following guidelines apply:
1 quarterly in-sync growth review for existing products & PMs, ideally just prior to the quarterly planning
3 monthly in-sync growth reviews in a row for a new product or new PM
In-sync growth review any time a PM spots an issue in the metrics they would like to discuss
Additionally, the team lead and the responsible exec can also ask for a in-sync growth review
In-sync growth reviews are usually joined by the PM, the team lead and the responsible exec. Team members usually don't join the growth reviews, but a summary and the full analysis is accessible to everyone and shared via Slack.
Structure of the in-sync growth reviews
During the meeting
Metrics walkthrough
Led by PM
Participants note questions/comments they have
Review of questions/comments that were made before or during the metrics walkthrough
Walkthrough + discussion of deep dives
If required: Ad-hoc analysis of questions that came up
Agree on to dos for the next meeting
Before the meeting
PM prepares growth review
PM shares summary + links to analysis as well as the growth review document with the participants as well as the small team, so everyone has the chance to review the document and add notes before the meeting
After the meeting
PM shares summary of meeting discussion + outcome with the small team
PM makes sure all to dos are completed by the next growth reviews
Structure of the async growth reviews
Very similar to the above, except that the metrics walkthrough doesn't happen in a meeting. The PM shares a summary of the full growth review they prepared (key metrics, deep dives, anomalies and follow-ups) in the team's Slack with the team lead and responsible exec tagged. The whole team is encouraged to read up on the full notes & numbers that are linked, and ask follow-up questions.
There's no golden rule or perfect framework for prioritization. Here are a few things we should keep in mind when building mature products (products with substantial revenue and usage).
As products mature, we start to get more and more users who are not strictly within our ICP. Building for these users is great - but only if we've satisfied the core needs of our company-wide ICP first.
Should different products have different ICPs?
The very first ICP should always be the same. However, some products will fill their needs sooner than others.
Prevent churn before capturing growth
Not all churn is preventable - some customers' businesses don't make it. These customers are usually in our smallest revenue bucket and shouldn't really impact prioritization - unless the question is about how to make them more successful (which is a good question for sure, but not always relevant).
Preventable churn usually comes from:
Lots of bugs or particularly bad bugs
Missing features that competitors offer
Pricing
Not proving value often enough (eg. lack of use because it doesn't fit into their workflow)
Churn should be roughy equivalent across products - if yours is high, figure out why and fix it. Growth is less effective when you have a leaky bucket.
Use metrics as a guide, not the end-all-be-all
Trust your instincts and your convictions. If you _just know_ that something is the right thing to build, then build it.
Use metrics to help point you in the direction of what general area to focus on if you don't have conviction elsewhere.
Reprioritize enterprise feature requests when it makes sense
Larger enterprises will sometimes make esoteric requests. Other times their requests are totally valid - but we're busy with other things.
If the following are true, you should prioritize their needs immediately:
The customer represents a large churn risk
The feature has been requested by multiple customers and will be widely used
The lack of the feature prevents them from using the core product
Don't put off the hard things
If something seems important but difficult, and another thing seems easy, don't just do the easy things. Teams that do the difficult things will pull ahead. (assuming doing the difficult thing is possible - usually we want to see some evidence that it is)
We expect every PM at PostHog to be obsessed with users. Not just to enjoy talking to them, but to crave it. Great PMs feel uneasy when they or their team go too long without a real user conversation.
This obsession can show up in different ways: maybe in the past they’ve been a founder, a product engineer, a user researcher, or worked in another deeply user-facing role. The path doesn’t matter, but the curiosity does.
Talking to users is table stakes at PostHog. It’s a skill anyone who cares can learn quickly and keep refining over time, independently of their role and background.
A red flag is someone who’s worked in user-facing roles for years but shows little genuine curiosity or interest in understanding users.
---
Metrics ownership
Owning metrics requires two distinct capabilities:
Technical capability
PMs at PostHog are expected to do their own data analysis. They must be fluent in SQL and comfortable investigating metrics directly in our data warehouse. Additional experience in data modeling, analytics engineering, or building dashboards is a plus.
Depth of experience
Beyond technical skill, we look for PMs who have lived with metrics over time. Not just “churn was high, I ran five interviews, we fixed churn.”
We want PMs who have owned a product for months or years, stayed close to metrics like retention, churn, or revenue, and have gone deep into diagnosing and improving them.
Ideal candidates can share examples such as:
Defining or refining an activation metric and validating it
Breaking down retention by customer segment and acting on findings
Investigating churn and iterating multiple times until a successful fix was found
Building a churn model or cross-sell analysis to guide prioritization
This experience is much harder to teach than talking to users, so we actively screen for it.
---
Product sense
Finally, PMs need strong product sense: The ability to recognize what makes a product feel powerful, intuitive, and cohesive.
This doesn’t mean micromanaging every design detail. It means having the judgment to know when the product experience is drifting away from what “feels right” and stepping in at the right level of detail.
Examples of how this shows up day to day:
Spotting when a flow adds friction: Noticing when a process feels slower, more complex, or less clear than it should.
Recognizing when defaults feel off: Identifying when the starting experience leads users in the wrong direction or creates unnecessary confusion.
Calling out incoherence: Seeing when patterns, language, or tone diverge from the rest of the product and risk breaking the overall consistency.
Identifying one-way door decisions: Understanding when a design, naming, or architectural choice would be hard to reverse and needs another round of iteration before shipping.
Balancing speed vs. craft: Knowing when quick progress is fine and when quality and polish are essential for long-term product perception.
Ensuring cohesiveness: Making sure the product not only works, but feels coherent, purposeful, and aligned with the company’s principles.
Strong product sense means keeping a holistic view. Understanding not just what works, but what feels right to users and to PostHog’s product philosophy.
---
Hands-on with code (optional but valuable)
It’s not a requirement that PMs at PostHog know how to code, but it helps. PMs who can navigate a codebase, make small changes, or who have built small side projects often find it easier to empathize with engineers on their team and also with our target users (developers).
We also find that PMs who occasionally ship a small PR in their product:
Build stronger relationships with engineers
Better understand technical trade-offs
Make more grounded product decisions
They don’t need to be an engineer, but curiosity about how things work and the willingness to dive in and experiment is a strong advantage.
---
Culture fit
PostHog PMs need to combine strong opinions with deep trust in their team. We want PMs who:
Have conviction and clear opinions about the areas they are (co-)responsible for: Metrics, pricing, users, positioning.
Can confidently act as the informed captain when needed, owning decisions in their domain.
At the same time, know when to disagree and commit and support a team lead or another informed captain’s decision even if they personally would have done something differently.
Trust the team on all the decisions that are not theirs to make.
For example:
A PM may strongly influence pricing, positioning, or launch readiness.
But they should not overrule roadmap or technical decisions made by engineers or the team lead.
Their job is to lead with context, to make a compelling case grounded in data and user insight. If the team decides differently, the PM assumes good intent and trusts that choice.
Ultimately, at PostHog:
The team lead owns the product.
The PM ensures the product is positioned and priced for success, and keeps feeding user and metric context into the team.
We value PMs who show conviction where it counts, humility where it doesn’t, and trust in their team above all else.
PM onboarding buddy: Any PM who has been at PostHog for at least a year can onboard a new PM. Ideally they have some overlap or knowledge of the products the new PM will be working on. The onboarding buddy is the "owner" of the onboarding. They organise logistics, make a plan for the week, invite small team members, and serve as the main contact person for the new joiner.
Blitzscale manager: A PM typically reports into the Blitzscale member that leads the majority of the products the PM works on.
Small team & small team leads: While the onboarding buddy can share best practices and example PM projects, it's the role of the teams to share with the PM the context of the team & product they are working on (strengths, weaknesses, opportunities, threats, etc.).
A typical PM onboarding has the following phases:
Before the onboarding week
Pick a date & location for the onboarding week
Invite small team members to onboarding Slack channel, and for the in-person onboarding (at least 1 team lead is encouraged, team members are optional)
Make a plan for the onboarding week
Double-check everything else is taken care of (e.g. laptop has been ordered, Blitzscale manager is informed when & where the onboarding happens)
Onboarding week
We have two artifacts that can be reused and adjusted for each PM onboarding. We recommend putting both in a single Google Doc, tailored to the PM and team they're joining, to act as the main onboarding doc for each PM onboarding.
Invite PM to their teams standups & sprint plannings
The main focus of the onboarding week should be on those three topics:
Teach the PM our ways of working: owned by the onboarding buddy.
Teach the PM the high-level context of the product they are working on: owned by the small team leads.
Give them their first chunky project they can work on, and ask questions throughout the week: co-owned by the onboarding buddy and small team lead. A growth review is a really good example, because they will learn about our data and product health, and naturally start thinking about next questions.
Don't forget to do something fun too! Have some nice dinners, explore the city you are in, and schedule a fun activity with everyone around.
After the onboarding week
For a PM to be off to a great start at PostHog, it's important that the onboarding buddy continues to work closely with the PM in the first weeks and months, reviewing first projects and giving feedback.
This section covers how the onboarding buddy supports the new PM through this period. For the goals we set over the same window, see First 6 months success criteria.
First month
The new PM schedules a weekly 1:1 with the onboarding buddy. This session can be used to walk through ongoing projects, asking questions and giving feedback.
The new PM invites the onboarding buddy to their first growth review, so that the onboarding buddy can give feedback. Participation in further growth reviews is optional.
The new PM should actively share bigger outputs they've been working on with the onboarding buddy for feedback, e.g. RFCs or analyses.
In addition, the new PM should set up regular 1:1s with their Blitzscale manager and the small team leads they work with, and actively facilitate feedback and ideas for high-impact projects.
First month → end of probation
After the first month, the 1:1s can likely be spaced out or moved to on-demand.
The onboarding buddy should still review some of the big projects or RFCs the new PM is working on, and give feedback.
The onboarding buddy should also share their impressions & feedback with the small team lead & Blitzscale manager, so they have all the context for a successful probation period.
About the probation period
There is not one person alone who can assess the success of a new PM. Instead, the success of the probation period should be co-owned by the onboarding buddy, the small team lead(s) and the Blitzscale manager, with the Blitzscale manager making the call if, in a rare case, a new PM doesn't pass probation. They should regularly share feedback with each other, and of course the new PM.
Questions for the onboarding buddy:
Has the PM adopted our ways of working & style successfully?
Does the work they produce meet our bar (growth reviews, RFCs, pricing work, etc.)?
Do they bring good energy to the PM meetings?
Do they raise the bar across PMs for how they work, and best practices they share with the team?
Keeper test: If the PM were to leave, would you feel the loss, and fight to keep them?
Questions for the small team leads:
Can you see the PM bringing value to the team, by the context & user feedback they facilitate?
Does the PM create a collaborative environment in the team, vs. a confrontational one?
Does the PM's work, and ways of working, energise the team vs. draining them?
Keeper test: If the PM were to leave your team, would you feel the loss, and fight to keep them?
Questions for the Blitzscale manager:
Can you see the PM bringing value to the team, and making them more productive?
Does the PM help move projects and topics along you deem high impact and/or urgent for the team?
Do you observe a healthy team environment, with the engineers appreciating the work and energy the PM is bringing into the team?
Keeper test: If the PM were to leave the team, would you feel the loss, and fight to keep them?
First 6 months success criteria
This is a reusable template for the success criteria we set with a new PM. Copy the block below into the onboarding doc and adjust it per person and per the products they'll be working on.
### First day
- Set all accounts up
- Complete a PostHog quest (e.g. answer a question that requires a funnel, watch some recordings)
- Potentially find out from team leads what would be interesting to know
- Make one small PR to the handbook, e.g. update the PM team page (/handbook/product/product-team) with your team responsibilities
### First week
Overarching goal: You have access to everything and as a result can do work that is given to you with a reasonable amount of context, so you're not doing the work uninformed of data / what users are saying.
- Complete the onboarding checklist
- You can work autonomously and drive data analysis & user research for your teams
- Set up two customer interviews
- Set up 1:1s with your teams' leads. Other people we'd recommend meeting in your first couple of weeks are people from the product marketing, support, billing, sales, and growth teams. Most teams have a expert for your specific product, those are the best fit
- You've understood the roadmap + quarterly goals for your teams, and perhaps updated some of it on the roadmap (/roadmap)
- You've reviewed and contributed to at least one RFC or open discussion in your team → chat to a team lead about what makes sense here
### First month
Overarching goal: You know how to prioritise your own time and get the work done. You are regularly talking to users, reviewing data proactively, and confidently driving growth reviews, perhaps with a little assistance still.
- Set up 1:1s with everyone in your teams to get to know them
- You've helped your teams prioritise what to work on in their sprints
- You've prepared the first growth review for your team, have a solid understanding of the relevant metrics, and shared your insights with the team
- You've brought one big problem to the attention of engineers, (helped) write an RFC (if anything relevant is in progress) and added customer anecdotes and data
- Continuously setting up and running user interviews where necessary, and sharing your insights with the team
- After 30 days & the first growth review: organise an (informal) feedback session with the team, to get feedback on your work so far and how to improve your ways of working together
### Six months
Overarching goal: You can handle multiple products at once and can do the work for those products by far to the highest standard of anyone in the company.
- Continuously preparing the monthly product growth reviews for your teams, sharing findings with the teams, and making sure follow-ups are happening
- Always finding new and important problems to bring to engineers, backed up with data and user interviews
- Provide just-in-time feedback to engineers as we release new features, based on your own experience from using the product, and assisting the engineers where necessary gathering user feedback, following our principles of shipping and iterating quickly
- Participated in your first quarterly planning with the product teams you work with & exec, informing what to work on and what to add to the roadmap
- Continuously setting up and running user interviews where appropriate
Onboarding week schedule
This is a reusable template based on a previous onboarding. Copy the block below into the onboarding doc and adjust dates, names, and team specifics per person.
### Logistics
Travel & accommodation
- 🛬 Arrival: [date]
- 🛫 Departure: [date]
- 🛏 Accommodation: [hotel]
Additional attendees
- Onboarding buddy (full week)
- Team lead(s) (1 to 3 days, depending on availability)
Non-work events
- Dinners TBD, plan something fun together
Onboarding issue
- Track first day / first week / first month / 6 months goals in a dedicated GitHub issue
### Schedule for the week
Monday / Tuesday (depending on arrivals)
- Welcome!
- Handbook walkthrough with the onboarding buddy: mission, goals, teams, etc.
- Chat about PostHog's "big bets" (e.g. AI, Data Stack; schedule async sessions with the relevant owners)
- First-day to-dos from the onboarding issue
- Afternoon: how the onboarding buddy currently works with their teams, and what works / doesn't (1:1s, joining standups, in-sync vs. async growth reviews, etc.)
- Dinner (TBD)
Wednesday
- 1:1 with each team lead: product overview, intros, what matters right now, how the new PM can help
- How we do growth reviews (with the onboarding buddy)
- Start a growth review for one of the new PM's products
- Join team standups to say hi
- Dinner (TBD)
Thursday
- Morning: individual work
- Afternoon: walkthrough of the index of tools/resources the onboarding buddy uses a lot
- Example PM projects
- Dinner (TBD)
Friday
- Continue onboarding issue to-dos & first projects; get input from team leads on good first projects
- Afternoon: everyone heads home 👋
### After the offsite
- Connect with any remaining team leads for the products the new PM will work on
At PostHog, product managers (PMs) exist to bring clarity and context to their teams. They do not own roadmaps or dictate what to build next. Instead, they ensure the team deeply understands its users and its product’s performance, so that the right decisions happen naturally.
A PM owns the following three areas for their product and team:
Systems for user discovery & product thinking
Ensure a system is in place for the PM and engineers to hold discovery calls with users regularly.
Have a process for storing customer feedback so that it’s retrievable if we ever decide to use it (but not putting it “in the backlog.”)
Always know how the product is performing, both in usage and revenue.
Be aware of key trends, areas of concern, and emerging opportunities.
When metrics move in the wrong direction, create a plan or hypothesis for where to dig deeper next.
We are following a defined format for growth reviews to make sure it's easy to compare performance across products. See Per-product growth reviews for more information.
Pricing
Regularly review whether pricing aligns with the value users get from the product.
Identify when pricing or packaging creates friction for adoption, retention, or expansion.
If we decide to make a pricing change, work on a new pricing model taking into account our pricing principles, and involve the billing and marketing teams at the right time to get the changes live.
Track the impact of pricing changes on revenue, conversion, and churn to understand what worked and what didn’t.
---
A PM shares ownership of the following areas with their product team. This doesn’t mean it's a lesser priority for a PM to own projects here. It simply means product engineers are equally expected to contribute.
User understanding
Understand who users are, what problems they face, and how they feel about the product. This context should be sourced through any relevant channel: user interviews, surveys, PostHog, support tickets, GitHub issues, BuildBetter recordings, or other data sources.
Refine the product’s target persona(s) as the product matures, including their needs / jobs to be done, and track this information on the team page.
Monitoring of the competitive landscape & industry trends
Research best-in-class competitors and identify the biggest gaps between our offering and theirs.
Facilitate input from Sales, Support, and users, who are often acutely aware of the features we’re missing — especially if they’re about to cause someone to churn.
Keep an eye on new product launches and industry shifts to ensure we’re not missing emerging opportunities — see The Innovator’s Dilemma for reference.
---
A PM supports the following areas for their product and team. In consultation with the team, they might own projects in these areas:
Launching a new product in beta or in general availability
Deciding on what we should be building next
Providing feedback on UX for features
Everything else in the PM role builds on these foundations.
---
The product lifecycle and the PM's focus
The PM’s work evolves with the product. While the principles stay constant — context and clarity — the emphasis shifts by stage of the product.
Note on the table below: Especially in the early stages (1 & 2), a team usually doesn’t have a PM yet — product engineers own all product decisions.
Review this table with the context from “The role at a glance” (own/share/support) and “Deciding when to add a product manager to a team.”
| Stage | Goal | Key PM questions | Typical PM work | Example projects | |------------|-----------|----------------------|----------------------|----------------------| | 1. Idea → Beta | Get a first version of the product into users’ hands | - Who are we building for?<br/>- What is the 80/20 of features?<br/>- What needs to happen to get this into beta as quickly as possible? | - Lead or synthesize early user research<br/>- Define MVP scope and launch criteria<br/>- Shape initial positioning → who the product is for and why it matters<br/>- Coordinate beta launch activities and internal comms (beta program, website copy, docs) | — | | 2. Beta → General Availability | Launch a product that users want to pay for | - What’s missing in the product to start charging for it?<br/>- How do we charge for it? | - Lead or synthesize early user research<br/>- Decide pricing model<br/>- Coordinate launch activities and internal comms (beta program, website copy, docs) | PostHog AI pricing, renaming “Max AI” to “PostHog AI” for clearer positioning | | 3. General Availability → Growth Stage | Strengthen and expand adoption | - Are users truly getting value?<br/>- Where are they dropping off or getting stuck?<br/>- What drives retention and revenue growth? | - Regularly review usage data, churn patterns, and feedback loops<br/>- Run interviews and other user research to understand user sentiment and evolving needs<br/>- Research “best in class” competitors to highlight gaps<br/>- Identify the biggest opportunities for improvement or expansion<br/>- Frame problems clearly so the team can decide autonomously what to build next<br/>- Collaborate on pricing adjustments or repositioning as understanding deepens | User interviews on error tracking, Surveys pricing change, Research into needs of data engineers after re-positioning of Data Warehouse / Data Stack | | 4. High Revenue / Mature Product | Sustain growth and manage complexity | - What’s limiting growth now?<br/>- What new segments, features, or pricing models allow us to sustain a 9% MoM revenue growth rate? | - Track advanced revenue and usage metrics (activation, retention, revenue retention)<br/>- Share context and opportunities in identified problem areas with the team<br/>- Run “conviction sprints” to refresh understanding of ICP and persona(s) as they relate to the product<br/>- Ensure product strategy stays grounded in real user and business outcomes | — |
---
Deciding when to add a product manager to a team
Because most engineers at PostHog have strong product skills, many early-stage products don’t need a PM right away (stages 1 & 2).
At this stage, it’s typically the team lead’s job to decide:
What to build
When to release the first version
How to charge for it
...with feedback and guidance from the Blitzscale team.
There are a few exceptions: When a team is working on an infrastructure-heavy product, it’s more important that the team lead has strong engineering and infra skills than product skills. In that case, it can make sense to add a PM early who can focus on product direction, positioning, and user research while the lead focuses on technical execution.
In most cases, though, we add a PM after a product has launched and started generating revenue (stage 3). Once a product is live, product opportunities multiply, and it becomes the PM’s job to surface what matters most, connect user feedback with metrics, and ensure the team’s effort goes where it has the biggest impact.
Ultimately, it’s up to the Blitzscale team to decide when adding a PM will help the team ship faster and focus more effectively. When that becomes true, it’s time to bring in a PM.
---
Collaboration and decision-making with the team
PostHog is an asynchronous and autonomous organization. PMs do not “own” the roadmap or feature priorities. The closest thing we have to a “product owner” at PostHog is the team lead.
Instead:
Engineers choose what to work on next based on shared context.
The PM’s job is to provide that context: articulate problems, surface data, and make trade-offs visible.
When major calls (like positioning, pricing, or launch scope) need to be made, the PM and team lead collaborate closely to select an informed captain: One person who makes the decisions and sees them through. The other can provide feedback when requested, but focuses elsewhere.
A PM typically chooses their own projects, but the team and team lead can “assign” them tasks when needed.
So, what is the role of product managers at PostHog? PMs set context across multiple products for how products are being used, what the competitive landscape is like, what users are feeling about PostHog, and how they're using things.
Among other things, they
run growth reviews for products that have product-market-fit
Each PM belongs to a small number of our small engineering teams, so that all teams have a strong sense that the PM is there to support them equally. This also ensures that the PM has the time to dive deep into issues that require it. PMs join small team standups and planning whenever it makes sense, but they are not required to attend _all_ team meetings. This is up to the PM to decide when it makes sense to join these, and when their time is better spent elsewhere.
Here is a overview that shows which of our PMs currently works with which team:
<legend className="bg-transparent">Product teams with no PM currently</legend>
-
Product goals
Product managers primarily support their teams in reaching their goals. The top two priorities of each PM are to run a growth review at the beginning of every month for each of their products, and to organize regular user interviews. (Our rule of thumb is 1 interview per week per PM).
The quarterly per-product planning typically highlight the biggest blind spots a team or product has (e.g. what metrics or parts of the product do we think have potential, but we don't have enough context yet). Teams are encouraged to include their "biggest unknown" as a research goal for the PM to own as part of their quarterly goals. Findings should be shared asynchronously via a GitHub PR in the product-internal repo, and in the growth reviews or team standups where applicable.
To keep track of their projects across teams, PMs should track their personal quarterly goals transparently somewhere, for example in the public PostHog Meta repo.
As the PM team, we are usually also pursuing a couple of side projects each quarter with the goal of leveling up how we do Product at PostHog.
In Q2 2026, we are working on the following themes:
Ensure our metrics definitions are mature enough for our scale (e.g. inconsistencies in activation & product intent) -> Annika
Investigate ways to make updates to activation definitions sustainable & consistent -> Mike
Figure out information flows between product, growth and marketing, so that we get the right exposure for new and mature products -> Abe
Make sure our products & tracking are set up for a agent-first world
Tracking human vs agent actions, and defining success for each -> every PM
Make sure each product has use cases and a “reason for being” in an agent-first world -> every product team
Think about ideas how to fix the “accountability gap” in growth reviews -> Cory
From product teams, expect more accountability
From PMs, get growth reviews done early in the month
“Business-as-usual” themes:
Make sure we standardise best practices & share knowledge as a group of 5 (soon to be 7) without central leadership, and without adding bureaucracy & friction
Use our PM brownbags to share how we use AI to be more effective
Setting up - Initial planning and alpha development behind a feature flag
Alpha - Slowly adding customers you've spoken with to the feature flag
Beta - Opening up to all users who want to opt-in
General availability (GA) - Full release with pricing, and marketing launch
Please refer to the new product RFC for what the actual steps are. Duplicating them here would cause them to go out-of-sync extremely quickly. We'll simply explain the rationale behind each of the stages.
Early access features vs. feature previews
Two related concepts power most of the lifecycle below, and it's worth being precise about them because they're easy to confuse:
Early access features are what you (the product team) create and manage in the Early Access Management tab. Each early access feature is linked to a feature flag and moves through stages — draft → concept → alpha → beta → general availability — that control who gets the feature. This is the producer side.
Feature previews are the user-facing UI where people opt in to your early access features, in the feature previews section of their settings. It has two tabs: Previews, where users toggle active (alpha/beta) features on or off to try them, and Coming soon, where they register interest in concept-stage features so we can contact them with updates. This is the consumer side.
In short: you set a feature's stage in Early Access Management, and users act on it in feature previews. Both work at the user level only, not the org or project level.
Phase 1: Setting up a product
Create an early access feature in the concept stage early. Concept-stage features appear in the Coming soon tab of feature previews, and adding them early offers several advantages. It enables us to gauge interest in a new feature via sign-ups, equips our marketing teams with news they can promote to users, and ensures that betas can have sample users ready from the moment they launch.
When someone joins a coming soon waitlist (in-app or on posthog.com), a $feature_enrollment_update event with $feature_enrollment_stage: concept is sent to Customer.io through a data pipeline, and they immediately receive a simple confirmation that they're on the waitlist. See onboarding and lifecycle emails for the full flow.
Concept features can either be large or small, so use your judgement about what is of interest to users, but it should be something that you expect to work on in the next 3-6 months.
Phase 2: Alpha
During alpha, you're testing with a small group of customers you've specifically invited. It's fine to have bugs and your testers know that's the case. You're also actively working on fixing all known bugs before we can move this on to an opt-in scenario.
Phase 3: Beta
Beta is when you open up the product to all users who want to opt-in. Betas do not need to have been in concept stage first.
Moving a feature to beta
In Early Access Management, update the feature's stage from concept to beta (or alpha). This does two things:
The feature moves from the Coming soon tab into the Previews tab of feature previews, so users can opt in to enable it.
Users who registered interest during the concept stage are automatically opted in to the new stage, and a user moved feature preview stage event fires for each of them — when the from property is concept and the to property is alpha or beta, this triggers an automatic email letting them know the feature is enabled and now available, and asking for feedback.
Make sure the linked feature flag includes a product_key on the payload field to give people access to the product in their sidebar. Check the new product RFC for more details.
To give customers a minimum amount of information and usability, set up the early access feature so that:
It has a title and short description
It has a 'Give feedback' button
It has documentation (marked as beta) linked to it
Titles, descriptions, and links are all set on the early access feature in Early Access Management. Product teams are responsible for writing documentation, but the can help, if needed.
<CloudinaryImage src="https://res.cloudinary.com/dmukukwp6/image/upload/goodbeta_daa2ddca2a.png" alt="An example of a good beta" className="dark:hidden" /> <CloudinaryImage src="https://res.cloudinary.com/dmukukwp6/image/upload/goodbeta_dark_1dd8b2e833.png" alt="An example of a good beta" className="hidden dark:block" />
Betas should include a title, description, feedback button, payload with product_key and link to basic docs
Beta requirements
A beta doesn't need to be perfect, but it should provide value to the user and have base elements of functionality. It doesn't need to be feature complete, but it should provide more than a mocked up front end. We aim not to leave items in beta unless they are in active development. All betas should be clearly documented.
Betas do not need to be performant for high-volume users and can have big bugs, but should be clearly marked as such in the UI.
It's helpful to let the Developer Marketing team know when new betas are added. They'll then add the beta to the changelog, organize any marketing announcements, plan a full announcement for full release, create an email onboarding flow to help you collect user feedback, and anything else you need. You can let them know via the marketing Slack channel.
Collecting beta feedback
Teams are encouraged to collect feedback from users in current betas so that they can build better products and we have some automations in place to facilitate this.
Joining an alpha or beta triggers automatic feedback emails from the beta-feedback@posthog.com Google Group: alpha users get an immediate email warning of rough edges and asking for feedback, while beta users get an email asking for feedback after 5 days. By default, all team leads and exec team members are in this Google Group and will get daily digests of responses. Others are invited to add themselves to the group, or change their notification settings.
Regardless, replies to this Google Group are routed to the support inbox, where the support team assesses each customer issue or piece of feedback, responds to the customer first, and routes it to the correct engineering team for follow-up. PMs and team leads are still encouraged to respond to and action this feedback for their alpha and beta releases, and to give merch credits as a thank you where appropriate.
Teams can collect additional feedback if needed and the is able to help with creating feedback emails or funnels.
Phase 4: Releasing & launching to general availability
Once a beta is mature enough, you may want to launch it into general availability (GA).
For clearer ownership, we distinguish between releases and launches.
A release is when a product or feature becomes available to existing users for the first time. This is the product team's responsibility. The PM or team lead drives it, using their own release checklist. A release can be gradual, targeted, or fully open.
A launch gets a product in front of existing and new people – potentially millions who've never heard of us. This is led by marketing with the product marketer working from the launch checklist. If there is disagreement within a team about whether something is ready to launch, that team's lead should make the decision - it's either on or it's off ("we want to launch, but not yet" is off).
Releases
Releases are typically owned by the team lead or the PM. When planning a release, consider the following:
Product readiness - Is the product ready for GA? Because a GA product is available to PostHog's whole user base, it should meet higher standards for feature set and quality than a beta product.
Pricing - Does the release include pricing? A GA release typically does, as per our pricing principles.
Release goals - What do we want to get out of this release (and launch)? Are there objectives or metrics we want to target?
Rollout plan - How is the product going to be rolled out, to whom, and over what timeframe (e.g. 20% of users day over day)? Create cohorts if applicable.
For complex new product releases, we recommend setting up a Slack channel to coordinate with marketing and billing, and a Slack canvas that answers the above topics, linking to the new product RFC, pricing RFC and launch checklist for this product.
Sometimes we run an open beta, most often for AI products. Here we need to ship pricing earlier than usual because of the costs incurred, and we want to start marketing earlier too. However, the product quality doesn't necessarily meet our GA bar yet, which is why we keep the beta label.
For open betas, follow the same process you would for GA: a release first, then a marketing launch.
How do I work with marketing and billing teams?
The short version here is to try and give other teams as much notice as possible when starting a release & launch cycle. Marketing and billing teams typically ask for two weeks of notice before a major launch, as a minimum. It's the responsibility of the team lead to ensure these teams are aware of upcoming launches.
We actively seek (outbound) input in everything we work on. In addition to having multiple channels to continuously receive inbound feedback, we generally do active outbound feedback requests for:
General product and experience feedback. Continuous effort to gather general feedback on the product and their holistic experience with PostHog are led by the PMs supporting the team.
Usability tests. We generally run these for new big features the Engineering team is working on. Run by the engineer building that feature.
We recommend to create a cohort first (with a static copy), and use that as a display condition.
We have more and more surveys running, therefore it's best if a survey wait period is applied. We recommend 14 days.
If your cohort is large (>1,000 users), it's best to not roll it out to 100%, as you might get overwhelmed by the amount of interviews in a short period of time. Start with 20-30% and increase if you need more interviews.
PMs use cal.com for scheduling interviews, but you can choose a different tool as well.
If a customer has requested a feature through Slack, then message them directly.
Email customers who have subscribed to the feature on the roadmap.
Email a slice of users, e.g. top users of your product, or conversely, people who churned.
Email writing inspiration
When crafting user outreach, just put yourself in the shoes of the person about to receive the message. How can you help each other by getting on that quick call?
Here's an example of an email from a real project, crafted by Michael Matloka to learn about the problems of top users of the PostHog AI beta:
Subject: Quick chat about your PostHog AI experience?
Hey $FIRST_NAME, Michael from PostHog engineering here!
I'm focused on improving PostHog's AI features, and I saw you've been using our AI assistant.
I want to make PostHog AI 10x better for you – and it'll be a gamechanger to hear about your personal experience with it.
What do you say about a 30min chat about your product-building workflow, this week or in a couple of weeks? I promise in return you'll get a better tool for your job, plus $40 of PostHog merch. :)
Feel free to pick any time that suits you in my calendar at $CAL_DOT_COM_LINK, or send me your own calendar! I'm excited to hear from you.
$GMAIL_SIGNATURE
Scheduling
Add all feedback calls to the User interviews calendar. If the invite was created from your own calendar, you can simply add "User interviews" as an invitee.
During the call
We recommend recording interviews using BuildBetter. Please, always ask and make sure the user is comfortable with being recorded before doing so.
Once the user confirms they are okay with this, you can easily trigger the recording by clicking on Join a call on the BuildBetter homepage and copy-pasting the call URL.
If you do not have access to BuildBetter yet, drop a message in the #pm Slack channel.
If you have any feedback, bug to report or feature request for BuildBetter, we have a shared Slack channel with them, feel free to directly message their team there.
Do a quick round of intros if you haven't met previously.
If this is the first interview with the user, ask them for context about their company, their role, if they're technical.
After the call
If you used BuildBetter, the tool will automatically generate a summary for you under the recording. We recommend checking this, and adding any additional thoughts, because the AI can sometimes pick up things incorrectly. You can also generate a doc using the platform, where you can give very specific prompts for the outline of the summary.
We also want to keep recordings easily identifiable, therefore please rename the recording to [topic of the interview] user interview with [first name of the user], e.g. Web analytics user interview with Joe.
In case recording wasn't possible, add the notes to the [Google Doc][feedback-doc].
Share a short summary of the user interview in the #posthog-feedback Slack channel.
If the user reported specific bugs or requested specific features, open the relevant issues in GitHub. Be sure to link to their person profile in case our engineers needs more context when scoping/building.
Generate the reward for the user (see below).
Most of the time, the reward will be a gift card for the PostHog merch store. If it's the case, create the gift card in Shopify.
Follow-up with the user. Send any applicable rewards, links to any opened GitHub issues, and answers to any outstanding questions.
Rewards
We strongly value our users' time. As such, we usually send a small gift of appreciation. We have the following general _guidelines_, but just use your best judgement.
As a thank you for a call, we send users a gift card to the PostHog merch store with around $40 of value (great for a swanky T-shirt plus stickers).
If the user wasn't up for a call, but nevertheless replied with a bunch of useful feedback async, it's good vibes to send them smaller gift card, with $20 of value.
When merch isn't an option (e.g. user has received some already), we can offer the user an equivalent-value gift card with Open Collective.
We keep a log of user feedback in the following places:
BuildBetter. Starting 2025, we keep track of all user interviews (recordings & notes) in BuildBetter.
Feedback notes. Feedback notes are mainly kept in this [Google doc][feedback-doc].
Old recordings. All older recordings are kept in [this folder][recordings] in the Product shared drive.
Wherever feedback happens, share it
Any PostHog team member may receive feedback at any time, whether doing sales, customer support, on forums outside of PostHog or even friends & family. If you receive feedback for PostHog, it's important to share it with the rest of the team. To do so, just add it to the #posthog-feedback channel.
To ensure feedback durability and visibility, the #posthog-feedback channel should not be used as the primary source of <i>storage</i>. Please add the feedback to the main Google doc.
We strongly recommend that everyone joins at least one user call per month. Regardless of your role, you will always benefit from staying in the loop with our users and their pain.
Right now, PMs conduct a lot of remote interviews with customers about their specific products to bring context to their teams. As the number of PostHog products grows, and as customers increasingly use multiple products together, small teams risk developing a siloed view of how our customers actually use PostHog.
This matters because:
We lose context on how customers use multiple products together to complete their “job to be done”.
Teams optimize locally (their feature, their metric) and can accidentally degrade the cross-product experience.
We miss expansion opportunities because we don’t see how multiple PostHog products are used in the wild.
We miss important context on how to make a whole organization successful with PostHog, not just a single user or use case.
One partial solution is to go meet customers in person.
The following is a guide to share what has worked, and what hasn't for others who might want to try this out.
Setting up meetings
Create an open flexible script.
Develop a small, flexible set of questions related to your product area, but keep them broader than your typical product interview. Leave space to understand organizational dynamics, team workflows, and feedback across PostHog’s full product suite.
Feel free to use interview time to watch customers use PostHog directly, and ask them questions about why they take specific approaches as they navigate around the product.
Pick a metro hub, and research potential customers.
Choose a city with a good number of PostHog customers. Aim to identify ~12–15 customers across different sizes and maturity levels in that region. 15 may sound like a lot but you'll likely only be able to talk to 30% of these customers in the end.
You should do deep research on each account - take notes of which products, and features our customers are using Vitally (and of course PostHog). Who at those companies is using specific features and have a look a few session recordings. You should refer back to these notes before meeting the customer in person so you are informed.
Coordinate with Sales and Customer Success.
Post in the relevant Sales and Customer Success Slack channels about your plans. Tag the account owners for the customers you’d like to visit. Ask if it’s a good time to reach out, whether they have additional context, or if there are other relevant customers or prospects to reach out to as well.
Hey @[sales/cs members] I’m visiting [City] in 2 weeks and would love to meet some of our customers in person. I was thinking of reaching out to [customer a], [customer b], [customer c] Is now a good time to chat with them? Any other company who uses [product] a good company to go visit?
Join customer Slack connections.
Introduce yourself in each shared channel. A good intro might look like:
👋 Hey everyone! I’m [Your Name] from the PostHog product team — I’m visiting [City] next week and would love to meet some of our customers in person. If you’re up for a chat over coffee or lunch to share feedback on how you use PostHog please let me know
Have your Sales owner tag relevant people within the customer org in that Slack thread. When the account owner directly tags people, the response rate increases significantly. Here are some examples of what worked:
@[relevant customer member] any ideas on who from [customer] may be around and interested in this? We find this kind of thing to be pretty mutually beneficial for us to learn about your needs, but also to help shape our offering as well
@[relevant customer member], [Your Name] from the product team is visiting [City] next week. They can visit and help your team better get better set up with [products]
cc @[relevant customer member]
Schedule meetings.
Send calendar invites to everyone who responds positively. (We have typically found about 30% of outreach resulted in a meeting.)
Remind participants.
Post a friendly reminder in the thread a day before each meeting.
Conducting meetings
Be flexible.
Some meetings will last 30 minutes, others 2 hours. Lunch-time slots often work well, you can grab food together, build rapport, and then dig in. If other posthog team members are free and local in the area and want to come along, feel free to bring them too.
Bring merch.
Small things like hats or shirts go a long way. Drop a message in #merch and Kendal can help you place an order.
Structure the time.
An effective structure we found was:
20 min casual lunch or intro conversation
30 min “enablement session” — A place and time for as many of the customers's employees to come ask any PostHog-related questions they’ve been holding onto
20 min focused discussion — Your prepared questions and reflections. If you have a enablement session you can often sneak these questions in while working with customers.
After the meetings
Follow up.
Thank them for their time, and if the customers had questions you could not immediately solve in your in person meetings, message and tag employees at PostHog who could help.
Reflect and Share.
You should walk away with a much clearer view of PostHog from your customer’s perspective — not just how they use your product, but why they use PostHog, what types of questions or jobs they are trying to complete with PostHog, and how they use PostHog as a whole.
Share this in the posthog-feedback channel or somewhere similar. Feel comfortable sharing a longform write up and tag people and teams that are relevant. Here's an abbreviated example:
I had the opportunity to meet multiple customers in person over the last few weeks. I went in with the intention of focusing on data pipelines and messaging. However, I was open to receiving feedback on our entire product suite.
Two interesting customers were [customer a] [customer b]
[customer a] does xyz, and currently uses product analytics, session replay, data pipelines, and feature flags. I was able to talk to [customer employee name], who is the head of engineering, as well as another employee who ran a business unit. They were the power users.
They use product analytics in two main ways:
1. Business review. They had a high-level dashboard that was setup earlier and the leadership team would view it every single week, tracking changes in things like MAUs and other business critical product KPIs.
2. Ad hoc product insights. If the GM of one of the product lines had a question that popped up in his mind, he would go to PostHog to try to answer it first.
They used insights and dashboards and were pretty comfortable with breakdowns and some of the more advanced features. However, interestingly, they did not use sql queries and they were not aware that you could even use sql either.
Data pipelines was used to inform colleagues of high-value customer interactions in the product. This was done via a Slack destination. This is a very specific job to be done that I've seen in a number of other companies as well.
They were particularly interested in organization-level views, specifically:
- Organizations who have completed key events
- Organizations who have not completed key events
The primary complaint and frustration that they had with PostHog product analytics was that it was very difficult to search for people who have not done things or organizations where things have not occurred.
I was surprised that both [customer a] and [customer b] did not know you can use sql insights with product analytics @product-analytics-folks
One other thing to note was both customers also did not know where they could find a list of all events, and definitions (I showed them the data management tab). One customer commented it would be good if AI added a description automatically of what each event actually signified, and if there were easy ways to delete old events. Data governance came up a lot even with this mid sized companies
Support should be a competitive advantage for PostHog. Users choose us partly because they know they'll get exceptional support. They stay partly because they feel valued and helped. They recommend us partly because they've had great experiences with our team.
As PostHog grows, we're scaling thoughtfully. We prioritize keeping the team technical, staying true to our values, and maintaining our user-first culture. We value attitude and aptitude over experience - we need people who can jump into the unknown and figure things out. We want to contribute code and build tools, while keeping quality and user-centricity at the core of everything we do.
The benchmark we're aiming for: other companies should measure themselves against PostHog support - not because we answer tickets quickly, but because we genuinely help users succeed.
Own your work from start to finish. Be proactive and self-driven. Don't wait to be told what to do. When you see a problem, jump in and solve it. Be resourceful, curious, and hands-on. If something needs doing, figure it out and make it happen. Taking ownership means being accountable for outcomes, not just tasks.
Delight users
Go beyond solving problems. Create moments that make users' days better. Be genuinely caring, reassuringly human, and empathetic in every interaction. Surprise users with your thoughtfulness and responsiveness. Bring positivity and warmth to technical conversations. When users walk away from an interaction with you, they should feel helped, valued, and hopefully a little bit delighted.
Stay humble
Check your ego at the door. Take feedback as a gift and be open to learning from anyone, regardless of their experience level or role. Share knowledge freely with the team and communicate with transparency and honesty. We get better together by staying curious, admitting what we don't know, and helping each other grow. No one has all the answers, and that's okay.
Ship fixes
Be deeply technical and hands-on. Don't just log bugs or pass tickets along - write the fix yourself. Raise PRs for docs improvements, patch code, and solve problems end-to-end. We're engineers who happen to do support, not support agents who escalate to engineers. If you can fix it, ship it. That's what makes PostHog support special.
We communicate clearly and don't hide behind jargon. We're relentlessly curious - pulling at every thread when investigating an issue, and seeing the bigger picture beyond the immediate problem. We're always looking for ways to improve, whether that's our processes, our docs, or our own skills. We're thorough without being slow, thoughtful without overthinking, and we genuinely care about getting things right for our users.
We help users through in-app support and Slack channels for enterprise customers. But we don't stop at answering questions:
Ship code: We write and merge small bug fixes and improvements ourselves.
Improve docs: We contribute fixes, clarify sections, and add missing information.
Build internal tools: We create tools for internal efficiency, SDK health checks for proactive customer help, and automations to streamline our work.
Share product feedback: We surface patterns and pain points we see from users.
We provide support Monday through Friday, 9am GMT to 5pm PST. We focus on being consistently excellent during our coverage hours, with clear expectations set for users.
What we don't do
Route tickets: We solve problems ourselves rather than passing them along.
Hide behind processes: We care more about outcomes than following rigid procedures.
Work in silos: We're integrated into product development and actively contribute to company discussions.
Accept "that's not my job": If we can help, we do. If we can't, we figure out who can and make the connection.
You can build a good company by focusing on getting lots of customers. To build a great company, you must delight your existing customers. This means that the journey doesn't simply end once we sign up a user - even more important is to ensure that PostHog is consistently delivering value for them.
How we ensure amazing customer support
It's easy for customers to reach us
We have a few different routes for users to contact us. As an open source company, our bias is towards increasing the bandwidth of communication with our users and making it easy for them to reach us through a clearly defined, simple set of channels.
These are the ways in which customers can currently reach us:
Support ticket - Customers can create a support ticket directly within the PostHog app, under the help menu. This offers both users and PostHog engineers the best possible experience as the ticket is automatically populated with a bunch of helpful context that makes troubleshooting easier. When in doubt, customers should be directed here.
Dedicated Slack channels - For higher-paying (or potential higher-paying) customers, we offer a dedicated channel on our main company Slack.
Sometimes users ask about the progress of certain issues that are important to them on GitHub. We don't consider GitHub to be a proper 'support' channel, but it is a useful place to gauge the popularity of feature requests or the prevalence of issues.
Support is done by actual engineers
All support at PostHog is done by actual, full-time engineers. We have two types of engineers:
Support engineers, who are focused solely on support across multiple products and sit in the
Product engineers, who are focused on products and take on support responsibilities in a support hero rotation
What do Support Engineers do?
Right now, support engineers provide the first level of support for most engineering teams and specialize in certain products.
Support engineers respond to and solve as many tickets as they can for these products, or escalate tickets to the appropriate product engineering team if needed. There are certain products where the engineers on those teams are directly responsible for support:
Security
Merch
Wizard & Docs
Clickhouse and infrastructure teams
Any team whose product is not yet in GA
When we hire new support engineers they will usually spend the first few weeks focused just on analytics related tickets, until they've started to build more familiarity with the platform as a whole.
What do Support Heroes do?
One person on each product team takes on the Support Hero role each week. This is a rotating responsibility, where the person involved spends a significant chunk of their time responding to support queries in PostHog Support and sharing that feedback with the team and/or building features and fixes in response. We find each stint as Support Hero throws up a lot of really valuable feedback.
Response targets, SLAs, and CSAT surveys
Response targets
We have a high volume of tickets and we're a small team, so we're not able to respond to all issues equally. For this reason we prioritize tickets according to the customer's plan. We set a response target for each plan so that we can be sure that tickets are being handled effectively.
Note that tickets are automatically prioritized in PostHog Support and users are updated with information about response targets to set appropriate expectations. In all cases, tickets are routed to the appropriate team and that team is responsible for meeting the response target.
The response times listed below are targets for an initial response, and it's possible we will respond faster. These targets are listed in calendar hours Monday - Friday. Please note that we do not offer any level of weekend customer support.
| Plan level | Target response time | |-----------|----------------------| | Free | Community support only | | Pay-as-you-go | 72 hours | | Boost | 48 hours | | Scale | 24 hours | | Enterprise | 8 hours |
Within PostHog Support, we will further prioritize tickets based on their selected priority. If you come across a ticket that doesn't have the priority set appropriately according to our severity level guidelines, then you should update the ticket with the appropriate priority.
As a general rule, we aim to prioritize customers who pay for support, or who are otherwise considered a priority customer, to ensure they get the best possible support experience.
Follow-up / next reply response targets
Our follow-up response targets and next reply targets are the same as the initial response targets. We believe that customers should receive regular updates on the status of their query - even if the update is that we're working on it and there's nothing meaningful to report at present.
Escalated ticket response targets
When support engineers need to escalate issues to other engineering teams for deeper investigation, the investigations can take longer but we should still check in with the customer to let them know! For escalated tickets, our response targets are the same as for all other tickets.
_NOTE:_ The targets are for a reply to the user. If the escalation turns out to be a bug or feature request, the reported issue doesn't have to be solved by the response target date, we just need to reply to the user. That reply may be to let them know it won't be fixed right away, but that we have opened a bug report or feature request. If we've opened a feature request or a bug report, you can refer the user to the GitHub issue for updates, and Solve the ticket. If you're replying with info that should resolve the issue, leave it in a Pending state (will be auto-solved in 7 days if the user doesn't reply.) If the user replied to confirm the issue is resolved, Solve the ticket. Use On-Hold sparingly, e.g. if you intend to get back to the user soon (more than a week, less than a month.)
CSAT surveys
We send out a CSAT survey after a ticket has been resolved for at least 1 day using this workflow for tickets set to resolved and this workflow for tickets set to pending. The emails contain a link to the hosted survey with their distinct_id, ticket_id, and ticket_number as query parameters, which are being used alongside their satisfaction rating to capture a survey sent event.
We very occasionally receive messages from people who are abusive, or who we suspect may have a mental illness. These can come via the app, or Community Questions. We do not expect support engineers to deal with abuse of any kind, ever.
If this happens, notify Charles Cook, Abigail Richardson or Fraser Hopper. They will either take this on, or advise you on how to reply.
Dealing with legal requests from users
We very rarely receive messages from people wishing to make a legal claim against PostHog, such as cease and desist letters. These can come via the app, or Community Questions. Do not respond to these requests. Instead, notify Charles Cook or Fraser Hopper immediately. They will either take this on, or advise you on how to reply.
Community
Support =/= community - we consider them to be separate things.
Community questions and Discord
Community is not support, but it is one of our best sources of product feedback. Community questions and Discord show what users ask and say about each product area, in real time.
Questions are routed to team Slack channels by topic, so each team can see the posts about its own products. Support heroes are welcome to read their team's community posts when they have time, but it is not a requirement. PostHog AI and other community members answer most questions.
Tutorials
We want to help teams of all sizes learn how to ask the right product analytics questions to grow their product. To help, we create content in the form of tutorials, blog posts, and videos.
We've also created a bunch of useful templates that cover many of the most popular PostHog use cases.
Common issues & questions
Dealing with billing issues
Issues related to billing are handled exclusively by our billing engineers. Billing support is currently lead by Eleftheria Trivyzaki. Most tickets get routed directly to billing support, however some issues require technical investigation before the billing issue can be resolved. In such cases, let Eleftheria Trivyzaki know by messaging #team-support in Slack, and leave a private note on the ticket briefly explaining what will eventually be required. Complete whatever technical investigation is required and then let the customer know you are handing them over to billing support.
Users asking for demos, consultations or partnerships
We often receive requests for demos, consultations or other sales-related requests. Most of the time these can be escalated to the Sales team if they arrive via PostHog Support.
We also often get requests for partnerships, backlinks, or messages trying to sell us baby Yahama pianos. Sometimes, people want to invest in PostHog. Most of these are obviously spam and can be ignored, but if you think an opportunity may be genuine then you can forward it to Joe Black so he can take over.
Users asking for their data to be deleted
Most of the time users can self-serve deletion requests and should be encouraged to do so in order to save time and ensure they take responsibility for deleting their own data. Users can delete their environment, project, and organization in the appropriate 'Danger Zone' section of their settings page if they have the correct permissions. Admins can remove members from their organization in the Members page.
If a user refuses to delete their own data, you must first confirm they have the permissions to do this by checking their email address matches that of an organization admin. As an extra layer of security, you should also ask them to confirm their address by emailing you directly from it (e.g. not through PostHog Support.) Only then should you delete any data on their behalf.
If a user asks for us to delete all of their _personal_ data in compliance with GDPR, you should confirm their identity as described above and delete the user from PostHog. Finally, you should notify Joe Black so he can delete customer data from our email marketing systems, and Fraser Hopper so he can coordinate further data deletion across our systems.
Targeted deletion requests
Occasionally users will mistakenly share sensitive data which should not have been shared via event/person properties. As such they wish to be more targeted in their deletion by removing only certain properties or events instead of an entire project.
Before taking any deletion action, they should ensure that they are no longer sending the sensitive data to us either by redacting information client-side or setting up a CDP transformation. If they don't do this first they will continue to send us the sensitive data even after deletion is actioned.
Due to the nature of how our infrastructure works, events and properties cannot be amended once they are stored in Clickhouse. As such, the only way to remove sensitive data is to delete the person profile associated with the events where the sensitive data has been captured. This can be achieved in the app or via the API. As per our deletion docs, the person profile will be removed immediately but the events will take some time (days or even weeks) to be removed.
If they aren't using person profiles, they won't be able to use this method and as such will need to revert back to deleting the entire project containing the sensitive data.
For customers spending $20K and above a year our Clickhouse team may be able to craft a more targeted event deletion/property amendment query. There are no guarantees here and it is very time consuming hence why we will only explore this for high-paying customers. If you have a customer in this situation and the above methods won't work for them; escalate a support ticket to the Clickhouse team with as much detail as possible on the event and property names where the data is leaked so that they can create a query to process the deletion. To expedite this you should ask the customer for a SQL query which correctly identifies the events or properties to be deleted, or help them in crafting that. Also verify that the numbers returned by this query match what the customer expects to see. Once started this can also take some time (days or weeks) so you should set those expectations with the customer.
If they need to remove data immediately, the only way to do this is the delete the project. There are no other alternatives.
How should I handle organization ownership transfers?
In case a user requests for organization permissions to be altered (e.g. the only member with owner membership left the company) follow these steps:
The ticket should be assigned ideally to Platform features
Ask the user to get the current owner to log in and update ownership.
If the owner left and they can get access to the current owner’s email, ask them do a password reset and then login as the owner and perform the action themselves.
If not, we should email the account owner’s email to see if we get a bounce back. Also check how long it is since they logged in.
If accessing the current owner's email is not an option, we should have the person requesting access verify their domain ownership by providing a TXT record example for posthog verification.
Once verified, membership can be updated for the request.
Note, if they’re on a paid plan we might also need to switch the contact on Stripe via a separate request to billing @posthog.com
How should I handle 2FA reset?
Locate the user's profile in admin and send them a 2FA reset link. The link expires in 24 hours, so let the user know they'll need to use it within that window.
How do I handle a bug report or feature request?
For feature requests from low priority users, give them this link and suggest they open a feature request on our public roadmap.
For bug reports from normal and high priority users (assuming you've confirmed it's a bug, and that there's not already an open bug report):
Be sure to include a link to the insight (or other), below the repo steps
Include a link to the ticket in the additional info section of the bug comment.
Reply to the user to thank\* them for alerting us to the bug. Let them know you've opened a bug report and provide a link to it.
Let them know they can follow the bug report on GitHub for updates.
When sending the reply, change the ticket from Open to Pending
In Slack, go to the team channel for the team that handles the feature that the bug report applies to (e.g. #team-product-analytics) and alert them with a post like "New bug report from a high priority customer: https://github.com/PostHog/posthog/issues/nnnnnn"
Steps for feature requests from normal and high priority users are pretty much the same, but use this form instead. If you find that there's already a matching feature request open, reply with a link to the feature request, and let them know they can upvote it by adding a "+1" comment.
Reaching the sales / CS / onboarding teams
If you need to reach the humans who look after a customer — for example, a support ticket should be handled by one of the sales / CS / onboarding teams, or you've spotted a sales lead — message #group-cs-sales-support to let the teams know. It's the cross-team channel for everyone who owns customers.
How should I handle self-hosted setups?
It's fine to politely direct users to the docs for self-serve open-source support and ask them to file a GitHub issue if they believe something is broken in the docs or deployment setup. We do not otherwise provide support for self-hosted PostHog.
We use PostHog Support as our support ticketing system. This ensures that we don't miss anyone, especially when their request is passed from one team to another at PostHog, or if they message us out of hours or over the weekend. PostHog Support allows us to manage all our customer conversations (email, widget, Slack, MS Teams) in one place and reply back on the same medium.
This page covers the practical, day-to-day mechanics of working tickets: where to find yours, how to prioritize them, what each status means, and how to escalate or hand a ticket off cleanly.
How do tickets get created?
Customers can reach us through several channels, and every one of them lands as a ticket in PostHog Support.
Email. Customers can email any of the addresses we've set up in our email channel settings.
Support widget. Customers can open the support side panel by opening the bottom-left More menu and clicking Support (direct link). This raises a widget channel ticket. Widget tickets are also raised when a customer gives feedback on a feature, or whenever they hit an error in the app.
Slack. Enterprise and high-paying customers may have a shared Slack channel with us. Any channel listed as a support channel in our Slack settings will automatically raise a ticket every time a message is posted. For any other channel that has @SupportHog in it, anyone can either react to a message with a :ticket: emoji or mention @SupportHog, and a ticket will be raised in PostHog Support. In shared channels, @SupportHog also watches for messages that look like potential support cases. When it spots one, it replies on the thread asking the customer whether they'd like to open a ticket (Open ticket or No thanks), and reminds them they can always raise one with the :ticket: emoji or by mentioning @SupportHog.
MS Teams. Enterprise and high-paying customers may also have a shared MS Teams channel with us. Any channel listed as a support channel in our Teams settings will automatically raise a ticket every time a message is posted. For any other channel that has @SupportHog in it, anyone can @mention SupportHog to raise a ticket. Note: unlike Slack, reacting with a :ticket: emoji in MS Teams does not raise a ticket.
How does a customer know their ticket was created?
For email and widget channel tickets, we use a workflow to send the customer an email letting them know we've got their ticket.
For Slack and MS Teams customers, the @SupportHog bot replies on the thread with a message confirming that a ticket has been created.
Creating tickets on behalf of customers
Sometimes a user will reach us somewhere that isn't a proper channel — a reply to an old, already-solved ticket thread, a question over Twitter, or an email that spirals into several separate issues. In these cases it's best to create a fresh ticket for them, so the correct SLAs apply and each issue stays distinct and easy to assign.
You can ask a user to open a new ticket themselves, but it's better if we do it for them. At the top of the PostHog Support page you can create a new ticket and fill in their details — this makes sure the right tags, SLAs, and so on are applied automatically.
A couple of things worth doing depending on where the issue came from:
If the user raised it somewhere public, like Twitter, it's a nice touch to let them know you've opened a ticket on their behalf.
If they were replying to an old, already-resolved ticket, mark that old ticket as resolved once you've moved the new issue into its own ticket.
Forwarding customer emails
If a customer has emailed you directly and the conversation should live in support, you don't need to copy anything over manually — forward the email to one of the support addresses in our email channel settings and a ticket will be created. Default to the address set as primary unless you have a reason to use another.
Make sure the customer's email address is included as a cc on the forward. This is how the ticket gets associated with the customer, so that they receive our replies and the right tags and SLAs are applied.
Where do the tickets live?
It depends on your role:
Support team members work from their SME view. This is available to you as a bookmark in your SME Slack channel.
Support heroes work from their team view. This is available to you in your team's #support-<team-name> channel.
If you ever forget where your view is, or you want to look at another team's view, click the Saved views button in PostHog Support to see every available view.
Tags and what they mean
Tickets are tagged automatically to tell us who the customer is, what plan they're on, and which part of PostHog the ticket relates to. Understanding the tags makes prioritizing, escalating, and transferring tickets much easier.
Customer and account tags
top_20 — this set is regularly reviewed by the sales team, and the priority is applied to the customers we'd like to have an especially fantastic support experience.
churn_risk — customers that sales/CS have flagged as a risk of churning. We want to be more responsive with these customers.
new_customer_onboarding — applied to tickets from recently created organizations. We want new customers to have a great onboarding experience, so these tickets get a tighter SLA.
plan_* — describes which plan the customer is on (for example plan_enterprise).
goodwill_enterprise — there's a sales/CS person assigned to the account, so we treat them as enterprise.
unknown_slack_default_enterprise — applied when we know a ticket came from a Slack channel but we can't identify the organization associated with the individual's account. This usually happens when the email isn't present in someone's Slack account, or the email in their Slack account doesn't match the email they use for PostHog. We default these tickets to plan_enterprise.
unknown_msteams_default_enterprise — the same as above, but for MS Teams. These are also defaulted to plan_enterprise.
ae_* and csm_* — applied if the account can be identified in customer analytics and has an AE and/or CSM assigned to it.
team_* — describes which team the ticket relates to. Applied based on the current state of the teams page and the feature ownership page.
support_needs_triage — applied when the classifier can't determine which small team the ticket relates to.
exclude_from_reporting — add this when a ticket is spam, an auto-response, or anything else that genuinely shouldn't count towards our total metrics and numbers.
auto_closed_security and auto_closed_merch — applied when the security or merch workflows auto-close a ticket as known spam. These tickets are also tagged exclude_from_reporting.
content_warning — applied automatically to tickets from organizations known to track adult or otherwise potentially offensive content. We have a clear definition of who we do business with, which means customers tracking this kind of content aren't automatically excluded. The tag exists so that team members don't inadvertently see anything offensive when impersonating a customer. If you ever discover potentially offensive content in a customer account, please update the workflow that applies this tag so the rest of the team is aware.
Prioritizing tickets
As a rough order of priority, work through:
top_20 and churn_risk customers
Customers on an enterprise plan (plan_enterprise)
All other paying customers, by most-breached ticket
That ordering is simply a starting point, not a rulebook. Use your judgement about what the next most important thing to work on actually is:
If something has been breached for a long time, work on it regardless of plan.
If something comes in that looks like it could be a wider issue, work on it regardless of plan.
Prioritization is not a set of hard-and-fast rules — we trust you to figure it out.
How will I know if a ticket is nearing a breach of our SLA targets?
TBD - SLA alerts coming soon.
Ticket statuses
Getting statuses right matters — it's how the rest of the team (and our reporting) knows what's actually happening with a ticket.
New - a new ticket that we haven't responded to yet.
Open - an open ticket that has either had a response from the customer, or one where we're continuing to investigate.
Pending - a ticket we've responded to and are now waiting on the customer for. Use this when we're asking something of the customer, or when we're not yet certain the ticket is resolved.
On hold - use this sparingly, and when you do, pair it with a snooze. The snooze means the ticket doesn't sit on hold forever — it comes back to you on a set date when you plan to check something or follow up. You might use this while waiting to confirm a billing invoice went through, or when you have a PR in review and intend to let the customer know once it ships. Do not use on hold while you're actively investigating — tickets we're actively working on should stay open.
Resolved - for tickets that are done. Use this when a ticket is obviously closed (for example, the customer has confirmed a fix or suggestion worked), and also when you're 90% confident that your response will resolve the customer's issue or question.
Working on a ticket
When you start working on a ticket, assign it and save it. This is the single easiest way to avoid two people investigating the same thing. Who you assign it to depends on your role:
If you're a support team member, assign the ticket to yourself.
If you're a support hero, you'll likely want to keep the ticket assigned to your team, so that every ticket your team is responsible for stays visible in your team's view.
To reply to a customer, write your message in the message box and click send. Once your message has gone out, double-check the ticket is in the correct status.
If you're a support hero and you ever have trouble responding to a customer — for any reason at all, including that you're not sure how to phrase something or you're just feeling stuck — reach out in #team-support. We're always happy to help.
How does a customer know we've responded?
For Slack and MS Teams tickets, your reply is posted directly on the thread.
For email channel tickets, your full response is sent to the customer via email.
For widget channel tickets, we use a workflow to send the customer an email letting them know we've responded and that they can see the full response in the support sidebar.
AI private notes
On some tickets you may see a private note from PostHog Assistant. This is an AI-generated note containing a response that the AI thinks is correct for the ticket.
Never copy and paste these responses — especially without checking them. AI can make mistakes, and it's your job to verify anything it says before it goes anywhere near a customer. By all means review these notes and rate them — it helps the improve them.
Attach private notes as you investigate. Future travelers will thank you: notes help the next person understand your thought process, they help engineers if you need to escalate, and they make it far easier for a teammate to pick up the ticket if you're on holiday or off sick.
Don't use private notes to communicate internally about a ticket — it's far too easy to miss them. If you need to ask something internally, raise it in Slack and then attach a private note with a link to the Slack thread. If you start any Slack conversation about a ticket, always leave a private note linking to it.
Escalating a ticket
To escalate a ticket to an engineering team, assign the ticket to that team. That's it.
Most tickets are default assigned to the support team, and are automatically tagged with the engineering team and SME grouping that best fit. To escalate to the relevant engineering team, all you need to do is assign the ticket to them.
If a ticket has been mis-categorized and is heading to a different team than the one it's tagged with, update the team and SME tags as needed.
Transferring a ticket to another SME group (within support)
If you're transferring a ticket to another SME group entirely, remove your SME tag and add theirs. Make sure the engineering team tag is up to date too — this keeps our reporting accurate.
If instead you want to give another SME group visibility without transferring ownership — for example, adding support_sme_accounts_billing so they can later enact a refund — just add their SME tag alongside your own.
Whenever you add an additional SME tag or transfer a ticket to a different SME group, attach a private note explaining why and what you're expecting to happen next.
Transferring a ticket to another team
To transfer a ticket to another team, assign the ticket to that team. As with SME transfers, whenever you change the assignee to a different team, attach a private note explaining why and what you're expecting. If you believe the ticket was mis-categorized, update the team tag as well so our reporting stays accurate.
Ticket activity history
If you're ever unsure how a ticket ended up in a particular state, or where a certain tag came from, check the ticket activity history. It shows every update that's happened on the ticket, including who actioned it — and that includes changes made automatically by a workflow.
Automations and workflows
A lot of the ticket flow runs automatically through PostHog workflows and realtime destinations — classification, tagging, SLA deadlines, notifications, CSAT, and more. You don't need to memorize all of this, but it's useful to know what's happening behind the scenes so you understand how a ticket got into a particular state (and where to look if something isn't behaving as expected).
Categorization
A classification workflow classifies tickets via a PostHog Desktop task. It sets the team_ and support_sme_ tags by looking at the current versions of the teams, feature ownership, and support SME handbook pages — so the tags are always derived from the current team names and SME groupings. The task then creates a support_ticket_classified PostHog event with the interpreted team's support Slack channel as a property. That event is consumed by a realtime destination which posts the ticket notification into the team's #support-<team-name> channel.
Assignment notifications
When a ticket is assigned to an engineering team's role — for example when support routes a ticket to Team Ingestion, or one team passes a ticket to another — a realtime destination posts a notification into the team's #support-<team-name> channel with the customer, the latest message, and a link to the ticket. The channel is derived from the assignee role's name, so it always matches the current teams page naming — this is one of the reasons role names, team names, and #support-* channel names need to stay in sync.
Assignments to the support, security, People & Ops (merch), and sales/CS teams are excluded — those have their own notification flows (see below). Assignments to individual people don't notify either: the ping is for "your team's queue just got a ticket", not for tickets someone has already picked up.
The same ticket and assignee combination notifies at most once per hour, so repeated or bulk re-assignments don't spam the channel. If a message can't be delivered to the team's channel (usually because the channel doesn't exist under the expected name, or the PostHog Slack app isn't in it), it's posted to #alerts-support instead with a warning.
Ticket lifecycle
When a ticket receives a response from the customer, we reopen it. If the responding customer is a top_20 or churn_risk customer, we also notify #support-top20.
When a ticket is in pending (i.e. we're expecting a response from the customer), we use this workflow to send the customer a reminder email after 5 days, and then resolve the ticket if it's still in pending after a total of 7 days.
When a PostHog team member responds on a ticket, we set the ticket status to open so the ticket is no longer marked as new.
SLAs / target response times
When a new ticket is created, this workflow identifies the customer's plan / account type and sets the relevant First Response Time (FRT) SLA deadline on the ticket. If the ticket is from a top_20 or churn_risk customer, we notify #support-top20. This workflow also assigns most tickets to the support team by default.
When a response is received from a customer, this workflow uses similar logic to the FRT workflow to identify the plan / account type — we redo these checks in case the customer's plan has changed since the ticket was created — and sets the relevant Next Response Time (NRT) SLA deadline. The NRT is not applied if the ticket already has an SLA set that is shorter than the NRT the workflow would apply.
After a PostHog team member responds, this workflow sets the update SLA deadline — the time within which the customer should receive an update from us about the progress of our investigation.
If a ticket is reopened by a team member (e.g. they change the status from resolved back to open because it was resolved by mistake), this workflow sets the NRT SLA deadline.
If a ticket is set to on hold, pending, or resolved, the SLA deadline on the ticket is cleared (via the on hold, pending, and resolved workflows).
If any of the SLA workflows can't set an SLA deadline, they alert #alerts-support — see Alerts.
CSAT
If we've auto-resolved a ticket that was left in pending, a CSAT email is sent to the customer from this workflow.
If we've changed a ticket's status to resolved, this workflow sends the customer a CSAT email one day later. We don't send CSAT emails for security or merch tickets.
We post some CSAT responses into #team-support using this workflow. If a comment is provided we always post the response. If there's no comment but the customer has given a low support or low product score, we also post the response into #team-support so we can investigate.
Sales / CS
When a new ticket comes in, this workflow checks the ticket's account in customer analytics for any assigned AE or CSM. If the account has an AE, it adds the ae_* tag; if it has a CSM, it adds the csm_* tag. If at least one of those tags is set, the workflow notifies the relevant account owner(s) in #support-managed-customers.
Security tickets
When a new security ticket is received, this workflow auto-closes some known spam. If the ticket isn't known spam, we tag it with team_security, assign it to the security team, auto-respond to the customer letting them know about our disclosure program, and then notify #security-reports.
We use this workflow to notify #security-reports when a customer responds on a security ticket.
Merch tickets
When a new merch ticket is received, this workflow auto-closes some known spam. If the ticket isn't known spam, we assign the ticket to the merch team and notify #merch-alerts.
We use this workflow to notify #merch-alerts when a customer responds on a merch ticket.
Alerts
Alerts about tickets needing attention are posted into #alerts-support:
If any of the SLA workflows can't identify a customer's plan / account type, no SLA deadline gets set. When that happens, the workflow posts an alert so we can investigate and set one manually. This applies to the FRT, NRT, update, and reopened ticket SLA workflows.
If a new email ticket arrives from one of our own addresses (merch@, security@, billing@, or support@posthog.com), this workflow posts an alert so we can check that nothing is misbehaving. Tickets tagged exclude_from_reporting are skipped.
When things break, we need to make sure users know what's happening and feel supported through it. This page covers how the support team handles incidents - what we do, when we do it, and how we stay aligned with engineering, marketing, and sales.
Raising an incident
Anyone can and should raise an incident if they suspect there is one. This includes support team members. When in doubt, always raise an incident - it's much better to declare something that turns out not to be an incident than to miss a real one.
Declaring an incident doesn't trigger any external notifications. It just creates an incident channel and alerts the right people internally.
If you're seeing multiple tickets about the same issue, or if something seems seriously broken, type /incident in any Slack channel to declare one. See the full guide on raising an incident for more details.
Once you've raised the incident, you should raise your hand to watch it from a support perspective, or actively hand it over to someone else on the team.
Your role during an incident
If you suspect an incident, raise one - type /incident in any Slack channel
When an incident is declared, a workflow posts to #team-support asking for someone to raise their hand
Whoever raises their hand owns watching that incident from a support perspective:
Monitor the incident channel for updates, and ensure the status page has clear messaging
Respond to new and existing tickets related to the incident, creating a standardized response as needed
Keep the team updated in #team-support with anything relevant
Hand over to the next timezone if the incident runs long
Don't duplicate comms - coordinate with the Comms Lead and TAMs/CSMs as needed
When an incident is declared
When an incident gets declared, our incident.io workflow automatically posts to #team-support. This post asks for someone from support to raise their hand and take ownership of watching the incident. All members of the support team are responsible for making sure that an incident has a Support Watcher assigned during business hours.
Support team members aren't automatically added to incident channels. You can keep an eye on #incidents for an overview of what's currently open. When you raise your hand in #team-support to watch an incident, join the incident channel using the link in the workflow post.
When you join the incident channel, you'll be automatically assigned the Support Watcher role in incident.io. This makes it clear and visible to both the support team and the incident team who is managing the incident from a support perspective.
If nobody from support joins the incident channel, the incident lead will get a nudge reminding them to assign the Support Watcher role, along with a note that support only watches incidents during business hours.
If you're online and available during your normal working hours, raise your hand on that thread. This is informal - it's just whoever can do it. If nobody responds after a few minutes and you're around, go ahead and volunteer even if you're in the middle of something else.
We don't have on-call support coverage. You're only expected to raise your hand for incidents during your normal working hours. If an incident is declared outside of working hours, support tickets will either need to wait until support working hours resume, or be handled by the @on-call-global person from engineering.
Once you've raised your hand and joined the incident channel, you'll be assigned the Support Watcher role. You own:
Following the incident channel and keeping up with status updates
Ensuring the status page has clear, customer-friendly messaging about the impact
Looking through existing tickets in the queue to see if any were opened because of this incident
Creating a standardized response (if appropriate) for responding to customers about the incident
Checking for new tickets coming into the support queue during the incident
Passing along relevant updates or highlights to the rest of the support team in #team-support
Understanding the user impact so the team can respond to tickets accurately
Your job isn't to fix the incident. Your job is to be the bridge between the incident response and the support team, and to make sure users opening tickets get accurate information.
Using the status page
The status page is our source of truth during incidents. The incident lead is typically responsible for keeping it updated, but as the support team member watching the incident, you should make sure the messaging is clear and customer-friendly.
Review the status page messaging when it's updated to ensure:
The impact is described in terms customers will understand (not just "elevated errors" or technical jargon)
The affected components are marked correctly
The messaging isn't ambiguous - users should understand what's broken and how it affects them
If the status page update is too generic or unclear, work with the incident lead to improve it. You can update it yourself using /incident statuspage (/inc sp) in the incident channel.
Good status page messaging:
Feature flags are being returned but with 30-60 second delays instead of the usual <1 second response time. All other PostHog features are operating normally.
Unclear status page messaging:
Elevated errors in the feature flags service.
Always link to the status page in ticket responses. Users should be able to check it themselves for updates rather than having to ask us every hour.
Creating a standardized response for the incident
If the incident is likely to generate multiple support tickets (most incidents do), create a standardized response so the whole team can respond consistently.
The response should include:
A brief description of what we currently understand about the incident
The specific impact to users (what's broken, what's working, what's degraded)
A link to the incident on our status page
Keep it simple and factual.
If there's a Comms Lead assigned:
For major or security incidents, share the draft with them before using it. We want to make sure we're saying consistent things across all channels. The Comms Lead should review the standardized response to ensure the messaging aligns with broader customer communications.
For minor incidents, share the standardized response with them after you've created it so they're aware of what messaging we're using.
If there's no Comms Lead assigned: Use your best judgement to create a clear, factual standardized response. If you think the incident warrants coordination with Marketing, mention it in the incident channel - but don't let that block you from responding to customers.
Update the standardized response if the situation changes significantly. If you do update it, let the Comms Lead know (if there is one).
Let the team know in #team-support (on the thread for the incident) when you've created the standardized response so they know to use it.
Handling incoming tickets during an incident
If you're the person who raised your hand to watch the incident, you're also responsible for keeping an eye on the support queue during the incident. Check through the queue for any existing tickets which might have been raised before the incident was declared, and then continue to monitor for new tickets being raised related to this incident.
Sort your tickets by newest so you can easily spot new tickets coming in. This makes it much easier to catch incident-related issues as they arrive.
Don't send generic "we're working on it" messages. Use the standardized response if you created one, or link to the status page, explain what we know about the impact, and give them a real timeline if we have one. If we don't have a timeline, say that too.
Example response:
Hey - yes, we're seeing this too. There's an incident affecting feature flag requests right now. You can follow updates on our status page, but the short version is that flags are returning but with higher latency than normal. The team is working on it and we'll update the status page as we know more. I'll be sure to let you know when it's resolved.
Important: Always tag incident-related tickets with incident/[number] (e.g. incident/123). This helps us track the user impact and keeps everything organized. Anyone on the support team responding to incident-related tickets should do this, not just the person watching the incident.
If you're seeing the same issue across multiple tickets, drop a note in the incident channel. Sometimes support spots patterns before monitoring does. Also share this in #team-support so the rest of the team knows what to expect.
Creating proactive tickets
Sometimes we need to reach out to users proactively during an incident - for example, if a specific org caused the incident or was significantly affected. The engineering team may ask us in #team-support to create tickets for affected customers.
Before creating any proactive tickets, check with the incident lead and coordinate with the Comms Lead to ensure we're not duplicating their communications.
Keeping the team updated
As the person watching the incident, keep the rest of the support team informed in #team-support. Share:
Major updates about what's happening
Changes to the user impact
Patterns you're seeing in tickets
When the incident is resolved
You don't need to copy every single update from the incident channel. Just share the things that would help someone else on the team respond to a ticket about this incident accurately.
Working with the Comms Lead
For an incident that requires external comms, Marketing will appoint a Comms Lead. They own external communication strategy. We don't.
As the support team member watching the incident, you should coordinate with the Comms Lead:
Coordinate on phrasing a standardized response (see 'Creating a standardized response for the incident' above)
If you're seeing patterns in support tickets that might inform their messaging
If you need help with a particularly complex or sensitive customer communication
When you update the standardized response - let them know what changed
If you think external comms are required but there isn't a Comms lead assigned, you can request one by asking in #team-marketing or using the @all-marketers tag in Slack.
Coordinating with TAMs and CSMs
Enterprise customers often have dedicated TAMs (Technical Account Managers) or CSMs (Customer Success Managers) from the Sales/CS team. When these customers reach out about an incident - either through their Slack channels or via tickets - we need to coordinate our response.
For minor incidents, we can usually just respond ourselves. Keep it straightforward and use the standardized response if you created one.
For major incidents, Sales/CS teams may want to handle communication with their customers directly. Check #group-cs-sales-support to see if they're coordinating a response plan. If you're unsure whether to respond to a particular customer:
Check #group-cs-sales-support to see if there's discussion about the incident
Message #group-cs-sales-support and ask if they'd prefer to handle the communication with this customer. Attach a private note to the ticket with a link to the conversation.
If nobody responds and the customer is waiting, respond yourself - it's better than leaving them hanging
Remember that TAMs and CSMs work in specific timezones. If an enterprise customer reaches out when their TAM/CSM is offline or on holiday, don't leave them waiting. Respond to their question. You can loop in their TAM/CSM as a heads-up, but the customer should get an answer from someone.
Handing over across timezones
If an incident is still ongoing when you're about to log off for the day, hand over to someone who's still working or coming online. Try to hand over to someone who has the most working hours ahead of them - this avoids multiple handovers.
Post in #team-support via the original incident thread with:
Current status of the incident (what's broken, what's being done about it)
Roughly how many support tickets we've seen related to it
Any key information the next person needs to know
Anything you told users in tickets that the team should be consistent about
If you're US West Coast based and logging off for the day, write detailed handover notes given that nobody in EU will be online yet. This way they can pick it up smoothly when they start their day.
If you're picking up an incident from someone in a previous timezone, read their notes, scan the incident channel for updates since those notes were written, and jump in. Raise your hand on the original #team-support workflow post if you haven't already.
After an incident resolves
Once the customer-facing impact of the incident is resolved:
Find all incident-related tickets by filtering for the relevant incident/xxx tag in PostHog Support
Go back through these tickets and update users that the incident is resolved
Check if any docs or help content needs updating based on what happened - if you can ship a quick docs fix or FAQ update, do it now while it's fresh
For major incidents, there will be a post-mortem. Read it. If you have feedback from the support side - things we could have done better, information we were missing, communication that didn't work, patterns you saw in tickets - add it to the post-mortem document or share it in the incident channel. Your perspective on the user impact and customer communication is valuable.
As we add more products to PostHog, it becomes increasingly difficult for individual support engineers to effectively work across every product. SMEs help us maintain deep expertise across our products and ensure every ticket gets answered by someone who really knows their stuff.
By allowing SMEs to own groups of PostHog products, we build the knowledge needed to delight users with better and faster answers, and develop close relationships with product teams so we can advocate for fixes and features that actually matter to users.
Product ownership
Product groups
The various PostHog products have been split into the following product groups:
A note on these groupings: These product groups are based on current ticket volumes. As products grow or new ones launch, we'll split or reorganize them. This structure will evolve with our needs.
SME ownership
All technical support engineers, regardless of SME ownership, work on:
Analytics products - work for this product group is shared as it represents the highest proportion of our tickets.
Unclassified tickets - where possible, these tickets should be tagged with the correct engineering team.
Beyond that, we have SMEs who own specific product groups. For each product group, we select one person from EU and one from NA to maintain timezone coverage:
Flags
EU: Ben Lea, NA: Phillip Ramirez
Data
EU: Luke Belton, Chris Shine, NA: Kyle Swank
Replay
EU: Christian Rafferty, NA: Ben Haynes
Observability + AI & client libraries
EU: Christiaan Hendriksen, NA: Steven Shults
Analytics
EU: Xander Jones, Alin-emanuel Cîciu
Accounts & Billing
EU: Eleftheria Trivyzaki
What SMEs actually do
Being an SME means you're the go-to person for your product group. This breaks down into three key aspects:
Own the customer perspective
Maintain oversight of all tickets in your product group
Spot patterns and common themes
Understand what bugs are frustrating users most
Know what features users are asking for
Partner with engineering teams
Build good relationships with the engineering teams who own your products
Consider attending their standups occasionally (you don't need to go to every one)
Keep an eye on their Slack channels to know what's recently shipped and what's being worked on
Understand what's on their roadmap
Bring customer context to help with their quarterly planning - what bugs are most prominent, what features users want most
Improve support
Look to improve the support experience within your product group
Identify ways we can proactively help customers and prevent tickets (e.g. docs, in-app prompts, automatic checks)
Look for ways to streamline support operations for your product group (i.e. identify most common investigation steps that could be surfaced onto tickets automatically)
How to work as an SME
Your PostHog Support views
SMEs each have a dedicated view in PostHog Support that includes:
Tickets created from Slack and MS Teams channels
Tickets submitted in-app
These views contain tickets from your specific product groups (see groupings above) and all shared product groups (analytics and unclassified tickets). If there are any unclassified tickets that appear in your view (tickets in the 'Support' group), then where possible please assign these to the correct product. Let Abigail Richardson know if there are certain types of tickets which regularly appear in the 'Support' group.
Important: These views show tickets assigned to other team members too, giving you full context of your products. Jump in if you know something off the top of your head or see someone stuck.
Your daily workflow
Start your day with your SME views. Build your knowledge. Get really good at your products. Once you're on top of your SME queue, move to the support shared view which has all tickets the technical support team is responsible for.
But here's the key: you're not locked into only your SME products. The goal is expertise, not silos. If you're caught up and the shared queue needs attention, dive in. If you're swamped and someone else can help with your SME queue, ask for it.
Coverage and coordination
You and your SME counterpart in the other timezone should work together to:
Share knowledge, patterns, and themes you're seeing in tickets
Coordinate on holiday planning - can you stagger time off to maintain coverage?
Call out when your SME queue is especially busy and you need help
Communicate in #team-support about coverage gaps or when you need backup
As we grow, we'll need less manual coordination. For now, always consider coverage and communicate proactively.
Attending product team offsites
You work closely with the engineering teams behind your products, so when one of them runs an offsite, it's natural to want to be there. Time in person with your product team can be genuinely valuable. A few things to make it work:
Give Abigail Richardson a shout early. The moment it's on your radar, flag it, so we can sort coverage together. Every now and then we might have to say no if support's stretched thin - and that's better to hear before you've booked flights.
Have a reason, or make it easy. You likely partner with a few different teams, and you can't be at every one of their offsites — nor should you try to be. Joining makes most sense when there's something specific you'll get out of being there in person, or the offsite is local enough that turning up is cheap and easy.
You're still on support. It's their offsite, not yours — so keep up with your normal tickets while you're there. Soak up the context and dip into their agenda, just don't vanish from the queue.
Don't leave customers hanging. We won't post customer notices for these trips, so from a user's side nothing should feel different. People shouldn't be waiting around just because you're away — stay as responsive as you'd be any other week.
None of this is meant to put you off. Loop us in early, keep customers the priority, and these trips are a great thing to do.
The support team exists to help our users succeed with PostHog, and we do that differently than most support teams.
We're not a ticket-routing operation. We genuinely care about making our users' experience exceptional, which we do by being a deeply technical team that takes pride in solving problems ourselves. We write code, ship fixes, update docs, and build internal tooling to deliver that experience. We move fast, stay humble, and believe that great support is about empowering users, not just answering questions.
Slack channels to stay current
To answer customer questions well we need to know what's just shipped. The #changelog internal channel keeps this in front of you — every member of the Support team should join it. It's owned by the Wizard & Docs team and updated constantly as PRs merge.
The channel is populated by agentic workflows that scan merged PRs and feature flag changes in the posthog/posthog repo and summarize them into it. Engineers can opt a PR in or out via the Publish to changelog? checkbox on the PR template, or via the @posthog Slack app. See how to publish changelog for the full flow.
Support isn't just about tickets! Well... it's a lot about tickets - but we don't judge the success of support engineers solely by how many tickets they solve. Instead, we like to free up support engineers to spend some time working on other tasks which help users. These tasks can include working on their quarterly goals, building new support features, contributing small PRs for bug fixes, or whatever else they think will help us move faster.
Why are support zero weeks useful?
The goal of zero weeks is to make non-ticket time more efficient and effective, and get more of our quarterly work done as a result.
At times we can really struggle to pull ourselves away from tickets and focus on the bigger picture. Having a block of dedicated non-ticket time allows us to spend time shipping things that will help us become better as a support team, and allow us to better help our customers.
How do support zero weeks work?
Each support team member is given an allocation of 2 support zero weeks in each quarter (i.e. 10 working days). These are weeks that each team member can book.
Team members are encouraged to consider taking the same zero weeks as someone else working on the same quarterly goal (so it can be done hackathon-style, you can consider using your monthly User Limit to meet up, etc)
Before the quarter starts
[ ] During quarterly goal planning we scope out goals that we think are achievable in our zero time each quarter.
[ ] Let Abigail Richardson know if you have any preference or restrictions on when you can take your zero weeks.
[ ] Abigail Richardson will check the PTO calendar, consider time zone constraints, and propose a schedule of zero weeks for the quarter. For each support team member, we will aim to schedule one zero week in the first half of the quarter and the other in the second half of the quarter.
[ ] Each team member should create a meta GitHub issue for their quarterly goal work.
Before your zero week
[ ] Hand over all of your in-progress tickets (including any in a pending state that you believe are ongoing / going to come back). Do this as a message into #team-support.
[ ] Set a status in Slack so it's clear to the rest of the team that you're on a zero week
During your zero week
[ ] Try your best to avoid the ticket queue (i.e. generally don't pick up new tickets or respond on tickets you were previously working on, except in exceptional circumstances).
[ ] Do reassign tickets back to the main ticket group if they accidentally come back assigned to you directly for some reason.
[ ] Do respond to any questions the team ask in #team-support about tickets you were previously working on.
[ ] Do consider that you may get pulled back onto tickets on a particular day if absolutely necessary (to be avoided as much as possible).
[ ] Make sure to keep notes and design choices publicly available on your meta GitHub issue.
:warning:
Team members who are working on tickets need to be aware of ticket queue and highlight in #team-support if the workload is getting too high
After your zero week
[ ] Ask in #team-support if there are any tickets that the team would like to return to you that you were previously handling.
[ ] Ask in #team-support for any feedback that the team has for you based on any of your tickets they have handled during your zero week.
[ ] Consider if this is a good stage in your goal to seek feedback from the team (likely via your meta GitHub issue or a different RFC). Please do consider if it's worth the team's time at this stage.
[ ] Get stuck into tickets!
What does this mean for side quests outside of quarterly goal work?
Do them!
The purpose of zero weeks is to give space and focus for quarterly goal work, not restrict what you can do on a day-to-day basis.
Where you have small things you'd like to do (docs updates, small PRs/bug fixes, setting up example apps, etc), you can absolutely do these alongside your ticket work.
Please just bear in mind that tickets are generally our highest priority (especially Sales/CS Top 20 and enterprise customers).
If there are larger pieces of work that you'd like to do, we can chat about updating your quarterly goals.
A collection of tips & tricks on helping to troubleshoot customer issues.
General
Add distinct_id as a column to see how the distinct_id changes (use SQL expression column). This is useful when troubleshooting identify / person profile related issues.
To breakdown events by anonymous vs identified, use this SQL snippet: IF(person.properties.$creator_event_uuid IS NOT NULL, 'Identified', 'Anonymous') AS user_type
Debug mode: append ?__posthog_debug=true to a site that has posthog running, e.g. https://app.mywebsite.com/login?__posthog_debug=true. This can show lots of useful information like logs and config.
To check a customer's PostHog configuration:
In session replay, enable doctor and look for posthog config event.
Open the customer's site in debug mode (see above)
To check if a customer is using a reverse proxy, look at their api_host configuration. If it shows us.i.posthog or eu.i.posthog – then they are not using a reverse proxy.
Feature flags
Check team activity to see if users have made any changes to the flag. Take note of the timestamp of any changes and see if it explains any discrepancies.
Funnels
Common funnel troubleshooting steps
Ensure you understand the conversion goal the user is tracking, clarifying this often helps, even if the user knows they’re doing the right thing
Are they reasoning about it right?
Have they chosen the correct events?
Are their events sent when they think/expect them to be sent?
Are they filtering the correct events for that flow?
If it’s a mix between frontend and backend events, they must ensure identification is done right
For reports about unexpected drop-offs, look at each event in the funnel separately to understand if they’ve dropped off on their own (using a Trends insight helps).
Attribution type (example ticket): Users often report that their experiment funnels show a lot of false or none values for the feature flag breakdown. This is commonly the cause because they have “First touchpoint” selected as attribution, but they want “Last touchpoint.” This is only relevant when they’re using funnel analysis outside of the experiment, since the experiment already only takes into account users who had the expected variant by the end of the funnel.
Search for events by the user’s IP address (which you can find in the event properties for the Web SDK). This works if the whole flow happens on the frontend, sometimes you can find that the same IP address has multiple distinct_id, which means that user may have multiple identities which funnels count separately.
Create funnels for each interval in their funnel: Something that would have given us more helpful information sooner would have been creating a funnel for step 1 to step 2 and another funnel for step 2 to step 3. This was what ultimately confirmed there was a user identification problem.
Funnels and user paths use different queries (example ticket): If a user reports seeing different numbers in funnels and user paths, that’s expected, these use different queries in the backend and measure different outcomes.
Look for identification splits: If they’re identifying users in different environments (backend vs frontend) different libraries (Web vs Segment), or even with multiple IDs (logged out vs logged in), or even cross-subdomain without proper persistence (cookies) or different implementation configuration, all of these could cause a desync between identities which can break a funnel.
Connecting frontend and backend identities
To connect frontend and backend identities, you only need to use the same distinct_id in both frontend and backend events. How you sync these depends on your system but here are some ways:
Recommended: Set the distinct_id based on a known user ID: If you have a stable internal user ID, set posthog.identify('your-user-id') on the frontend, and use that same ID in backend events. This ensures alignment across both environments
Alias: identify with id 1 -> alias with id 2 as alias and id 1 as distinct_id
Wrong: identify with id 1 -> identify with id 2 -> alias
Use a signed token or cookie: Store the distinct_id in a cookie or session token shared between frontend and backend, especially if you're using server-side rendering or middleware that handles both sides.
Pass the ID from frontend to backend: When a user logs in or performs a tracked action, capture their distinct_id in the frontend (e.g., using posthog.get_distinct_id()), then include it in API requests or session headers so your backend can reuse it when sending events. Careful, you’re relying on PostHog’s distinct_id here, which may not be an expected value.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | ✓ | Unique identifier for the SDK (e.g., 'posthog-js', 'stripe-node') | | schemaVersion | string | | Version of this schema format being used | | info | Info | ✓ | Metadata about the SDK | | classes | Class[] | ✓ | Main classes/modules exposed by the SDK | | types | Type[] | | Type definitions, interfaces, and enums | | categories | string[] | | List of functional categories for organizing methods |
---
Info
Metadata about the SDK.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | ✓ | Package/library identifier | | title | string | ✓ | Human-readable name of the SDK | | version | string | ✓ | Current version of the SDK | | description | string | | Brief description of what the SDK does | | slugPrefix | string | | URL-friendly prefix for documentation links | | specUrl | string (uri) | | URL to the source specification or repository | | docsUrl | string (uri) | | URL to the official documentation | | license | string | | License type (e.g., 'MIT', 'Apache-2.0') | | platforms | string[] | | Supported platforms (e.g., 'browser', 'node', 'react-native') |
---
Class
Main classes/modules exposed by the SDK.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | ✓ | Unique identifier for the class | | title | string | ✓ | Display name of the class | | description | string | | Overview of what this class provides | | functions | Function[] | ✓ | Methods and functions available on this class | | properties | Property[] | | Instance properties of this class | | staticMethods | Function[] | | Static methods on this class | | events | Event[] | | Events emitted by this class |
---
Function
Methods and functions available on a class.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | ✓ | Unique identifier for the function | | title | string | ✓ | Function name as it appears in code | | description | string | | Brief description of what the function does | | details | string \| null | | Extended explanation, usage notes, or caveats | | category | string | | Functional category (e.g., 'Initialization', 'Capture') | | releaseTag | ReleaseTag | | Stability/visibility status of the function | | showDocs | boolean | | Whether to display in public documentation | | params | Parameter[] | | Function parameters | | returnType | TypeReference | | Return type of the function | | examples | Example[] | | Code examples showing usage | | throws | ThrowsClause[] | | Exceptions/errors that may be thrown | | since | string | | Version when this function was introduced | | deprecated | string \| boolean | | Deprecation notice or true if deprecated | | seeAlso | string[] | | Related functions or documentation links | | path | string | | Source file path for this function | | async | boolean | | Whether this is an async function | | overloads | FunctionOverload[] | | Alternative function signatures |
---
Parameter
Function parameters.
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | ✓ | Parameter name | | type | string | ✓ | Type annotation for the parameter | | description | string | | What this parameter is for | | isOptional | boolean | | Whether this parameter is optional | | defaultValue | string | | Default value if not provided | | isRest | boolean | | Whether this is a rest parameter (...args) |
---
TypeReference
Reference to a type, used for return types and property types.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | | Reference ID to a type definition | | name | string | ✓ | Display name of the type |
---
Type
Type definitions, interfaces, and enums.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | ✓ | Unique identifier for this type | | name | string | ✓ | Type name | | description | string | | What this type represents | | kind | TypeKind | | Kind of type definition | | properties | Property[] | | Properties for object types | | enumValues | EnumValue[] | | Values for enum types | | example | string | | Inline type definition or usage example | | path | string | | Source file path | | extends | string[] | | Types this type extends | | generic | GenericParameter[] | | Generic type parameters |
---
Property
Properties on types or classes.
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | ✓ | Property name | | type | string | ✓ | Type of the property | | description | string | | What this property represents | | isOptional | boolean | | Whether this property is optional | | isReadonly | boolean | | Whether this property is read-only | | defaultValue | string | | Default value | | deprecated | string \| boolean | | Deprecation notice |
---
Example
Code examples demonstrating usage.
| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | | Unique identifier for the example | | name | string | | Title describing what the example demonstrates | | code | string | ✓ | The example code | | language | string | | Programming language (e.g., 'javascript', 'typescript') | | description | string | | Additional explanation of the example |
---
Event
Events emitted by a class.
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | ✓ | Event name | | description | string | | When this event is emitted | | payload | string | | Type of data passed to event listeners |
---
ThrowsClause
Exceptions/errors that may be thrown by a function.
| Field | Type | Required | Description | |-------|------|----------|-------------| | type | string | | Type of error thrown | | description | string | | When this error is thrown |
---
EnumValue
Values for enum types.
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | ✓ | Enum member name | | value | string \| number | ✓ | Enum member value | | description | string | | What this enum value represents |
---
GenericParameter
Generic type parameters.
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | ✓ | Generic parameter name (e.g., 'T') | | constraint | string | | Type constraint (e.g., 'extends string') | | default | string | | Default type |
---
FunctionOverload
Alternative function signatures for overloaded functions.
| Field | Type | Required | Description | |-------|------|----------|-------------| | params | Parameter[] | | Parameters for this overload | | returnType | TypeReference | | Return type for this overload | | description | string | | Description specific to this overload |
---
Enumerations
ReleaseTag enum:
| Value | Description | |-------|-------------| | public | Stable, public API | | beta | Beta feature, may change | | alpha | Alpha feature, likely to change | | internal | Internal use only | | deprecated | Deprecated, avoid use |
TypeKind enum:
| Value | Description | |-------|-------------| | interface | Interface definition | | type | Type alias | | enum | Enumeration | | class | Class definition |
PostHog's API specifications are (mostly) generated automatically from the OpenAPI spec. We have a tooling to generate the API specification markdown files from the OpenAPI spec.
Where we publish the API specifications
When ever you run the app locally, the API specification is available at /api/schema/, and you can view it using Swagger UI.
On the website, the API specification is available at /docs/api/. Some of these pages are hand-rolled, and some are generated from the OpenAPI spec.
The website ingests the OpenAPI specification during the Gatsby build process in two stages:
During sourceNodes: The OpenAPI spec is fetched and parsed using OpenAPIParser and MenuBuilder from the redoc library. This creates a structured menu of API endpoints that's used for navigation. The menu groups endpoints and handles pagination for groups with more than 20 items.
During onPostBuild: The build process fetches the OpenAPI spec from https://app.posthog.com/api/schema/ (or from the POSTHOG_OPEN_API_SPEC_URL environment variable if set). The spec is then passed to generateApiSpecMarkdown(), which:
Iterates through all paths and HTTP methods in the spec
For each endpoint with an operationId, creates a markdown file named after the operation ID
Recursively extracts all referenced component schemas for each endpoint
Generates markdown files containing the endpoint's OpenAPI JSON in a code block
Writes these files to public/docs/open-api-spec/
The generated markdown files are then available at /docs/open-api-spec/{operationId}.md and are included in the documentation site's API reference section.
How to update the OpenAPI spec
Any of the automatically generated pages sources from the OpenAPI spec. To update the content of an automatically generated page, you need to update the OpenAPI spec by making changes to the PostHog/posthog repository.
Updating the page title and description
These updates happen in the PostHog/posthog.com repository.
Page title: Update the titleMap object in src/templates/ApiEndpoint.tsx. For example, to change the "Actions" page title, modify the actions entry in the map.
Page description: Create or update an overview.mdx file in the corresponding API folder. The file should be located at contents/docs/api/{name}/overview.mdx, where {name} matches the API endpoint name (e.g., events, feature-flags).
These updates happen in the PostHog/posthog repository.
Endpoint title: The title is auto-generated from the operationId in the OpenAPI spec using the generateName() function in src/templates/ApiEndpoint.tsx. To customize it, update the operationId or description in the Django viewset in the PostHog repository. You basically need to update the path to update the title.
Endpoint description: Create an MDX file named after the endpoint's operationId in the appropriate API folder. The file should be located at contents/docs/api/{name}/{operationId}.mdx.
Example: contents/docs/api/feature-flags/feature_flags_list.mdx adds custom content that appears under the "List all feature flags" endpoint. The content from this file is rendered above the endpoint's description from the OpenAPI spec.
Updating the endpoint parameters and responses
The endpoint request body parameters, query parameters, path parameters, response body, response headers, API key scopes, etc. are all defined in the Django serializers and viewsets in the PostHog repository.
Generally, there are two types of "views" in Django and they require different annotations to generate accurate OpenAPI specs.
Model-based CRUD views: These are views that are backed by Django models. These CRUD views are backed by models defined in the Django ORM. They map literally to Django model fields, and generally don't need any additional annotations for accurate request and response definitions.
Function-based views: These are views that are backed by Python functions. These views are not backed by models, and generally annotated with @action decorators. For these views, we need to manually annotate request and response definitions.
If an endpoint needs additional annotation, you can use the @validated_request decorator to annotate the view. This decorator will use the serializers passed in for both validation and annotation of the request bodies, query parameters, and response bodies, ensuring the OpenAPI spec stays accurate (or we know when they're not).
Basic usage
The @validated_request decorator wraps a view function and provides validation for request and response data:
from posthog.api.mixins import validated_request
from drf_spectacular.utils import OpenApiResponse
from rest_framework import serializers, status
from rest_framework.response import Response
# Django uses serializer to validate request body data, validated request can infer the request and response schemas from the serializer definitions.
class EventCaptureRequestSerializer(serializers.Serializer):
event = serializers.CharField(max_length=200, help_text="Event name")
distinct_id = serializers.CharField(max_length=200, help_text="User distinct ID")
properties = serializers.DictField(required=False, default=dict)
class EventCaptureResponseSerializer(serializers.Serializer):
status = serializers.ChoiceField(choices=["ok", "queued"])
event_id = serializers.UUIDField()
distinct_id = serializers.CharField()
@validated_request(
request_serializer=EventCaptureRequestSerializer,
responses={
200: OpenApiResponse(response=EventCaptureResponseSerializer),
},
summary="Capture an event",
description="Sends an event to PostHog for tracking",
)
def capture_event(self, request):
# Access validated request body data
event_name = request.validated_data["event"]
distinct_id = request.validated_data["distinct_id"]
# Process the event...
return Response(
{
"status": "ok",
"event_id": str(uuid.uuid4()),
"distinct_id": distinct_id,
},
status=status.HTTP_200_OK,
)
Validating query parameters
Use query_serializer to validate query parameters:
Declare status codes with no response body using None:
@validated_request(
responses={
204: None, # No response body
},
)
def delete_item(self, request, pk):
# Delete the item...
return Response(status=status.HTTP_204_NO_CONTENT)
Validation modes
By default, @validated_request uses strict validation for requests (raises on invalid data) and non-strict for responses (logs warnings in DEBUG mode). You can control this:
Which endpoints have validated request and response definitions
The @validated_request decorator is new and many endpoints have not been annotated yet. The following endpoints have been annotated:
tasks
task-runs
feature_flags
feature_value
We plan on slowly annotating all endpoints with the @validated_request decorator through Q1 2026.
The special case for Capture
Ingestion is basically an entirely different service and not included in the OpenAPI spec. It also has special limitations like batching, rate limiting, etc that need to be documented separately. It doesn't fit the classic patterns for a RESTful API as well as other endpoints.
The ingestion team and docs team will need to work together to update the OpenAPI spec for the Capture endpoint.
We built an agent that automatically drafts docs PRs in posthog.com when your code changes are merged into the posthog monorepo.
The content writer agent leverages the Inkeep platform to index and reference the PostHog website, codebase, and our docs style guide, so its drafts are usually a solid starting point — but they still need your review for technical accuracy.
Who owns what
Product engineersown the docs for their products. When the agent opens a docs PR based on your merged code, you're responsible for reviewing it for technical accuracy, iterating on it until it's right, and merging it. You don't need docs team sign-off — treat it like any other PR for your product.
The team does not review every docs PR. Engineers loop us in when they want a second opinion. We're responsible for building the system, monitoring its output quality over time, and tuning and steering the agent.
Agent system for the content writer
The workflow
When you merge a PR in the posthog monorepo, the Inkeep bot automatically opens a docs PR on posthog.com and tags you as a reviewer. From there:
Review the draft for technical accuracy, completeness, code examples, and links.
(Optional) Loop in the docs team if you want a second opinion on style, structure, or information architecture — tag @team-wizard-and-docs as reviewers.
Approve and merge when the docs are ready.
If you tagged @inkeep or made changes to the PR, a feedback form is posted after merge. This helps us understand where the agent fell short — please fill it out so we can continue improving the agent.
How to make changes
You can iterate on an Inkeep docs PR in a few ways:
Tag @inkeep in a PR comment to ask the agent to make specific changes. Describe what you need and Inkeep will push updated commits.
Edit the files yourself — either by pulling the branch locally or directly on GitHub. This bypasses the AI loop entirely and is often faster when you know exact changes you want to make.
What to check
Technical accuracy — Does the documented behavior match what your code actually does?
Completeness — Are all user-facing changes covered?
Code examples — Are snippets correct, realistic, and using PostHog conventions?
Links — Do internal links (website or in-app) point to real pages?
When to loop in the docs team
You don't need our approval to merge a docs PR. But do loop us in when:
You need a second pair of eyes on information architecture choices (e.g., new sidebar sections, new landing pages, navigation changes, etc.)
You want a style or structure review beyond what you can assess yourself
The change is large and you want a second opinion
Tag @team-wizard-and-docs as reviewers on the PR, and we'll help out.
The context mill repo gathers up-to-date context from multiple sources, packaging developer docs, prompts, and working example code into a versioned manifest, which can be shipped anywhere.
The PostHog MCP server currently fetches the context mill repo manifest and exposes it to any MCP-compatible client as resources and slash commands. This is what currently powers the PostHog AI wizard.
The context mill effectively acts as an assembly line for turning disparate PostHog knowledge into something portable, something AI systems can reliably consume.
You can break its context engineering flow into three main stages.
Context sourcing: The context mill can pull from the entire PostHog developer docs, with pages delivered from posthog.com as raw Markdown. It also includes curated, hand-crafted prompts and working example apps.
Context assembly: The context mill transforms and packages the sourced context into a zip file manifest, which is meant to be portable and self-contained. We can structure and shape the manifest however we need.
Context delivery: The context mill creates a versioned release for the manifest, which can be consumed by any agent or MCP server as a skill or resource.
Getting the best results requires some hand-cranking and refining. Context mill packages are created using a simple declarative YAML spec, so it’s worth spending some time experimenting and tuning things until they feel right.
Developers love the wizard: it's the fastest way to get a deep, correct integration of PostHog, with none of the hallucinations that come from naive agent-based attempts.
For users, it is a one-line CLI command which runs an AI agent that automatically instruments PostHog into their codebases.
npx -y @posthog/wizard@latest
The wizard's architecture
The wizard is a CLI tool that runs locally against developers' projects.
It wraps the Claude Agent SDK to perform the integration, reviewing project code and making edits as needed.
To direct the agent, the wizard uses the PostHog context mill repository as a context provider. The context mill provides the agent with skills packages for great integrations, which include workflow prompts, documentation, and example code to maximize correctness and completeness.
The context mill repo generates a zip file and manifest that determines the structure of the skills packages.
Commands and skills
The wizard's command surface comes from context mill, not hardcoded in the wizard. A skill becomes a command when its config.yaml declares a cli: block with role: command – so wizard audit eventsis the audit-events skill, promoted to a command. A skill without that block stays reachable only via wizard skill <name>. Same machinery, two surfaces — which is why wizard audit <subcommand> chooses an audit area rather than taking a skill name (the [skill] label in wizard audit --help is an internal positional name, not a prompt for a skill).
Because these entries are read from the published manifest at runtime, adding a subcommand under a command that already exists is a context mill release – no wizard release required. A new audit leaf (e.g. wizard audit feature-flags) is just a skill with cli: { role: command, parentCommand: audit }; the audit parent is already registered in the wizard, so the subcommand resolves from the manifest at runtime.
A brand-new top-level command word is the exception – it also needs a wizard PR. yargs only routes top-level commands that are statically registered in the wizard's bin.ts, so nothing in a context mill release can conjure a new top-level word on its own. To add one you ship both: the skill (with cli: { role: command }) in context mill, and a thin native command in the wizard — a ProgramConfig (usually via createSkillProgram) plus a nativeCommandFactory stub registered in bin.ts, exactly like migrate and revenue-analytics. Ship the context mill PR first so the manifest is published before the wizard tries to resolve the skill.
Worked example — adding wizard mcp-analytics. This flat top-level command was added across four PRs and is the canonical reference for the pattern: the skill (context-mill#202), the wizard command stub (wizard#731), the test fixtures (wizard-workbench#2158), and the docs/wizardSupport label (posthog.com#17939). Copy that shape rather than inferring from the cli: schema alone.
Cover both test layers when you add a command:
Unit (wizard repo) — a per-command test in programs-cli.test.ts asserting the command registers in the expected shape (flat vs. family) and dispatches the right skillId. Fast, runs in the wizard's CI.
End-to-end (workbench) — a PostHog-less fixture app under apps/<command>/ plus an entry in apps/manifest.json, so the workbench can drive the real agent run via phrocs. Add a fixture per distinct path the skill handles (mcp-analytics ships one for the SDK-wrap path and one for the custom-dispatcher path).
The full cli: block schema (roles, parentCommand, the default leaf, naming rules) lives in context mill's CONTRIBUTING.md; the wizard side (command registration, families, aliases) is documented in the wizard repo's AGENTS.md. The command surface is curated, not inclusive — new role: command promotions want a wizard-maintainer sign-off, since a public command name is hard to deprecate.
Developing the wizard
Use the wizard workbench for local, end-to-end development of the wizard. The workbench can run the full wizard stack in local development mode, with hot reload where supported.
The workbench is also responsible for CI and testing the wizard across a matrix of test applications.
https://github.com/PostHog/posthog (contains the MCP server)
Next, configure the workbench to run the wizard and its local dependencies. Read the README.md file in the wizard-workbench repository to get started and create a .env file with the paths to the dependent repos.
Open a terminal at the workbench root and run:
phrocs
Using the MCP inspector
You'll want the link that looks like this from the mcp-inspector phrocs panel:
Access the link in your browser, set the transport type to Streamable HTTP, and set the URL to http://localhost:8787/mcp for local development. (Alternatively, you can also inspect the production MCP by setting the URL to https://mcp.posthog.com/mcp).
You'll need a PostHog API key to access the MCP server. Get one from the user API keys settings page. Open the Authentication tab and paste the key into the Bearer token field.
Hit connect and you'll see the MCP server's contents.
Handling wizard drama
First, identify cause of failure: run npx -y @posthog/wizard@latest. You can find target projects known to work in the wizard-workbench repository.
Review the logs at /tmp/posthog-wizard.log. This log can be quite verbose, so agent-driven analysis may be helpful to quickly pinpoint where things are going wrong. Include the below details to help the agent diagnose the issue.
Potential points of upstream failure:
Without OAuth from PostHog, the wizard cannot access the AI gateway. This will prevent all wizard runs. But if OAuth is not possible, we've probably got bigger problems than just the wizard itself.
If GitHub's release artifacts are not available, the wizard will be guessing blindly at how to integrate PostHog, producing incorrect and incomplete integrations.
If wizard's agent harness cannot connect to the AI gateway, the wizard run will fail.
If Anthropic's API is down, the wizard run will fail.
The wizard has the above upstream dependencies. It is also a bundle of client code, subject to various bugs and distribution mishaps. If upstream services are healthy but the wizard is still failing, it's likely a bug in the wizard itself.
Find a previous release version number and run npx @posthog/wizard@<version> against your example project. If the wizard runs successfully, you can compare the logs to the current release to see what changed. This will also confirm a safe rollback path.
To roll back, submit a PR that reverts the bad commits. The PR title must use a conventional commit prefix (e.g. revert: rollback to pre-X.Y.Z). Once merged, release-please will auto-create a release PR with the version bump. Merge that release PR, and the publish workflow will publish the reverted code to npm.
Remember to do a quick sanity check after release with npm @posthog/wizard@latest to see if your fix actually worked.
Declare an incident
If an upstream dependent PostHog service like OAuth or the AI gateway is down, an incident may already in progress. Check the #incidents channel for any related alerts. If not, declare an incident, describing the highest-level issue that's causing the wizard to fail.
If the wizard client code itself is failing, that's an incident as well.
The is responsible for improving the docs. This means:
Building tools and systems to improve baseline quality and structure
Shipping docs content based on prioritized feedback and emerging use cases
Reviewing and improving draft documentation created by product teams
Improving the subjective docs experience (navigation, discovery, interactivity, etc.)
Creating context services that power agents like the AI wizard
Working on large scale docs projects
Ownership within the Wizard & Docs team
We've previously assigned ownership to areas of the PostHog platform and product docs to individuals, but we're presently more project orientated.
You can view what we're working on right now by:
Reading our goals on the page
Dropping in on our #team-wizard-and-docs Slack channel
You can share ideas / requests for new docs in the #team-wizard-and-docs Slack channel, or by creating an issue on the posthog.com repo.
As ever, though, PRs > issues. ;)
Sources for inspiration
There are lots of places you can go to find inspiration for what to work on during your stint, such as:
community questions
open issues on our project board
feedback in #brand-mentions
#docs-feedback
#content-docs-ideas
#ask-max for questions missing content
Inkeep chat sessions where there is a documentation gap
Most unhelpful docs
Most popular docs
that annoying thing you saw that you keep meaning to go fix
FAQ
I'm really busy, can the team write docs for me?
We can help, but we can't do it all for you. We lack the context necessary to document new features. First drafts of documentation must always come from the relevant product team.
If you need help updating documentation:
Write a draft that covers the basics, which the content team can then help review and polish.
If multiple docs pages need updating, create an example of changes needed and then request help to complete the rest.
Bottom line: It's much easier for the content team to improve a draft than write completely new documentation, especially when documenting new features. Pull requests > Issues.
Who should review docs updates?
Tag the docs reviewers team on GitHub and someone will come running.
You can embed light mode and dark mode versions of the image using this code snippet:
<ProductScreenshot
imageLight = "https://res.cloudinary.com/dmukukwp6/image/upload/add_holdout_light_ce0827be42.png"
imageDark = "https://res.cloudinary.com/dmukukwp6/image/upload/add_holdout_dark_cc687f7688.png"
classes="rounded"
alt="Screenshot of the form to create a new holdout"
/>
First, you should start with two assumptions about our users.
They're busy and have limited time.
They're not experts and don't know what we know.
This style guide helps you write docs based on these assumptions.
These are guidelines, not rules. They exist to keep our docs consistent and polished, but good judgement matters more than strict adherence when you're writing. If something makes the docs clearer, more helpful, or just plain better, do it.
See the style guide from the for additional writing guidelines.
---
Tools to enforce style
Tools like prose linters and LLMs are effective at catching style guide violations that humans often miss. Use them to check your writing against this entire guide.
We apply style guides through multiple tools.
Vale – enforces style guide rules through prose linting in PRs
InKeep docs writer – an AI agent that uses style guides as context when drafting docs PRs
Skill – (coming soon) agent skills that uses style guides as references for writing docs
---
Voice and tone
Address the reader directly
Address the reader directly using "you" instead of "the user", "developers", or "we".
Do: "You can create an insight by clicking New insight."
Don't: "Users can create insights."
Use the imperative form and drop the "you" when giving instructions, commands, or guidance.
Do: "Create an insight by clicking New insight"
Use active voice
Active voice makes it clear who or what performs an action.
Do: "PostHog captures events automatically."
Don't: "Events are captured automatically by PostHog."
Exception: Use passive voice when the actor is unknown or unimportant.
Acceptable: "The data is encrypted at rest."
Use present tense
Write in present tense. Avoid future tense unless you are explicitly describing future behavior or outcomes.
Do: "The insight displays your data."
Don't: "The insight will display your data."
Be concise
Remove unnecessary words. Every clause should add either value or clarity.
Do: "Click Save"
Don't: "Now you can go ahead and click the Save button to save your changes"
Avoid unexplained jargon
When you introduce technical terms or acronyms, explain them on first use or link to a definition. Don't assume the reader knows what you're talking about.
Do: "Create a cohort to analyze behavior. A cohort is a group of users who share common properties."
Do: "Create a cohort — a group of users who share common properties — to analyze behavior."
Don't: "Enable LTV analysis by configuring your CDP and syncing cohort data to the warehouse."
Contractions
Use contractions to maintain a conversational tone.
Do: "That's it. The experiment is running."
Don't: "That is it. The experiment is running."
---
Product terminology
Capitalize product names
Always capitalize PostHog product names as proper nouns. Use "Product Analytics", not "product analytics".
Do: "Use Session Replay to understand user behavior."
Don't: "Use session replay to understand user behavior."
However, if you're referring to the general industry term or a feature that isn't specific to PostHog, use lowercase. For examples: "many companies offer product analytics."
Keys and tokens
| Term | Description | |------|-------------| | Project token | The public identifier (starts with phs_) used in SDKs and the snippet to send events. This is NOT an API key. Never call it project API key. | | Personal API key | A private key (starts with phx_) used for server-side API access. This IS an API key. | | Feature flags secure API key | A separate key used for local evaluation of feature flags. |
Do: "Add your project token to the PostHog initialization code."
<!-- vale PostHogBase.ProjectToken = NO -->
Don't: "Add your project API key to the PostHog initialization code."
<!-- vale PostHogBase.ProjectToken = YES -->
PostHog platform
| Platform term | Description | |---------------|-------------| | PostHog | Use by default. Refers to our cloud platform. Most users are on cloud, so do not specify "Cloud" unless differentiating from self-hosted. | | PostHog Cloud | Only use when explicitly differentiating cloud features from self-hosted deployments. | | Self-hosted PostHog or hobby deployments | Use when referring to self-hosted installations. |
Do: "Go to Insights in the PostHog app and click New insight."
Do: "This feature is only available on PostHog Cloud."
Don't: "To create an insight on PostHog Cloud, go to the Insights tab."
---
Grammar and mechanics
Use American English
PostHog is a global company. Our team and our customers are distributed around the world. For consistency, we use American English spelling, grammar, date, and time formatting.
Do: color, analyze, behavior, license
Don’t: colour, analyse, behavior, licence
Sentence case for headings
Use sentence case for all headings. Capitalize only the first word and proper nouns like our products.
Do: "## How to create a feature flag"
Do: "## Get started with PostHog Feature Flags"
Don't: "## How To Create A Feature Flag"
Oxford comma
Always use the Oxford comma.
Do: "PostHog offers analytics, session replay, and feature flags."
Don't: "PostHog offers analytics, session replay and feature flags."
Numbers
Spell out numbers zero through nine
Use numerals for 10 and above
Use numerals for percentages, measurements, and technical values
Do: "You can create three dashboards" or "You can create 15 dashboards."
Do: "Set the timeout to 30 seconds."
Use straight apostrophes and quote marks
Many writing tools, such as Google Docs, Notion and Word, add curly quotes and apostrophes. Please avoid using these. They can normally be turned off in the settings.
Use British-style en dashes
While we default to American English in most things, we prefer using the British-style en dash ( – ) with a space either side rather than the longer em dash with no spaces (—) used in American English.
Please don't use a hyphen instead of en dash. On Macs, holding down Option and the hyphen key will give you an en dash.
Do: "Don’t up vote your own content, and don’t ask other people to – post it and pray."
Don't: "Don't up vote your own content, and don't ask other people to—post it and pray."
Follow official capitalization for branded technologies.
Do: GraphQL, WebSocket, PostgreSQL
Choose simple words
Choose simple, common words over complex alternatives.
| Instead of | Use | |------------|-----| | utilize | use | | facilitate | help | | commence | start, begin | | subsequent | next | | prior to | before |
Use precise verbs
Use precise verbs that clearly describe the action being performed.
| Vague | Specific | |-------|----------| | use the API | call the API | | work with data | query data, analyze data | | handle errors | catch errors, log errors | | manage users | add users, remove users, assign roles |
Problem/Solution labels - **Problem:** and **Solution:** in troubleshooting docs
Do: "Note: Use feature flags to control rollouts."
Do: "Problem: Events aren't appearing in the dashboard."
Avoid using bold text for general emphasis in prose. If something is important and needs extra emphasis, consider using a callout box instead.
Don't: "This is a really important step in the process."
Don't: "Make sure you always configure this setting before deploying."
Bold UI elements
Use bold for UI elements like buttons, menu items, labels, and text fields. Don't use quotes.
Do: Click New insight in the Insights tab.
Don't: Click the "New insight" button.
For nested UI elements, use > to connect them hierarchically.
Do: In PostHog, navigate to Settings > API keys > Personal API key.
Don't: In PostHog, navigate to Settings, look under API keys, and then click Personal API key.
Avoid excessive formatting
Don't use:
Multiple header levels in short sections
Bold text for general emphasis in prose
Lists when prose is clearer
Too many callout boxes
Choose components by task
Use existing docs components. Keep plain Markdown for prose, lists, and reference tables.
| Reader's task | Component or format | Guidance | |---|---|---| | Choose an equivalent code example | MultiLanguage selector="tabs" | Label each language or framework. Keep the examples equivalent. | | Follow an ordered procedure | Steps and Step | Give each step one action and an expected result. Keep required steps before optional work. | | Navigate an existing guided quickstart | QuestLog and QuestLogItem | Reuse the guide's structure. Keep the path to the first result short. | | Notice a consequential limitation | CalloutBox | Keep warnings visible beside the affected step. Use callouts sparingly. | | Read advanced compatibility notes | <details> and <summary> | Use a descriptive summary. Keep prerequisites and required instructions outside the fold. | | Inspect a product screenshot | ProductScreenshot | Supply useful alt text and light/dark variants when needed. |
Check the component's README, when present, and an existing usage before adding it. Do not create a new component for a pattern we support.
Check the Markdown export
Readers and AI agents use Copy page and the page's .md URL. Those exports must contain the same instructions as the website.
Check that the export preserves:
Every language example, including inactive tabs
Code indentation and blank lines
Table columns, empty cells, links, and inline code
Compatibility notes inside closed details
One title and one image per light/dark screenshot pair
Exclude copy buttons and other page controls from the export. Fix conversion problems in the shared exporter, not in a second copy of the docs.
Run pnpm test:markdown when you change components or Markdown conversion. Add a focused case if your change introduces a new rendering pattern.
Minimal preview builds do not generate .md files. Check the actual export from a full build before claiming that a preview validates it.
Links
Wikipedia-style internal links
Link the first mention of a PostHog term, feature, or SDK on a page to its docs page.
Example: "To create an insight, first capture events. Then, select the data you want to see."
Link to the PostHog app
Link directly to PostHog in-app pages using https://app.posthog.com/. Users are redirected automatically to the correct US or EU subdomain.
Do: "Go to the Insights tab and click New insight."
Don't: "Go to the Insights tab and click New insight."
Don't: "Go to the Insights tab and click New insight."
Link text
Link text should describe the destination. Avoid generic text like "click here" or "this page."
Never use camelCase or PascalCase for event or property names.
Show real-world examples
Use realistic examples that demonstrate actual use cases.
Do:
```js
posthog.capture('purchase_completed', {
product_id: 'prod_12345',
revenue: 49.99,
currency: 'USD'
})
```
Don't:
```js
posthog.capture('event', {
property: 'value'
})
```
Comment sparingly
Only add comments when code isn't self-explanatory:
// Don't show the survey if user dismissed it in the last 30 days
if (lastDismissed > Date.now() - 30 * 24 * 60 * 60 * 1000) {
return
}
---
Screenshots and media
It's extremely important to ensure screenshots or videos don't show any personal or sensitive user information like emails, phone numbers, or other identifying details.
Screenshot requirements
To maintain consistency and clarity:
Focus on the relevant UI - Exclude sidebars and irrelevant interface elements
Use standard viewport - Set device width to 1000-1400px in devtools
Use annotations – Add arrows, text, or other visual elements to highlight specific UI elements
We have one of the coolest changelogs on the internet. It's also one of the busiest.
As a company that ships weirdly fast, it's important to share what we're working on with as many people as possible, as often as possible. The changelog is a great way to do that.
Most of it runs itself now too. A bot finds the work worth announcing, engineering teams review it in Slack, and it lands on the website.
What gets included
New features, mostly! But changelog entries can also include beta launches, UX improvements, or performance improvements.
For engineers, here's the rule of thumb: _if you'd want a user to know about it, it belongs in the changelog_.
A published changelog entry
The changelog bot
To stay on top of shipping speed, we released a changelog bot in Slack. It turns PostHog PRs into published changelog entries, with a human approving each one in Slack.
Here's how it works:
Daily intake. A Cloudflare Worker scans merged PRs across 26 repos and records every one as a candidate.
Weekly curation. An AI agent inside the same Cloudflare Worker looks at each team's _entire week at once_ and ranks their shipped PRs. It surfaces at most 10 items per team, rolls near-duplicates into groups, and sets aside anything not worth announcing on the changelog. It writes editorial copy for the surfaced items.
Digest. Every Thursday, a Python app posts one message per team into that team's Slack channel, with one card per surfaced entry.
Review. Teams use the cards to review changelog entries before publishing.
Publish. When someone selects Publish in Slack, the same Python app opens an issue in PostHog/changelog-drafts with the fields as YAML frontmatter plus a publish label. That repo's GitHub Action holds the Strapi token and does the actual POST to posthog.com.
The Slack workflow looks like this:
<ProductVideo videoLight="https://res.cloudinary.com/dmukukwp6/video/upload/Clean_Shot_2026_08_24_at_11_11_17_d851cc5932.mp4" alt="Changelog bot workflow in Slack" classes="rounded" />
Publish what doesn't make it into the digest
The changelog bot does a good job at picking PRs for weekly digests, but sometimes it misses something it should have surfaced. No problem!
On a weekly digest in Slack, there's a 🗃 See what didn't make it button that shows everything the curator set aside for your team. It's split into two groups:
Near-misses — real user-facing work that fell just below the cut. This is the pile you're usually looking for.
Internal — no user-visible change. These are shown anyway, so you can correct the bot if it got one wrong.
Selecting Add to digest on any of them kicks off the curation step. The AI curator will write a draft for you and post a new card into the same digest thread. Sometimes you may just have to wait a few seconds for it to finish.
Changelog content and ownership
Technically speaking, the changelog is a stream of content that's published across multiple channels.
From start to finish, a changelog entry is:
Posted in each team's channel, via the weekly digest
The engineer is responsible for reviewing their team's digest cards and making sure their feature actually makes it through. The curator writes the first draft, but you're the one who knows whether it's right.
The changelog code and data (stored in our Strapi CMS) is maintained by the . To learn more about how the features work, check out their roadmap and changelog handbook pages.
How to publish manually
People are encouraged to self-serve and publish changelog entries. If you'd rather skip the bot entirely, here's how.
You must be logged into your posthog.com account. Only website moderators (a.k.a PostHog employees) are permitted to publish changelog entries.
Option 1: The main changelog
Go to the /changelog page and click the + button in the top right corner.
Fill out the changelog form and click Create to publish.
The changelog entry will appear on the website on the next website build, which is usually when a PR is merged into the master branch.
| Field | Required | Recommended value | |-------|----------|-------------------| | Title | Yes | The title of the changelog entry. Keep it short and sweet. | | Description | Yes | The description with native Markdown support. Add screenshots or gifs here. | | Hero image | No | We leave this empty. We add images in the description field for more control. | | Status | Yes | It must be set to Complete to appear in the changelog. | | Date | Yes | The completed date of the changelog entry. | | Team | Yes | The team that shipped the feature. | | Author | No | We normally leave this blank because we pull in GitHub PR metadata which includes author and reviewers. | | Product or feature | Yes | The category or product area of the feature. Select Uncategorized if nothing fits. | | Type | Yes | Set to New feature for most changelog entries. | | GitHub URLs | Yes | It's technically optional, but the GitHub URL populates the changelog entry with the feature's PR metadata. | | Category | Yes | The product category of the changelog entry. | | Show on homepage | No | Always set the toggle to off or no. |
Option 2: The product changelogs
Each product has a dedicated changelog page in their docs that filters entries from the main changelog. You can also publish directly from these pages using the + Add changelog button.
Each product should have a changelog page in their docs
Add a /docs/<product>/changelog link to the product's sidebar in src/navs/index.js.
Add an entry for the product to productConfigMap in src/components/Docs/ProductChangelog.tsx, mapping it to the topic and team names used in Strapi.
Step 3 is the one people forget, so CI fails if a page is missing it. The same applies when a topic or team is renamed in Strapi — update productConfigMap to match, or the page goes empty.
At PostHog, we want our docs to win over developers and give us a competitive edge.
The focuses on delivering a delightful developer experience, maintaining a well-organized knowledge base, and writing documentation that is a genuine pleasure to read for both humans and robots.
Our team's values
Treat docs like a product
Be practical, not just technical
Great docs start with writing
Teach the robots
Help our customers win
1. Treat docs like a product
We treat our docs like a product because they are. They have users (readers and AI agents), use cases (implementation, education, troubleshooting, etc.), and success metrics (more on this later).
Documentation presents unique challenges and opportunities. But ultimately, great docs drive product activation by providing the right information, in the right way, at the right stage in a developer's journey.
This means helping developers set up their very first PostHog event and helping existing customers with complex configurations integrate their third or fourth PostHog product. It also means enabling our docs to be used as context for AI workflows. It's a wide spectrum, but the goal is the same: help developers self-serve and succeed with PostHog.
Docs are a core part of the product experience. So when you're working on them, take some time to ask:
Where is the reader on their PostHog developer journey?
Where do they need to go next?
How does this help them get there?
Can the reader use this as valuable context for AI?
2. Be practical, not just technical
Developers don't want abstract examples or out-of-context code snippets. They want to solve real problems and use cases.
We want to showcase code that's runnable, practical, and immediately useful.
As a rule of thumb, our docs should show code within application context whenever possible. The examples we provide should reflect how PostHog is actually used in production, in the wild.
The in-context example is more verbose, but much more useful. It shows how PostHog fits into applications, which helps developers understand when and where to use it.
3. Great docs start with writing
Writing is something we love to do here at PostHog. The principles of PostHog writing and marketing all still apply here.
But documentation has a few unique demands.
People come to our docs looking for answers, usually with limited time. We focus on precise and consistent writing because they contribute to a smoother, more efficient learning experience.
Docs need to be finely tuned. Even small oversights or tiny mistakes can create snags that confuse readers. So nitpicking isn’t just allowed, it’s encouraged!
<summary>Nitpick #1</summary>
~~Just~~ Click Save ~~and the insight will be created~~ to create an insight.
<summary>Nitpick #2</summary>
~~Events are captured automatically by PostHog.~~ PostHog captures events automatically.
Nits and semantics and formatting (oh my!) – they're all part of the fun of technical writing. Careful attention to detail is what turns good docs into great ones, so don't shy away from it.
This does not mean our docs have to be dry or academic. In fact, they should have a natural flow that makes them easy to read. Be open, direct, and opinionated. Don't be afraid to add humor and personality when there's opportunity.
PostHog's writing voice is one of the key things that sets us apart from a sea of generic SaaS platforms. It's important that this voice can come through in our docs.
The docs style guide is a key reference we'll continue to update with examples and best practices.
4. Teach the robots
Robots aren’t a future concern. They're already here, and they're changing how people discover, evaluate, and use PostHog.
AI workflows depend on accurate and up-to-date context. Our documentation, the knowledge base, is the largest maintained source of natural language context we have. LLMs read our docs. Developers paste them into prompts. Agents use them as skills.
In other words, our docs teach AI how to be useful.
The AI wizard is a direct outcome of this philosophy. An agent that automatically integrates multiple PostHog products across frameworks, the wizard is the fastest way to activate PostHog because it consumes our docs as structured, on-demand context. It closes the gap between curiosity and real usage.
Making this possible requires context engineering and shaping our documentation into a moving, living system. We code as much as we write.
5. Help our customers win
Our customers are smart, discerning, and ambitious. They're here to build. They want to 10x their own products.
Our docs exist to help them win.
This means we should include details beyond references and technical implementations. We should share examples, use cases, and the big picture reasons why they should use a product or feature.
How we prioritize
Here's how we loosely define high-priority docs work:
Anything that blocks product adoption or severely impacts the product experience
Anything that speeds up new content velocity or improves overall quality
Anything that unblocks better LLM-assisted workflows
Usable docs (e.g., SDK references) come first. Cool docs (e.g., interactive code editor) come after
Measuring success
Our north star indicators that tell us if our docs are heading in the right direction:
Praise for how awesome our docs are (#brand-mentions, #posthog-feedback, etc.)
More docs transformed into high-quality context for AI agents
Fewer support tickets caused by bad or missing docs
More docs used by customer facing teams as a valuable self-serve resource
The website's core technical architecture is built and maintained by the . See their handbook pages on the website and MDX components for more information.
Gatsby and MDX features
Snippets for content reuse
Create snippets in a _snippets/ directory for content you want to reuse across multiple pages.
When to create a snippet:
Content appears in 2+ pages
Event schemas or property tables
Platform-specific code blocks
Reusable UI components
MDX snippets
Create an MDX snippet for static reusable content like tables, callouts, or text blocks.
The error event includes the following properties:
| Property | Type | Description |
|----------|------|-------------|
| `$exception_message` | string | The error message |
| `$exception_type` | string | The error type |
Use the snippet in an MDX page like this:
TSX snippets
Create a TSX snippet for dynamic content for lightweight components or React hooks.
If the TSX snippet contains substantial logic, create a reusable component or hook in /src/components/ or /src/hooks/ instead.
Frontmatter
All .mdx pages support frontmatter, which Gatsby uses to configure page metadata.
---
title: Install PostHog for React
platformLogo: react
showStepsToc: true
---
This guide walks you through installing PostHog for React.
Here's a table of available frontmatter fields:
| Field | Purpose | Example | |-------|---------|---------| | title | Page title | React installation | | platformLogo | Platform icon key for installation pages | react, python, nodejs | | showStepsToc | Show steps in right sidebar TOC | true | | hideRightSidebar | Hide right sidebar TOC on start-here and changelog pages | true | | contentMaxWidthClass | Control and customize the width of main content column | max-w-5xl | | tableOfContents | Override the auto-generated TOC with custom entries | [{ url: 'section-id', value: 'Section Name', depth: 1 }] |
Magic <placeholders>
You can use magic placeholders or strings to replace the project token, project name, app host, region, and proxy path in the code block with values from the user's project.
If the user is logged into the PostHog app, the placeholder will be replaced with the actual value from their project.
If the user is not logged into the PostHog app, the placeholder will display as is.
| Placeholder | Description | Default | | -------------------------- | ----------------------------- | ----------------------------------------------- | | <ph_project_token> | Your PostHog project token | n/a | | <ph_project_name> | Your PostHog project name | n/a | | <ph_app_host> | Your PostHog instance URL | n/a | | <ph_client_api_host> | Your PostHog client API host | https://us.i.posthog.com | | <ph_region> | Your PostHog region (us/eu) | n/a | | <ph_posthog_js_defaults> | Default values for posthog-js | 2026-05-30 | | <ph_proxy_path> | Your proxy path | relay-XXXX (last 4 digits of project token) |
You can use these placeholders in the code block like this:
const client = new PostHog('<ph_project_token>', { host: '<ph_client_api_host>' })
Docs components
Screenshots and gifs
For UI screenshots and gifs with light and dark variants:
<ProductScreenshot
imageLight="https://..."
imageDark="https://..."
alt="Descriptive alt text"
classes="rounded"
/>
For code examples in multiple programming languages:
// JavaScript example
Python example
Callout boxes
You can add callout boxes to documentation to ensure skimmers don't miss essential information.
Here is some information
Three styles are available:
fyi: this is for stuff that's helpful but not critical
action: these are tasks developers should complete and not miss
caution: these flag the potential for misconfiguration, data loss, and other churn vectors
They look like this:
Provide detail here. You can go on at length if necessary.
Provide detail here. You can go on at length if necessary.
Provide detail here. You can go on at length if necessary.
Valid icons are listed in PostHog's icon library.
Steps
Use the <Steps> component for content that walks the reader through a strict sequence of instructions. Think how-to guides or step-by-step tutorials.
Steps are automatically numbered.
Write the _content_ in **markdown**.
Add checkpoints to help readers verify their progress.
Our mdx parser does not play nice with certain whitespace. When using the component, make sure you:
Add a line break after the opening component tags
Avoid using 4-space indents
Decision tree
Use decision trees to help users choose between 2-6 options:
<DecisionTree
questions={[
{
id: 'platform',
question: 'What platform are you using?',
options: [
{ value: 'web', label: 'Web' },
{ value: 'mobile', label: 'Mobile' },
],
},
]}
getRecommendation={(answers) => {
// return recommendation based on answers
}}
/>
PostHog AI components
You can also link to PostHog AI which used to be called Max AI.
Use <AskMax> to provide in-context help:
The <AskMax> component opens the PostHog AI chat window directly on the website. Use this for documentation pages where users might need help understanding concepts or troubleshooting. Unlike <MaxCTA> which links to the PostHog app, this keeps users in the docs context.
<AskMax
quickQuestions={[
'How do I mask sensitive data?',
'Can I enable recordings only for certain users?',
'How can I control costs?',
]}
/>
<AskAIInput> renders a question box that opens the PostHog AI chat window seeded with what the reader typed, plus the current page as context. Every docs page already gets one automatically under the title, so don't add it by hand to a page under /docs – you'll end up with two.
The shortcode is still available for pages outside /docs that want one:
Linking to PostHog AI in the app
The <MaxCTA> component renders a callout that sends readers into the PostHog app with a question for PostHog AI:
Under the hood it builds a URL using the #panel=max: hash format, which you can also use directly in any link. The question must be URL-encoded (encodeURIComponent), and an optional prefix before the question controls what happens when the panel opens:
| URL | Behavior | |-----|----------| | https://app.posthog.com/#panel=max:What%20changed%3F | Opens the PostHog AI side panel with "What changed?" pre-loaded, so the user can edit it before sending | | https://app.posthog.com/#panel=max:!What%20changed%3F | Auto-runs "What changed?" immediately, without waiting for the user to press enter |
Use the pre-load form when the reader should review or adapt the question first, and the auto-run (!) form for CTAs where the question is fully self-contained, like <MaxCTA> does. The prefix parsing lives in parseCommandString in maxLogic in the app repo.
Platform logos
All platform logos are centralized in src/constants/logos.ts. To add a new platform:
Upload SVG to Cloudinary
Add key to src/constants/logos.ts in camelCase
Reference in MDX frontmatter: platformLogo: myPlatform
Use consistent naming: stripe, react, nodejs, etc.
Debugging MDX issues
Common MDX parsing issues:
Avoid deep indentation. Stay at 2 spaces or less
Add line breaks after opening JSX tags and before closing tags
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.
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 | |---------|--------| | AI Observability | ✅ 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 | | 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 like Steps, 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 different OnboardingContentWrapper to 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.
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_BRANCH environment 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.tsx that 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 start and verify the page renders correctly at the expected URL.
Commit and merge both the posthog/posthog and posthog/posthog.com PRs.
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.
Pocket guides are the docs site's use case books at /pocket-guides: each volume is a shelf cover, a 101, and a set of use cases that each end in a CTA. They render as a full-window e-reader – figures embedded where the prose cites them – and everything a reader sees is authored in MDX.
Every use case ends in one action, and the action is what the volume is for. Self-driving chapters add a custom scout. AI Observability chapters hand over a PostHog AI prompt that builds the eval, dashboard, or funnel the chapter describes. A future Support volume will have its own. Pick the shape when you plan the volume, not per chapter – a book where every chapter ends somewhere different reads as a link dump.
Only use cases get a CTA. The front matter and the 101 point onward with ordinary links in the prose. Giving those pages a button too spends the reader's attention on "install this" and leaves nothing for the action each use case is actually built around.
Which volume does a use case belong to? If the answer is a custom scout, it belongs in the self-driving volume, even when the subject is AI Observability or Support. Other volumes cover their product outside self-driving, and cross-link to the scout chapter that automates the manual loop they just taught.
This page is the short version for authors. The source of truth for the component side lives in the repo: src/components/PocketGuides/README.md (the reader, figures, and MDX traps) and src/components/SelfDrivingInbox/README.md (the report frontmatter contract, the SKILL.md format, and the agent-mirror constraints).
How a guide is authored
A use case is one directory:
contents/pocket-guides/<volume>/<slug>/
├── index.mdx everything a human reads
└── SKILL.md the scout itself, verbatim (scout volumes only)
Copy contents/pocket-guides/self-driving/_starter/ to begin – it's a commented skeleton
of both files, kept out of every gallery by the _ prefix.
Frontmatter carries the structured data: title, shortTitle, pocketGuideOrder (reading
order; 0 is the front matter, omit to keep a draft unlisted), the report block that renders as the inbox figures, watches, requires, category, and schedule.
A non-scout chapter carries a pocketGuideCta: block instead – kind: prompt with the PostHog AI
prompt itself, or kind: link with a destination – rendered by `` where the chapter wants it, and repeated in the reader's pinned bar automatically.
A new volume is a directory plus a row in src/constants/pocketGuides.ts. The reader reads
the volume id off the slug, so nothing in the components needs to know your volume exists.
The body carries every word.<LeftPage> holds the figures, <RightPage> the prose; the
reader interleaves each figure after the first block that cites it via ``.
SKILL.md is a real file, not a string – same frontmatter as the canonical scouts in the
monorepo, so one can be pasted in or lifted out without reformatting. The page renders it byte-for-byte, and the "Add this scout" deep link prefills PostHog from it.
**When PostHog already ships the scout as a template, set appTemplate: and write no
SKILL.md.** The CTA opens that template in the app, which carries the tags and schedule the encoded deep link doesn't, and the scout file is fetched from the monorepo at build time so the page can't describe a scout the button doesn't create – details in src/components/SelfDrivingInbox/README.md.
The two MDX traps
Never start a line with an inline component (<Term>): MDX v1 treats a line-leading tag
as a block and splits the paragraph. Keep inline tags mid-sentence.
Don't hand-wrap block components in paragraphs – and if a figure ever renders inside a
<p>, check the gatsby-remark-inline-jsx-paragraphs plugin's pocket-guides guard first, then remember Gatsby caches compiled MDX (the fix shows only after the .mdx changes or pnpm clean).
Keep the learning in the book
A reader who clicks out to the docs mid-page usually doesn't come back. So when a guide names something the reader might not know, define it in place:
<Term> for a concept – the definition appears on hover, and clicking the term opens the
docs page that owns it.
Figure markers for parts of a screen – hovering a numbered marker glosses that element.
Plain links only for things the reader is meant to go do, like an install guide, or for a
neighbouring guide.
If you find yourself writing "see the docs for X" mid-sentence, X probably wants to be a term.
Term definitions
<Term> hover-card definitions live in src/components/PocketGuides/terms.tsx, each quoted from the docs page it links to. If a docs definition changes, update the quote there.
Adding new content elements
The book styles every markdown element itself (its container opts out of the site's prose styling), so a new kind of content – a table, a new list style, anything the guides haven't used before – renders unstyled until the book's component map supports it.
Check the rendered page whenever you introduce an element the guides haven't used yet.
Unsupported elements fail silently: browser-default styling, not an error.
Inherit website defaults instead of reinventing them. Wrap the element in the site's
native styling (see how lists and tables borrow .article-content in src/components/PocketGuides/bookPieces.tsx) rather than writing book-specific styles.
Test text resizing on web and mobile. Use the Aa control at every size, at desktop and
phone widths – the book's type scales from one base size, and new elements need to keep up.
Measuring
Reader interactions emit the pocket_guide_interaction event (marker glosses, term hovers, contents, font size, scout-file expansion), and every CTA emits it too. The kind property names the action:
cover_click – a volume opened, with the volume id. Fires from every surface that shows a
cover or a spine, so placement is what tells them apart.
shelf_link_click – the "All guides" link out to the shelf, rather than a single volume.
add_scout_click – both "Add this scout" CTAs, with the scout name. That click is the
conversion for a self-driving guide.
cta_link_click and ai_prompt_click – the ` button, with the guide` url.
ai_prompt_copy – the PostHog AI prompt copied from its code block. For a prompt guide this
is the conversion, not the button beside it – a reader who copies the prompt has taken the action whether or not they use the deep link.
skill_file_copy – a scout or SKILL.md file copied from its figure, with the file's name.
Volumes that ship a skill rather than a scout have no button at all, so this is their conversion.
guide_link_click – a link in a guide's prose, with its href. Some chapters answer with a
link (the skill on GitHub, a docs page), which makes that link the chapter's CTA.
setup_command_copy – the wizard command copied from a volume's front matter, a CTA
prerequisite, or the "Not set up yet?" block.
Every CTA also sends a placement, so the pinned bar can be compared against the block it shortcuts, and so a guide open can be traced to the surface that sent it.
Inside a guide: action_section, enable_section, front_matter, figure, prose,
pinned_bar.
Surfaces that open a guide: shelf (/pocket-guides), docs_index (the /docs library
column), product_docs (a product's docs page), self_driving_page (/self-driving).
placement is a required prop on Cover and VolumeCard, so a new surface cannot ship without declaring itself – the build fails first.
A new volume needs no tracking work. The CTA components carry it, so a guide is measured as soon as it uses one. Adding a new kind of CTA is the only case that needs a new kind here.
SDK references document class, method signatures, and type interfaces for each SDK. They complement examples in tutorials and guides by providing a comprehensive reference with all the details. They're important for deep understanding of PostHog SDKs and as context for LLM-based tools. Tutorials and guides reference them for parameter and return type details.
Which SDKs have reference docs
It's an ongoing effort to create SDK reference docs for all our SDKs, starting with popular SDKs. Here's the current status:
| SDK | Status | |-----|--------| | JavaScript Web SDK | ✅ Completed | | Python SDK | ✅ Completed | | Node.js SDK | ✅ Completed | | React Native SDK | ✅ Completed | | iOS SDK | 🚧 In progress | | Flutter SDK | ⏳ Not started | | Android SDK | ⏳ Not started | | Go SDK | ⏳ Not started | | Java SDK | ⏳ Not started | | Rust SDK | ⏳ Not started | | PHP SDK | ⏳ Not started | | .NET SDK | ⏳ Not started |
How the SDK reference docs work
SDKs are parsed for basic information like class names, method names, and type interfaces.
Descriptions, parameters, return types, and examples are extracted from the SDKs or SDK doc comments.
The information is rewritten into a standardized JSON format (HogRef). They're stored in each SDK's repository under a references directory. For example, the JavaScript Web SDK reference is stored here.
When an SDK releases a new version, the reference docs are generated automatically. Here's an example workflow.
The Strapi instance behind the website is configured to fetch the HogRef JSON files from the SDK's repository and display them on the website via a cron job.
The website renders the HogRef JSON files as a table on the SDK reference page.
Each language works slightly differently, but the general process is the same.
Create a workflow to generate the HogRef JSON file when a new version of the SDK is released. See an example workflow.
Update the cron-tasks.ts file to fetch the HogRef JSON file from the SDK's repository and display it on the website.
Once the HogRef is ingested into the Strapi instance via the cron job, a new page should be created automatically on the website. The website will render the HogRef JSON file as a table on the SDK reference page.
Find existing links to the SDK's GitHub repository source code and point them to the new HogRef JSON file instead.
Vale is a prose linter that enforces PostHog's writing style across the website: docs, blog posts, newsletters, and more.
It catches spelling mistakes and style inconsistencies based on rules we define – like the unforgivable use of em dashes.
Why use a prose linter?
Prose is infinitely diverse. Different authors, tones, and writing goals make inconsistencies easy to introduce and a nightmare to maintain.
A prose linter creates a baseline. It automatically enforces the core mechanical and stylistic rules we care about most as a brand, so our writing stays consistent.
"Never send an LLM to do a linter's job." – someone
LLMs can generate drafts and reviews, but they are not reliable linters. They're slow and expensive compared to deterministic tools.
Use Vale to detect issues, then use LLMs to hep fix them.
pnpm vale:staged # Lint md/.mdx files you have staged in git
pnpm vale contents/blogs/ # Lint a specific directory
pnpm vale contents/blog/my-post.md # Lint a specific file
pnpm vale . # Lint current directory
pnpm vale:test # Lint the .vale/test/ directory
Styles are enforced by a collection rules and checks written as YAML files. We can organize these rules into directories to create different style guides for different areas of our website.
Vale then applies these rules hierarchically and in combination with each other.
PostHogBase Rules for all .md and .mdx files
├── AmericanEnglish
├── ProductNames
├── EnDash
├── OxfordComma
├── Spelling
├── Inclusivity
└── ...
PostHogDocs Rules for /docs
├── DefinitionListDash
├── DirectAddress
├── Trivializers
└── UIBoldNotQuotes
PostHogEditorial Rules for /blog, /newsletter, /tutorials
├── BulletSpacing
├── EnableNotAllow
└── Hedging
Adding a rule
Pick the right directory. PostHogBase will apply the rule everywhere, PostHogDocs to the docs, and PostHogEditorial to the blog, newsletter, and tutorials.
Create a .yml file in the respective styles/ subdirectory.
The two most common rule types are substitution and existence.
# Substitution – suggest a replacement
extends: substitution
message: "Use '%s' instead of '%s'."
level: warning
swap:
colour: color
# Existence – flag terms that shouldn't appear
extends: existence
message: "Avoid using '%s'."
level: warning
tokens:
- simply
- obviously
Each rule can be configured to a severity level:
Errors
Warnings
Suggestions
We generally stick to warnings and suggestions.
The Vale docs have more information on rule types and configuration.
If you add a new rule, update the test/ directory with examples and run pnpm vale:test to see if it works as expected.
You can also test specific rules with the Vale CLI.
Not every violation is actually a mistake. We frequently use industry terms, brand names, and colloquialisms that aren't in standard dictionaries like "faq", "devops", or "stonks."
You can add exceptions to the Vale rules as vocabulary or as a spelling exception.
Vocabularies are case-sensitive regex patterns that enforce exact capitalization. Use for brand names, products, and technologies where casing is a part of correctness. They will be exempt from rules like SentenceCase.yml.
Spelling exceptions are case-insensitive words the spell checker should accept. Use for industry terminology or developer jargon that isn't in standard dictionaries. They will be exempt from the rule Spelling.yml.
The .vale.ini file
We've configured global ignores in .vale.ini based on certain scopes, tokens, and tags.
This guide explains how to write and structure your tool's documentation. A tool is a PostHog capability like support, error tracking, or product analytics. We used to call these "products" or "apps".
Products are the surfaces a tool runs on – Web, Slack, MCP, PostHog Desktop. That's the Surfaces section.
Context is the data that feeds the tool and the self-driving loop. That's the Context section.
If the terminology here is confusing at all, check out the glossary.
The structrure outlined in this guide is intended for tool-specific docs. Some docs, like API and SDK references, won't fit nicely in this box. That's okay. Refer to the other Wizard & Docs handbook pages for how to write onboarding, SDK, and API docs.
Docs categories
We've created a standard, flexible structure for tool docs. Each section groups pages that serve a distinct purpose in the developer journey.
Every docs page should fit into one of the following categories:
Overview – The landing page for your tool's docs. Think of it as a one-pager for your tool.
Get started – The minimal steps and context needed to get your tool up and running.
Surfaces – Where and how people use your tool, across each product (surface) it runs on: the web app, Slack, MCP, PostHog Desktop. Every tool runs on at least one.
Context – The data that feeds your tool, and where it comes from.
Resources – Standalone "lookup" pages like pricing, troubleshooting, and references.
We recommend using Support docs as a reference. They're the clearest example of this structure, so they're a good template when writing docs for a new tool or improving an existing one.
PostHog has a wide variety of tools. For example, Data Pipelines is integration heavy while PostHog AI and Workflows are UI-oriented. They require different content structures for their docs, so adapt this structure to your tool's needs.
That said, stick to this structure first. It’s worked well for other tools, both in terms of docs-to-adoption conversion and user feedback, so it’s proven to be effective.
Sidebar navigation
The sidebar navigation mirrors the docs structure. The hierarchy drives how users discover and navigate docs. Here's how it looks for Support, our reference example:
<ProductScreenshot imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/q_auto,f_auto/support1_efb384ae51.png" alt="Support docs sidebar navigation, showing the section groups: Overview, Get started, Surfaces, Channels, Imports, and Resources" padding={false} />
Support fills the Context role with two top-level sections – Channels and Imports – because each is distinct enough to stand on its own. Your tool might need only one context section, or might name it something else. Ordering and grouping are controlled by array position and header-only nodes in src/navs/index.js.
Overview
This is your tool's book cover – a busy engineer scanning it should learn in seconds what it is, where they use it, where its data comes from, and how it feeds Self-driving.
Get started is a category, not a page. It groups the pages that get new users up and running as quickly as possible, with _just_ enough context to understand what's going on. Those pages are:
A Start here page
An Install or setup page (if your tool needs one)
Keep advanced or complex features out of these pages. Those belong on the relevant surface or context page.
Start here
A high-level map of the adoption journey – the milestones to succeed with your tool, like a video game's quest log. It acts as a syllabus: users invest more when they can see what they're signing up for. These are high-converting pages for paid ads, so they matter. Build it with the QuestLog component.
<ProductScreenshot imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/q_auto,f_auto/support3_543a55c537.png" alt="Support start here page, built with the QuestLog component" padding={false} />
Include the following, keeping advanced details to dedicated pages in surfaces, context, or resources:
Only include a dedicated installation page if your tool has an install or setup step. One page is enough for minimal setup (Support uses Set up the widget); SDK-based tools get an installation index plus a quickstart per platform.
SDK installation pages share a special architecture: they render the same content as the in-app onboarding flow, with the source of truth in the posthog/posthog monorepo pulled in automatically. The installation index auto-generates a grid of platform cards via usePlatformList(), sorted by src/navs/index.js order, with logos from each page's platformLogo frontmatter. See the onboarding docs handbook for setup.
Surfaces
_Where and how_ people use your tool – the web app, Slack, MCP, PostHog Desktop, or the API. Each of these is a product (surface); there's one page per product, framed around what the user does there. This section is always called "Surfaces," and it's where AI-driven work lives now (MCP and PostHog Desktop are products too – there's no separate "PostHog AI" category). Name pages after the action: "Use [Tool] in/on [Product]."
This is the data that feeds your tool, and where it comes from. Unlike Surfaces, this section's name changes per tool: Support splits it into Channels (where tickets come from) and Imports (history brought in from tools like Zendesk); another tool might call it Sources, Inputs, or Signals. In-depth "How X works" explainers live here too, attached to the data they describe.
Include the following in your pages here:
One or more top-level sections named for your tool's data sources
A "How X works" explainer for each source or key concept
A setup or connection guide per source
Mermaid diagrams for data flows (use PostHog brand colors!), and tables for definitions
These are quick lookup pages and may anything standalone that doesn't fit the other categories.
Include the following pages here, as needed:
Pricing – model, free-tier limits, how usage is calculated, and how to cut costs. Use <SingleProductPricing>. Transparency is a differentiator for us, so be upfront.
Troubleshooting or FAQ – frequently asked questions or common issues and fixes, kept current from support tickets. Remember: if it's something that can be documented in any of the above sections, it isn't really a good FAQ/troubleshooting guide. Use searchable headings with numbered solutions.
Changelog – tool updates via <ProductChangelog>, filtered from the main /changelog.
References – links to SDK reference docs and tool-filtered API docs.