debugging-experiments
Debug and support PostHog Experiments (A/B tests) for a customer looking at their own results.
Skill by PostHogOfficial
Chalk Labs
Need help deploying debugging-experiments?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/posthog-debugging-experiments-1de05b
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: backend, data
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions: not checked yet.
What's inside
- Skill name
debugging-experiments- Description
- Debug and support PostHog Experiments (A/B tests) for a customer looking at their own results. Use whenever an experiment support ticket is pasted or a customer asks a results question, most commonly "why aren't my exposures even?", "why is one variant getting no traffic?", "why am I missing / seeing too few exposures?", "why does the bias banner show?", or "why don't PostHog's numbers match my SQL?". Pulls the experiment's real data read-only, matches it to a known-cause catalog, and produces a customer-facing explanation, fix, and review of the pertinent numbers. Loads diagnosing-experiment-health as its deep diagnostic library. DO NOT TRIGGER when: creating an experiment (use creating-experiments), only configuring rollout (configuring-experiment-rollout) or metrics (configuring-experiment-analytics), asking lifecycle questions (managing-experiment-lifecycle), or the underlying feature flag is what's misbehaving rather than the results (use debugging-feature-flags).
- License
- MIT
- Instructions
- 269 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Agent Skills spec issues
- files: referenced but missing: references/interpretation.md, references/numbers-vs-sql.md, references/mid-run-changes.md, references/diagnostic-snapshot.md
Files (5)
- SKILL.md
- customer-reply.md · references/
- pulling-the-data.md · references/
- real-vs-noise.md · references/
- srm_check.py · scripts/
SKILL.md (first lines)
# Debugging experiments
PostHog Experiments are A/B tests: a feature flag randomizes users into variants, the SDK
records an **exposure** when the flag is read, and PostHog computes per-variant metrics and
significance. A customer looks at that results page and asks why it looks wrong.
**Most experiment-results tickets are config or exposure-collection problems, not statistics
bugs.** The randomization is fine; something upstream is skewing which users get exposed, or
stopping exposures from being recorded. The job is to find _which_, prove it with the
customer's own data, and hand back a plain-language explanation plus the fix.
This skill is the customer-support front door. It carries the two most common complaints
inline (uneven exposures, missing exposures) and loads
[`diagnosing-experiment-health`](../diagnosing-experiment-health/SKILL.md) as a diagnostic
library for the deeper long tail (interpretation traps, numbers-vs-SQL, mid-run surprises).
## Debugging workflow
1. **Parse the ticket.** Extract project ID, instance (US vs EU — the URLs and data live in
different places), experiment ID or name, the `lib`/platform if relevant, the exact
complaint in the customer's words, and what they already tried. Aged or multi-reply tickets
are dirty: the config may have been edited mid-thread, so re-pull current state and treat
earlier claims as stale.
2. **Resolve the experiment.** If the ticket names it rather than giving an ID, load
[`finding-experiments`](../finding-experiments/SKILL.md) to resolve it, then call
`posthog:experiment-get`.
3. **Pull the data read-only.** Run the fixed data-pull sequence in
[references/pulling-the-data.md](references/pulling-the-data.md). This produces the
"pertinent numbers" you will show the customer: per-variant exposed-person counts, `$multiple`
share, the `distinct_id`/`person` fragmentation ratio, the SRM chi-squared result, the
exposure trajectory, and the flag/experiment activity log. Verify from data before asking
the customer anything.
4. **Match the complaint** to the known-cause catalog below. Confirm the single leading cause
with one targeted number from step 3 before writing. Treat the customer's _own_ conclusion
("it's just noise", "a measurement bug") as a hypothesis to **disconfirm**, not confirm —
pull the data independently rather than re-deriving their answer. Quantify a suspected cause
before asserting its impact (count the contaminating cohort, don't eyeball it). One trap in
particular: never run the SRM chi-square against an _assumed_ even split — read the configured
`rollout_percentage` first, since an intended 34/33/33 reads as a ~2% SRM under an equal-split
assumption.
5. **Scope the fix to the experiment's state** before recommending it. On a **draft**, config
changes are free — recommend freely. On a **running** experiment every change has a mid-run
tradeoff (changing the split is an anti-pattern — prefer reset or end+restart; see
[`configuring-experiment-rollout`](../configuring-experiment-rollout/SKILL.md) and
[`managing-experiment-lifecycle`](../managing-experiment-lifecycle/SKILL.md)). On a
**stopped/shipped** experiment the flag and results are the documented outcome, so recommend
interpretation or a _next_ experiment, not a mid-run edit. Don't propose reversing a state change
unless the customer asks how to undo it.
6. **Write the reply** using [references/customer-reply.md](references/customer-reply.md):
cause → fix → the numbers that prove it, in the customer's UI language.
## Known-cause catalog — "exposures aren't even" / "one variant has no traffic"
Ordered by how often they're the answer. Full mechanism detail lives in
[`diagnosing-experiment-health/references/bias-and-skew.md`](../diagnosing-experiment-health/references/bias-and-skew.md)
(group A) — load it when a case needs more depth than the summary here.
**First, split a real SRM into its two possible homes.** Assignment is a deterministic hash of a
stable identifier (the `distinct_id` by default; the device ID or group key for those flag types —
see [references/pulling-the-data.md](references/pulling-the-data.md)), so with an unchanged split
every user has a _fixed_ variant and any set of users must fall close to the configured percentages.
A confirmed SRM (chi-squared p < 0.001 at healthy volume — not eyeballed) therefore lives in exactly
one of two places:
- **Assignment-side** — the recorded variant disagrees with what the hash would assign. Something
overrode assignment at serve time: a stale local-evaluation definition, an inherited bootstrap
value, a forced release-condition variant, or a mid-run rehash.
- **Capture-side** — the recorded variant _agrees_ with the hash (assignment is fine), but _which_
users get an exposure recorded is selected: one arm reaches a surface the other never does, or
one arm's users read the flag before it loaded and are silently dropped.
The decisive test that tells you which half you're in — recompute the assignment hash offline, then
split the observed gap into the part explained by _which users got recorded_ (selection ⇒
capture-side) and the part explained by _users recorded onto the wrong arm_ (reassignment ⇒
assignment-side) — is the
[decisive test in references/pulling-the-data.md](references/pulling-the-data.md#the-decisive-test-recompute-assignment-offline),
with a runnable [`srm_check.py`](scripts/srm_check.py). Run it before guessing. It names a side only
when one component both dominates the gap and is statistically distinguishable from zero; otherwise
it reports the split as mixed, or the test as inapplicable, and says why. Don't route on the raw
agreement percentage — scattered disagreements can't produce a _directional_ SRM, so a large
capture-side skew under a little override noise still reads as high agreement. The causes below are
tagged with the half they sit in.
- **Uneven split + "Exclude from analysis" (the bias banner).** This is the most common real
cause. When the variant split is uneven _and_ multiple-variant handling is set to **Exclude
from analysis** (the default) _and_ some users were exposed to more than one variant, the
excluded `$multiple` users are dropped asymmetrically — the smaller variant loses a larger
fraction of its users, so it looks artificially worse. PostHog raises the **"Setup likely
introduced bias"** banner once the `$multiple` share crosses 0.1%. Detect it purely from
`posthog:experiment-get` (split + `exposure_criteria.multiple_variant_handling`) and the
`$multiple` total from the exposure query. Fix: switch handling to **Use first seen
variant**, and/or move to an even split.
- **Sample ratio mismatch (SRM).** The observed split is statistically far from the configured
split. Confirm with the chi-squared test (p < 0.001) from
[references/pulling-the-data.md](references/pulling-the-data.md) — don't eyeball ratios; a 2:1 skew
at a few dozen exposures is normal noise. Count **people, not events** — run the test on the
per-person `total_exposures` from `posthog:experiment-results-get`, since raw
`$feature_flag_called` counts vary by how often each arm re-reads the flag and will manufacture an
SRM that isn't there. Once confirmed, use the decisive test above to pick the half, then work the
tagged causes below.
Bot traffic and identity fragmentation are weak
_directional_ causes — a crawler counts once per person, and fragmentation only inflates the
excluded `$multiple` bucket — so suspect either only when it correlates with one arm.
- **Capture-by-surface (capture-side).** One arm reaches a page or screen the other never does, so
it collects exposures the other structurally can't. Confirm: split the _first-exposure_ variant
by `$pathname` / `$screen_name` (query in [references/pulling-the-data.md](references/pulling-the-data.md)).
Some paths near 50% and others near 100% one variant ⇒ this is it; every path showing the same
skew ⇒ capture-by-surface is out and the bias is upstream.
- **Flag read before it loaded (capture-side).** A user who evaluates the flag before flags have
loaded (or who doesn't match a release condition) gets `false`/`undefined`, which the variant
allow-list silently drops — so those users vanish from their arm instead of showing up wrong. If
one arm is short by ~N persons, check whether the `false`/`null` person count (broken down by
`$lib`/surface) is near N and concentrated on the short arm. If so, flag-read timing is the lead
and the fix is in the customer's code.
- **Identity fragmentation.** The same person is split across multiple `distinct_id`s (usually
`identify()` called _after_ the flag is read, or anonymous→identified transitions), so they
appear in both arms and inflate the `$multiple` bucket (and, with an uneven split + Exclude,
feed the bias banner above). Signal: `distinct_id`/`person` ratio noticeably above 1 (use 1.2 as
a soft cue), or persons seen under more than one variant. On its own this does **not** create aFrom PostHog/skills, MIT.
Signals
- Stars
- 75
- Forks
- 8
- Open issues
- 2
- Last commit (this folder)
- Oct 7, 2026 (23 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/PostHog/skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
Same skill elsewhere
Copies of this SKILL.md published by others; search shows only one of them.
More from PostHog
- 0.759score
PostHog MCP Server
PostHogOfficial
Official PostHog MCP Server for product analytics, feature flags, experiments, and more.
ConnectorAFreshness: ARemote★ 40.4KClaude Code +3 - 0.754score
code-reviewer
PostHog
Subagent "code-reviewer" from PostHog/posthog: Use this agent when you need expert code review of recently written or modified code.
TemplateAFreshness: A★ 40.4KClaude Code - 0.683score
authoring-log-alerts
PostHogOfficial
Author useful, low-noise log alerts on services in a PostHog project.
SkillAFreshness: A★ 95Claude Code +9 - 0.683score
auditing-experiments-flags
PostHogOfficial
Audit PostHog experiments and feature flags for configuration issues, staleness, and best-practice violations.
SkillAFreshness: A★ 95Claude Code +9 - 0.683score
analyzing-offline-evaluations
PostHogOfficial
Inspect and compare offline AI evaluation experiments, diagnose case-level regressions, and follow scorer history across application, model, or prompt changes.
SkillAFreshness: A★ 95Claude Code +9 - 0.683score
authoring-error-tracking-alerts
PostHogOfficial
Author error tracking alerts that fire when an issue is created, reopened, or starts spiking.
SkillAFreshness: A★ 95Claude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get debugging-experiments running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
debugging-experiments skill. Agent Mart. https://agentmart.dev/skills/posthog-debugging-experiments-1de05b (last updated 2026-10-24)