[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-posthog-exploring-llm-costs":3,"mdc--50bc08-key":37,"related-org-posthog-exploring-llm-costs":1309,"related-repo-posthog-exploring-llm-costs":1478},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":32,"sourceUrl":35,"mdContent":36},"exploring-llm-costs","investigate LLM costs in PostHog","Investigate LLM spend in PostHog — total cost over time, cost by model, provider, user, trace, or custom dimension, token and cache-hit economics, and cost regressions. Use when the user asks \"how much are we spending on LLMs?\", \"which model \u002F user \u002F feature is most expensive?\", \"why did cost spike?\", wants to build a cost dashboard or alert, or pastes a trace URL and asks about its cost.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"posthog","PostHog","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fposthog.png",[12,16,17,20,23],{"name":13,"slug":14,"type":15},"Observability","observability","tag",{"name":9,"slug":8,"type":15},{"name":18,"slug":19,"type":15},"LLM","llm",{"name":21,"slug":22,"type":15},"Cost Optimization","cost-optimization",{"name":24,"slug":25,"type":15},"Analytics","analytics",56,"https:\u002F\u002Fgithub.com\u002FPostHog\u002Fskills","2026-04-29T05:48:49.875484",null,4,[],{"repoUrl":27,"stars":26,"forks":30,"topics":33,"description":34},[],"PostHog skills (under construction)","https:\u002F\u002Fgithub.com\u002FPostHog\u002Fskills\u002Ftree\u002FHEAD\u002Fskills\u002Fomnibus\u002Fexploring-llm-costs","---\nname: exploring-llm-costs\ndescription: >\n  Investigate LLM spend in PostHog — total cost over time, cost by model,\n  provider, user, trace, or custom dimension, token and cache-hit economics,\n  and cost regressions. Use when the user asks \"how much are we spending on\n  LLMs?\", \"which model \u002F user \u002F feature is most expensive?\", \"why did cost\n  spike?\", wants to build a cost dashboard or alert, or pastes a trace URL\n  and asks about its cost.\n---\n\n# Exploring LLM costs\n\nPostHog attaches per-call cost metadata to every `$ai_generation` and `$ai_embedding`\nevent at ingestion time. Every cost question reduces to an aggregation over those\ntwo event types — the interesting variation is only in how you group, filter, and\ncompare.\n\nThis skill covers the common cost investigations: total spend, breakdowns\n(model, provider, user, trace, custom property), token and cache-hit analysis,\nregression debugging, and materializing results as insights, dashboards, or alerts.\n\n## Tools\n\n| Tool                            | Purpose                                                             |\n| ------------------------------- | ------------------------------------------------------------------- |\n| `posthog:execute-sql`           | Ad-hoc HogQL for any cost aggregation — the workhorse of this skill |\n| `posthog:query-llm-traces-list` | List traces with rolled-up cost, token, and error metrics           |\n| `posthog:query-llm-trace`       | Cost breakdown of a single trace across all its events              |\n| `posthog:read-data-schema`      | Discover which custom properties exist for breakdowns               |\n| `posthog:insight-create`        | Materialize a cost chart as a saved insight                         |\n| `posthog:dashboard-create`      | Bundle cost insights into a dashboard                               |\n| `posthog:alert-create`          | Alert when cost crosses a threshold                                 |\n\n## Core rules\n\nThree rules cover most of what goes wrong:\n\n- **Sum `$ai_total_cost_usd` for rollups, never the components.** Components drop\n  request and web-search fees. The UI's cost cells sum `$ai_total_cost_usd`\n  over `event IN ('$ai_generation', '$ai_embedding')`; mirror that. Full\n  schema and rationale in [cost properties](.\u002Freferences\u002Fcost-properties.md).\n- **Always include both `$ai_generation` and `$ai_embedding`** in cost queries\n  unless the project demonstrably does not use embeddings — missing them silently\n  under-counts. `$ai_trace` and `$ai_span` carry no rollup cost; some SDK\n  wrappers duplicate `$ai_total_cost_usd` onto `$ai_trace` so don't include\n  it in rollups or you'll double-count.\n- **Always set a time range.** Cost queries without one scan the full events table.\n\n`$ai_total_cost_usd` is set at ingestion via one of three paths (passthrough,\ncustom pricing, automatic lookup). When a cost looks wrong, read\n`$ai_cost_model_source` first — see [cost sources](.\u002Freferences\u002Fcost-sources.md)\nfor the precedence rules and a diagnostic query.\n\nCache-hit math depends on whether the provider reports cache tokens inclusively\nor exclusively of `$ai_input_tokens`. Always branch on the per-event\n`$ai_cache_reporting_exclusive` flag, never on provider name — see\n[cache accounting](.\u002Freferences\u002Fcache-accounting.md) for the exclusive-vs-inclusive\nformula.\n\n`distinct_id` is the canonical user dimension. Customers often attach custom\nproperties (`feature`, `tenant_id`, `workflow_name`) — discover them with\n`posthog:read-data-schema` before grouping. Don't guess names.\n\n## Workflow: total spend in a window\n\n```sql\nposthog:execute-sql\nSELECT round(sum(toFloat(properties.$ai_total_cost_usd)), 4) AS total_cost_usd\nFROM events\nWHERE event IN ('$ai_generation', '$ai_embedding')\n    AND timestamp >= now() - INTERVAL 30 DAY\n```\n\n## Workflow: cost breakdowns\n\nEvery cost question is a variation of the same template — group by a dimension,\naggregate `$ai_total_cost_usd`. See [breakdown patterns](.\u002Freferences\u002Fbreakdown-patterns.md)\nfor ready-to-run recipes:\n\n- Cost over time (daily)\n- Cost by model\n- Cost by user (top spenders)\n- Cost by trace (top expensive traces)\n- Cost by custom dimension\n- Cost-per-call distribution\n- Input vs output vs cache economics\n\n## Workflow: inspect a single trace's cost\n\nWhen the user pastes a trace URL and asks about its cost, fetch the trace and\nsurface the per-event breakdown:\n\n```json\nposthog:query-llm-trace\n{ \"traceId\": \"\u003Ctrace_id>\", \"dateRange\": {\"date_from\": \"-30d\"} }\n```\n\nSum `$ai_total_cost_usd` across the returned events, grouped by span name or\nmodel, to show which step(s) drove the cost. The trace response already\nincludes `totalCost` as a convenience.\n\n## Workflow: debug a cost regression\n\n\"Our LLM bill jumped — why?\" is almost always one of: more calls, bigger\nprompts, a new model, or a change in cache-hit rate. Work through them in\norder — see [regression debugging](.\u002Freferences\u002Fregression-debugging.md) for\nthe 5-step playbook.\n\n## Workflow: materialize as an insight, dashboard, or alert\n\nAfter ad-hoc queries answer the question, persist them as insights, bundle\ninto a dashboard, or wire up alerts. See [materializing](.\u002Freferences\u002Fmaterializing.md)\nfor ready-to-run JSON for `posthog:insight-create`, `posthog:dashboard-create`,\nand `posthog:alert-create`.\n\n## Constructing UI links\n\n- **Dashboard**: `https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Fdashboard`\n- **Traces list** (sort by cost): `https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Ftraces`\n- **Generations list**: `https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Fgenerations`\n- **Users list** (per-user cost): `https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Fusers`\n- **Single trace**: `https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Ftraces\u002F\u003Ctrace_id>?timestamp=\u003Curl_encoded_iso>`\n\nAlways surface a UI link so the user can verify visually.\n\n## Keeping this skill current\n\nProvider reporting behavior (which tokens are inclusive vs exclusive,\nwhich costs show up where) shifts over time and can differ between SDK\nversions for the same provider. To avoid rot:\n\n- Branch on event-level flags (`$ai_cache_reporting_exclusive`,\n  `$ai_cost_model_source`) rather than hardcoded provider or model names.\n  Those flags are ingestion's resolved answer for the specific event and\n  are the right source of truth.\n- `$ai_total_cost_usd` is always authoritative for rollups — prefer it\n  over summing components, which can drift as new cost categories are\n  added.\n- For anything not covered here (new cost categories, changes to\n  pricing lookup, provider additions), run `posthog:docs-search` for\n  \"calculating costs\" or \"AI observability\" first rather than trusting a\n  hardcoded rule in this file.\n- If you find this skill contradicting the UI, trust the UI and flag\n  the skill for an update.\n\n## Tips\n\n- Always set a time range — cost queries without one scan the full events table\n- Token, cost, model, and `$ai_trace_id` properties are on `events` — but message _content_ (`$ai_input` \u002F `$ai_output_choices`) lives only on the `posthog.ai_events` table; see the traces skill's [event reference](..\u002Fexploring-llm-traces\u002Freferences\u002Fevents-and-properties.md) if you need content alongside cost\n- Always include `$ai_embedding` alongside `$ai_generation` when summing cost; embeddings are cheap per-call but add up at scale\n- Costs are written at ingestion (see [Calculating LLM costs](https:\u002F\u002Fposthog.com\u002Fdocs\u002Fai-observability\u002Fcalculating-costs)) — if `$ai_total_cost_usd` is missing or zero, read `$ai_cost_model_source` first: `passthrough` means the SDK supplied costs; `custom` means custom token prices; `openrouter` \u002F `manual` mean automatic lookup; missing means the model wasn't matched (unusual custom model, fine-tune). Grep: `countIf(properties.$ai_total_cost_usd IS NULL)` per `(model, source)`\n- Custom pricing uses **per-token** prices, not per-million — if a custom-priced model looks ~1M× too expensive or too cheap, that's almost always the bug\n- Exclude errored calls from cost totals only when explicitly asked — providers still charge for many error modes, and including them gives the truthful bill\n- For per-user totals, exclude rows where `distinct_id = properties.$ai_trace_id` — some SDKs default distinct_id to the trace ID when no user is set\n- Cost is additive across `$ai_generation` + `$ai_embedding` events within a trace; summing on `$ai_span` gives zero. `$ai_trace` may carry `$ai_total_cost_usd` from some SDK wrappers — don't include it in rollups or you'll double-count. `$ai_evaluation` events also carry cost but are not part of the stock UI rollups; include them only when the user explicitly wants evaluation spend in the total\n- Cache-hit rate depends on `$ai_cache_reporting_exclusive` — branch on the event-level flag rather than on provider or model name. Provider behavior and SDK versions drift; the flag is ingestion's resolved answer for that specific event\n- When answering \"why is X expensive?\", show the cost **and** the token split — the user almost always wants to know whether to shrink prompts, shrink outputs, or switch models\n- Before building a custom dashboard, check whether the stock `\u002Fai-observability\u002Fdashboard` tiles already answer the question — re-creating them is churn\n- For large tenants, materialize common cost queries as insights and reuse via `insight-query`; ad-hoc SQL is fine for one-offs but re-running it on every dashboard load is expensive\n\n## References\n\n- [cost properties](.\u002Freferences\u002Fcost-properties.md) — full property schema, total-cost rationale, event-set rules\n- [cost sources](.\u002Freferences\u002Fcost-sources.md) — how costs get set at ingestion plus a diagnostic query\n- [cache accounting](.\u002Freferences\u002Fcache-accounting.md) — exclusive vs inclusive providers, cache-hit-rate formula\n- [breakdown patterns](.\u002Freferences\u002Fbreakdown-patterns.md) — SQL recipes for every common breakdown\n- [regression debugging](.\u002Freferences\u002Fregression-debugging.md) — 5-step playbook for cost spikes\n- [materializing](.\u002Freferences\u002Fmaterializing.md) — insight, dashboard, and alert JSON\n",{"data":38,"body":39},{"name":4,"description":6},{"type":40,"children":41},"root",[42,50,73,78,85,232,238,243,351,377,406,447,453,510,516,536,574,580,585,715,734,740,753,759,791,797,878,883,889,894,944,950,1240,1246,1303],{"type":43,"tag":44,"props":45,"children":46},"element","h1",{"id":4},[47],{"type":48,"value":49},"text","Exploring LLM costs",{"type":43,"tag":51,"props":52,"children":53},"p",{},[54,56,63,65,71],{"type":48,"value":55},"PostHog attaches per-call cost metadata to every ",{"type":43,"tag":57,"props":58,"children":60},"code",{"className":59},[],[61],{"type":48,"value":62},"$ai_generation",{"type":48,"value":64}," and ",{"type":43,"tag":57,"props":66,"children":68},{"className":67},[],[69],{"type":48,"value":70},"$ai_embedding",{"type":48,"value":72},"\nevent at ingestion time. Every cost question reduces to an aggregation over those\ntwo event types — the interesting variation is only in how you group, filter, and\ncompare.",{"type":43,"tag":51,"props":74,"children":75},{},[76],{"type":48,"value":77},"This skill covers the common cost investigations: total spend, breakdowns\n(model, provider, user, trace, custom property), token and cache-hit analysis,\nregression debugging, and materializing results as insights, dashboards, or alerts.",{"type":43,"tag":79,"props":80,"children":82},"h2",{"id":81},"tools",[83],{"type":48,"value":84},"Tools",{"type":43,"tag":86,"props":87,"children":88},"table",{},[89,108],{"type":43,"tag":90,"props":91,"children":92},"thead",{},[93],{"type":43,"tag":94,"props":95,"children":96},"tr",{},[97,103],{"type":43,"tag":98,"props":99,"children":100},"th",{},[101],{"type":48,"value":102},"Tool",{"type":43,"tag":98,"props":104,"children":105},{},[106],{"type":48,"value":107},"Purpose",{"type":43,"tag":109,"props":110,"children":111},"tbody",{},[112,130,147,164,181,198,215],{"type":43,"tag":94,"props":113,"children":114},{},[115,125],{"type":43,"tag":116,"props":117,"children":118},"td",{},[119],{"type":43,"tag":57,"props":120,"children":122},{"className":121},[],[123],{"type":48,"value":124},"posthog:execute-sql",{"type":43,"tag":116,"props":126,"children":127},{},[128],{"type":48,"value":129},"Ad-hoc HogQL for any cost aggregation — the workhorse of this skill",{"type":43,"tag":94,"props":131,"children":132},{},[133,142],{"type":43,"tag":116,"props":134,"children":135},{},[136],{"type":43,"tag":57,"props":137,"children":139},{"className":138},[],[140],{"type":48,"value":141},"posthog:query-llm-traces-list",{"type":43,"tag":116,"props":143,"children":144},{},[145],{"type":48,"value":146},"List traces with rolled-up cost, token, and error metrics",{"type":43,"tag":94,"props":148,"children":149},{},[150,159],{"type":43,"tag":116,"props":151,"children":152},{},[153],{"type":43,"tag":57,"props":154,"children":156},{"className":155},[],[157],{"type":48,"value":158},"posthog:query-llm-trace",{"type":43,"tag":116,"props":160,"children":161},{},[162],{"type":48,"value":163},"Cost breakdown of a single trace across all its events",{"type":43,"tag":94,"props":165,"children":166},{},[167,176],{"type":43,"tag":116,"props":168,"children":169},{},[170],{"type":43,"tag":57,"props":171,"children":173},{"className":172},[],[174],{"type":48,"value":175},"posthog:read-data-schema",{"type":43,"tag":116,"props":177,"children":178},{},[179],{"type":48,"value":180},"Discover which custom properties exist for breakdowns",{"type":43,"tag":94,"props":182,"children":183},{},[184,193],{"type":43,"tag":116,"props":185,"children":186},{},[187],{"type":43,"tag":57,"props":188,"children":190},{"className":189},[],[191],{"type":48,"value":192},"posthog:insight-create",{"type":43,"tag":116,"props":194,"children":195},{},[196],{"type":48,"value":197},"Materialize a cost chart as a saved insight",{"type":43,"tag":94,"props":199,"children":200},{},[201,210],{"type":43,"tag":116,"props":202,"children":203},{},[204],{"type":43,"tag":57,"props":205,"children":207},{"className":206},[],[208],{"type":48,"value":209},"posthog:dashboard-create",{"type":43,"tag":116,"props":211,"children":212},{},[213],{"type":48,"value":214},"Bundle cost insights into a dashboard",{"type":43,"tag":94,"props":216,"children":217},{},[218,227],{"type":43,"tag":116,"props":219,"children":220},{},[221],{"type":43,"tag":57,"props":222,"children":224},{"className":223},[],[225],{"type":48,"value":226},"posthog:alert-create",{"type":43,"tag":116,"props":228,"children":229},{},[230],{"type":48,"value":231},"Alert when cost crosses a threshold",{"type":43,"tag":79,"props":233,"children":235},{"id":234},"core-rules",[236],{"type":48,"value":237},"Core rules",{"type":43,"tag":51,"props":239,"children":240},{},[241],{"type":48,"value":242},"Three rules cover most of what goes wrong:",{"type":43,"tag":244,"props":245,"children":246},"ul",{},[247,291,341],{"type":43,"tag":248,"props":249,"children":250},"li",{},[251,265,267,272,274,280,282,289],{"type":43,"tag":252,"props":253,"children":254},"strong",{},[255,257,263],{"type":48,"value":256},"Sum ",{"type":43,"tag":57,"props":258,"children":260},{"className":259},[],[261],{"type":48,"value":262},"$ai_total_cost_usd",{"type":48,"value":264}," for rollups, never the components.",{"type":48,"value":266}," Components drop\nrequest and web-search fees. The UI's cost cells sum ",{"type":43,"tag":57,"props":268,"children":270},{"className":269},[],[271],{"type":48,"value":262},{"type":48,"value":273},"\nover ",{"type":43,"tag":57,"props":275,"children":277},{"className":276},[],[278],{"type":48,"value":279},"event IN ('$ai_generation', '$ai_embedding')",{"type":48,"value":281},"; mirror that. Full\nschema and rationale in ",{"type":43,"tag":283,"props":284,"children":286},"a",{"href":285},".\u002Freferences\u002Fcost-properties.md",[287],{"type":48,"value":288},"cost properties",{"type":48,"value":290},".",{"type":43,"tag":248,"props":292,"children":293},{},[294,310,312,318,319,325,327,332,334,339],{"type":43,"tag":252,"props":295,"children":296},{},[297,299,304,305],{"type":48,"value":298},"Always include both ",{"type":43,"tag":57,"props":300,"children":302},{"className":301},[],[303],{"type":48,"value":62},{"type":48,"value":64},{"type":43,"tag":57,"props":306,"children":308},{"className":307},[],[309],{"type":48,"value":70},{"type":48,"value":311}," in cost queries\nunless the project demonstrably does not use embeddings — missing them silently\nunder-counts. ",{"type":43,"tag":57,"props":313,"children":315},{"className":314},[],[316],{"type":48,"value":317},"$ai_trace",{"type":48,"value":64},{"type":43,"tag":57,"props":320,"children":322},{"className":321},[],[323],{"type":48,"value":324},"$ai_span",{"type":48,"value":326}," carry no rollup cost; some SDK\nwrappers duplicate ",{"type":43,"tag":57,"props":328,"children":330},{"className":329},[],[331],{"type":48,"value":262},{"type":48,"value":333}," onto ",{"type":43,"tag":57,"props":335,"children":337},{"className":336},[],[338],{"type":48,"value":317},{"type":48,"value":340}," so don't include\nit in rollups or you'll double-count.",{"type":43,"tag":248,"props":342,"children":343},{},[344,349],{"type":43,"tag":252,"props":345,"children":346},{},[347],{"type":48,"value":348},"Always set a time range.",{"type":48,"value":350}," Cost queries without one scan the full events table.",{"type":43,"tag":51,"props":352,"children":353},{},[354,359,361,367,369,375],{"type":43,"tag":57,"props":355,"children":357},{"className":356},[],[358],{"type":48,"value":262},{"type":48,"value":360}," is set at ingestion via one of three paths (passthrough,\ncustom pricing, automatic lookup). When a cost looks wrong, read\n",{"type":43,"tag":57,"props":362,"children":364},{"className":363},[],[365],{"type":48,"value":366},"$ai_cost_model_source",{"type":48,"value":368}," first — see ",{"type":43,"tag":283,"props":370,"children":372},{"href":371},".\u002Freferences\u002Fcost-sources.md",[373],{"type":48,"value":374},"cost sources",{"type":48,"value":376},"\nfor the precedence rules and a diagnostic query.",{"type":43,"tag":51,"props":378,"children":379},{},[380,382,388,390,396,398,404],{"type":48,"value":381},"Cache-hit math depends on whether the provider reports cache tokens inclusively\nor exclusively of ",{"type":43,"tag":57,"props":383,"children":385},{"className":384},[],[386],{"type":48,"value":387},"$ai_input_tokens",{"type":48,"value":389},". Always branch on the per-event\n",{"type":43,"tag":57,"props":391,"children":393},{"className":392},[],[394],{"type":48,"value":395},"$ai_cache_reporting_exclusive",{"type":48,"value":397}," flag, never on provider name — see\n",{"type":43,"tag":283,"props":399,"children":401},{"href":400},".\u002Freferences\u002Fcache-accounting.md",[402],{"type":48,"value":403},"cache accounting",{"type":48,"value":405}," for the exclusive-vs-inclusive\nformula.",{"type":43,"tag":51,"props":407,"children":408},{},[409,415,417,423,425,431,432,438,440,445],{"type":43,"tag":57,"props":410,"children":412},{"className":411},[],[413],{"type":48,"value":414},"distinct_id",{"type":48,"value":416}," is the canonical user dimension. Customers often attach custom\nproperties (",{"type":43,"tag":57,"props":418,"children":420},{"className":419},[],[421],{"type":48,"value":422},"feature",{"type":48,"value":424},", ",{"type":43,"tag":57,"props":426,"children":428},{"className":427},[],[429],{"type":48,"value":430},"tenant_id",{"type":48,"value":424},{"type":43,"tag":57,"props":433,"children":435},{"className":434},[],[436],{"type":48,"value":437},"workflow_name",{"type":48,"value":439},") — discover them with\n",{"type":43,"tag":57,"props":441,"children":443},{"className":442},[],[444],{"type":48,"value":175},{"type":48,"value":446}," before grouping. Don't guess names.",{"type":43,"tag":79,"props":448,"children":450},{"id":449},"workflow-total-spend-in-a-window",[451],{"type":48,"value":452},"Workflow: total spend in a window",{"type":43,"tag":454,"props":455,"children":460},"pre",{"className":456,"code":457,"language":458,"meta":459,"style":459},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","posthog:execute-sql\nSELECT round(sum(toFloat(properties.$ai_total_cost_usd)), 4) AS total_cost_usd\nFROM events\nWHERE event IN ('$ai_generation', '$ai_embedding')\n    AND timestamp >= now() - INTERVAL 30 DAY\n","sql","",[461],{"type":43,"tag":57,"props":462,"children":463},{"__ignoreMap":459},[464,475,484,493,501],{"type":43,"tag":465,"props":466,"children":469},"span",{"class":467,"line":468},"line",1,[470],{"type":43,"tag":465,"props":471,"children":472},{},[473],{"type":48,"value":474},"posthog:execute-sql\n",{"type":43,"tag":465,"props":476,"children":478},{"class":467,"line":477},2,[479],{"type":43,"tag":465,"props":480,"children":481},{},[482],{"type":48,"value":483},"SELECT round(sum(toFloat(properties.$ai_total_cost_usd)), 4) AS total_cost_usd\n",{"type":43,"tag":465,"props":485,"children":487},{"class":467,"line":486},3,[488],{"type":43,"tag":465,"props":489,"children":490},{},[491],{"type":48,"value":492},"FROM events\n",{"type":43,"tag":465,"props":494,"children":495},{"class":467,"line":30},[496],{"type":43,"tag":465,"props":497,"children":498},{},[499],{"type":48,"value":500},"WHERE event IN ('$ai_generation', '$ai_embedding')\n",{"type":43,"tag":465,"props":502,"children":504},{"class":467,"line":503},5,[505],{"type":43,"tag":465,"props":506,"children":507},{},[508],{"type":48,"value":509},"    AND timestamp >= now() - INTERVAL 30 DAY\n",{"type":43,"tag":79,"props":511,"children":513},{"id":512},"workflow-cost-breakdowns",[514],{"type":48,"value":515},"Workflow: cost breakdowns",{"type":43,"tag":51,"props":517,"children":518},{},[519,521,526,528,534],{"type":48,"value":520},"Every cost question is a variation of the same template — group by a dimension,\naggregate ",{"type":43,"tag":57,"props":522,"children":524},{"className":523},[],[525],{"type":48,"value":262},{"type":48,"value":527},". See ",{"type":43,"tag":283,"props":529,"children":531},{"href":530},".\u002Freferences\u002Fbreakdown-patterns.md",[532],{"type":48,"value":533},"breakdown patterns",{"type":48,"value":535},"\nfor ready-to-run recipes:",{"type":43,"tag":244,"props":537,"children":538},{},[539,544,549,554,559,564,569],{"type":43,"tag":248,"props":540,"children":541},{},[542],{"type":48,"value":543},"Cost over time (daily)",{"type":43,"tag":248,"props":545,"children":546},{},[547],{"type":48,"value":548},"Cost by model",{"type":43,"tag":248,"props":550,"children":551},{},[552],{"type":48,"value":553},"Cost by user (top spenders)",{"type":43,"tag":248,"props":555,"children":556},{},[557],{"type":48,"value":558},"Cost by trace (top expensive traces)",{"type":43,"tag":248,"props":560,"children":561},{},[562],{"type":48,"value":563},"Cost by custom dimension",{"type":43,"tag":248,"props":565,"children":566},{},[567],{"type":48,"value":568},"Cost-per-call distribution",{"type":43,"tag":248,"props":570,"children":571},{},[572],{"type":48,"value":573},"Input vs output vs cache economics",{"type":43,"tag":79,"props":575,"children":577},{"id":576},"workflow-inspect-a-single-traces-cost",[578],{"type":48,"value":579},"Workflow: inspect a single trace's cost",{"type":43,"tag":51,"props":581,"children":582},{},[583],{"type":48,"value":584},"When the user pastes a trace URL and asks about its cost, fetch the trace and\nsurface the per-event breakdown:",{"type":43,"tag":454,"props":586,"children":590},{"className":587,"code":588,"language":589,"meta":459,"style":459},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","posthog:query-llm-trace\n{ \"traceId\": \"\u003Ctrace_id>\", \"dateRange\": {\"date_from\": \"-30d\"} }\n","json",[591],{"type":43,"tag":57,"props":592,"children":593},{"__ignoreMap":459},[594,603],{"type":43,"tag":465,"props":595,"children":596},{"class":467,"line":468},[597],{"type":43,"tag":465,"props":598,"children":600},{"style":599},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[601],{"type":48,"value":602},"posthog:query-llm-trace\n",{"type":43,"tag":465,"props":604,"children":605},{"class":467,"line":477},[606,612,617,623,628,633,637,643,647,652,656,661,665,669,674,678,684,688,692,696,701,705,710],{"type":43,"tag":465,"props":607,"children":609},{"style":608},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[610],{"type":48,"value":611},"{",{"type":43,"tag":465,"props":613,"children":614},{"style":608},[615],{"type":48,"value":616}," \"",{"type":43,"tag":465,"props":618,"children":620},{"style":619},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[621],{"type":48,"value":622},"traceId",{"type":43,"tag":465,"props":624,"children":625},{"style":608},[626],{"type":48,"value":627},"\"",{"type":43,"tag":465,"props":629,"children":630},{"style":608},[631],{"type":48,"value":632},":",{"type":43,"tag":465,"props":634,"children":635},{"style":608},[636],{"type":48,"value":616},{"type":43,"tag":465,"props":638,"children":640},{"style":639},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[641],{"type":48,"value":642},"\u003Ctrace_id>",{"type":43,"tag":465,"props":644,"children":645},{"style":608},[646],{"type":48,"value":627},{"type":43,"tag":465,"props":648,"children":649},{"style":608},[650],{"type":48,"value":651},",",{"type":43,"tag":465,"props":653,"children":654},{"style":608},[655],{"type":48,"value":616},{"type":43,"tag":465,"props":657,"children":658},{"style":619},[659],{"type":48,"value":660},"dateRange",{"type":43,"tag":465,"props":662,"children":663},{"style":608},[664],{"type":48,"value":627},{"type":43,"tag":465,"props":666,"children":667},{"style":608},[668],{"type":48,"value":632},{"type":43,"tag":465,"props":670,"children":671},{"style":608},[672],{"type":48,"value":673}," {",{"type":43,"tag":465,"props":675,"children":676},{"style":608},[677],{"type":48,"value":627},{"type":43,"tag":465,"props":679,"children":681},{"style":680},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[682],{"type":48,"value":683},"date_from",{"type":43,"tag":465,"props":685,"children":686},{"style":608},[687],{"type":48,"value":627},{"type":43,"tag":465,"props":689,"children":690},{"style":608},[691],{"type":48,"value":632},{"type":43,"tag":465,"props":693,"children":694},{"style":608},[695],{"type":48,"value":616},{"type":43,"tag":465,"props":697,"children":698},{"style":639},[699],{"type":48,"value":700},"-30d",{"type":43,"tag":465,"props":702,"children":703},{"style":608},[704],{"type":48,"value":627},{"type":43,"tag":465,"props":706,"children":707},{"style":608},[708],{"type":48,"value":709},"}",{"type":43,"tag":465,"props":711,"children":712},{"style":608},[713],{"type":48,"value":714}," }\n",{"type":43,"tag":51,"props":716,"children":717},{},[718,719,724,726,732],{"type":48,"value":256},{"type":43,"tag":57,"props":720,"children":722},{"className":721},[],[723],{"type":48,"value":262},{"type":48,"value":725}," across the returned events, grouped by span name or\nmodel, to show which step(s) drove the cost. The trace response already\nincludes ",{"type":43,"tag":57,"props":727,"children":729},{"className":728},[],[730],{"type":48,"value":731},"totalCost",{"type":48,"value":733}," as a convenience.",{"type":43,"tag":79,"props":735,"children":737},{"id":736},"workflow-debug-a-cost-regression",[738],{"type":48,"value":739},"Workflow: debug a cost regression",{"type":43,"tag":51,"props":741,"children":742},{},[743,745,751],{"type":48,"value":744},"\"Our LLM bill jumped — why?\" is almost always one of: more calls, bigger\nprompts, a new model, or a change in cache-hit rate. Work through them in\norder — see ",{"type":43,"tag":283,"props":746,"children":748},{"href":747},".\u002Freferences\u002Fregression-debugging.md",[749],{"type":48,"value":750},"regression debugging",{"type":48,"value":752}," for\nthe 5-step playbook.",{"type":43,"tag":79,"props":754,"children":756},{"id":755},"workflow-materialize-as-an-insight-dashboard-or-alert",[757],{"type":48,"value":758},"Workflow: materialize as an insight, dashboard, or alert",{"type":43,"tag":51,"props":760,"children":761},{},[762,764,770,772,777,778,783,785,790],{"type":48,"value":763},"After ad-hoc queries answer the question, persist them as insights, bundle\ninto a dashboard, or wire up alerts. See ",{"type":43,"tag":283,"props":765,"children":767},{"href":766},".\u002Freferences\u002Fmaterializing.md",[768],{"type":48,"value":769},"materializing",{"type":48,"value":771},"\nfor ready-to-run JSON for ",{"type":43,"tag":57,"props":773,"children":775},{"className":774},[],[776],{"type":48,"value":192},{"type":48,"value":424},{"type":43,"tag":57,"props":779,"children":781},{"className":780},[],[782],{"type":48,"value":209},{"type":48,"value":784},",\nand ",{"type":43,"tag":57,"props":786,"children":788},{"className":787},[],[789],{"type":48,"value":226},{"type":48,"value":290},{"type":43,"tag":79,"props":792,"children":794},{"id":793},"constructing-ui-links",[795],{"type":48,"value":796},"Constructing UI links",{"type":43,"tag":244,"props":798,"children":799},{},[800,816,832,847,863],{"type":43,"tag":248,"props":801,"children":802},{},[803,808,810],{"type":43,"tag":252,"props":804,"children":805},{},[806],{"type":48,"value":807},"Dashboard",{"type":48,"value":809},": ",{"type":43,"tag":57,"props":811,"children":813},{"className":812},[],[814],{"type":48,"value":815},"https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Fdashboard",{"type":43,"tag":248,"props":817,"children":818},{},[819,824,826],{"type":43,"tag":252,"props":820,"children":821},{},[822],{"type":48,"value":823},"Traces list",{"type":48,"value":825}," (sort by cost): ",{"type":43,"tag":57,"props":827,"children":829},{"className":828},[],[830],{"type":48,"value":831},"https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Ftraces",{"type":43,"tag":248,"props":833,"children":834},{},[835,840,841],{"type":43,"tag":252,"props":836,"children":837},{},[838],{"type":48,"value":839},"Generations list",{"type":48,"value":809},{"type":43,"tag":57,"props":842,"children":844},{"className":843},[],[845],{"type":48,"value":846},"https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Fgenerations",{"type":43,"tag":248,"props":848,"children":849},{},[850,855,857],{"type":43,"tag":252,"props":851,"children":852},{},[853],{"type":48,"value":854},"Users list",{"type":48,"value":856}," (per-user cost): ",{"type":43,"tag":57,"props":858,"children":860},{"className":859},[],[861],{"type":48,"value":862},"https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Fusers",{"type":43,"tag":248,"props":864,"children":865},{},[866,871,872],{"type":43,"tag":252,"props":867,"children":868},{},[869],{"type":48,"value":870},"Single trace",{"type":48,"value":809},{"type":43,"tag":57,"props":873,"children":875},{"className":874},[],[876],{"type":48,"value":877},"https:\u002F\u002Fapp.posthog.com\u002Fai-observability\u002Ftraces\u002F\u003Ctrace_id>?timestamp=\u003Curl_encoded_iso>",{"type":43,"tag":51,"props":879,"children":880},{},[881],{"type":48,"value":882},"Always surface a UI link so the user can verify visually.",{"type":43,"tag":79,"props":884,"children":886},{"id":885},"keeping-this-skill-current",[887],{"type":48,"value":888},"Keeping this skill current",{"type":43,"tag":51,"props":890,"children":891},{},[892],{"type":48,"value":893},"Provider reporting behavior (which tokens are inclusive vs exclusive,\nwhich costs show up where) shifts over time and can differ between SDK\nversions for the same provider. To avoid rot:",{"type":43,"tag":244,"props":895,"children":896},{},[897,916,926,939],{"type":43,"tag":248,"props":898,"children":899},{},[900,902,907,909,914],{"type":48,"value":901},"Branch on event-level flags (",{"type":43,"tag":57,"props":903,"children":905},{"className":904},[],[906],{"type":48,"value":395},{"type":48,"value":908},",\n",{"type":43,"tag":57,"props":910,"children":912},{"className":911},[],[913],{"type":48,"value":366},{"type":48,"value":915},") rather than hardcoded provider or model names.\nThose flags are ingestion's resolved answer for the specific event and\nare the right source of truth.",{"type":43,"tag":248,"props":917,"children":918},{},[919,924],{"type":43,"tag":57,"props":920,"children":922},{"className":921},[],[923],{"type":48,"value":262},{"type":48,"value":925}," is always authoritative for rollups — prefer it\nover summing components, which can drift as new cost categories are\nadded.",{"type":43,"tag":248,"props":927,"children":928},{},[929,931,937],{"type":48,"value":930},"For anything not covered here (new cost categories, changes to\npricing lookup, provider additions), run ",{"type":43,"tag":57,"props":932,"children":934},{"className":933},[],[935],{"type":48,"value":936},"posthog:docs-search",{"type":48,"value":938}," for\n\"calculating costs\" or \"AI observability\" first rather than trusting a\nhardcoded rule in this file.",{"type":43,"tag":248,"props":940,"children":941},{},[942],{"type":48,"value":943},"If you find this skill contradicting the UI, trust the UI and flag\nthe skill for an update.",{"type":43,"tag":79,"props":945,"children":947},{"id":946},"tips",[948],{"type":48,"value":949},"Tips",{"type":43,"tag":244,"props":951,"children":952},{},[953,958,1019,1038,1112,1124,1129,1142,1190,1202,1214,1227],{"type":43,"tag":248,"props":954,"children":955},{},[956],{"type":48,"value":957},"Always set a time range — cost queries without one scan the full events table",{"type":43,"tag":248,"props":959,"children":960},{},[961,963,969,971,977,979,985,987,993,995,1001,1003,1009,1011,1017],{"type":48,"value":962},"Token, cost, model, and ",{"type":43,"tag":57,"props":964,"children":966},{"className":965},[],[967],{"type":48,"value":968},"$ai_trace_id",{"type":48,"value":970}," properties are on ",{"type":43,"tag":57,"props":972,"children":974},{"className":973},[],[975],{"type":48,"value":976},"events",{"type":48,"value":978}," — but message ",{"type":43,"tag":980,"props":981,"children":982},"em",{},[983],{"type":48,"value":984},"content",{"type":48,"value":986}," (",{"type":43,"tag":57,"props":988,"children":990},{"className":989},[],[991],{"type":48,"value":992},"$ai_input",{"type":48,"value":994}," \u002F ",{"type":43,"tag":57,"props":996,"children":998},{"className":997},[],[999],{"type":48,"value":1000},"$ai_output_choices",{"type":48,"value":1002},") lives only on the ",{"type":43,"tag":57,"props":1004,"children":1006},{"className":1005},[],[1007],{"type":48,"value":1008},"posthog.ai_events",{"type":48,"value":1010}," table; see the traces skill's ",{"type":43,"tag":283,"props":1012,"children":1014},{"href":1013},"..\u002Fexploring-llm-traces\u002Freferences\u002Fevents-and-properties.md",[1015],{"type":48,"value":1016},"event reference",{"type":48,"value":1018}," if you need content alongside cost",{"type":43,"tag":248,"props":1020,"children":1021},{},[1022,1024,1029,1031,1036],{"type":48,"value":1023},"Always include ",{"type":43,"tag":57,"props":1025,"children":1027},{"className":1026},[],[1028],{"type":48,"value":70},{"type":48,"value":1030}," alongside ",{"type":43,"tag":57,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":48,"value":62},{"type":48,"value":1037}," when summing cost; embeddings are cheap per-call but add up at scale",{"type":43,"tag":248,"props":1039,"children":1040},{},[1041,1043,1051,1053,1058,1060,1065,1067,1073,1075,1081,1083,1089,1090,1096,1098,1104,1106],{"type":48,"value":1042},"Costs are written at ingestion (see ",{"type":43,"tag":283,"props":1044,"children":1048},{"href":1045,"rel":1046},"https:\u002F\u002Fposthog.com\u002Fdocs\u002Fai-observability\u002Fcalculating-costs",[1047],"nofollow",[1049],{"type":48,"value":1050},"Calculating LLM costs",{"type":48,"value":1052},") — if ",{"type":43,"tag":57,"props":1054,"children":1056},{"className":1055},[],[1057],{"type":48,"value":262},{"type":48,"value":1059}," is missing or zero, read ",{"type":43,"tag":57,"props":1061,"children":1063},{"className":1062},[],[1064],{"type":48,"value":366},{"type":48,"value":1066}," first: ",{"type":43,"tag":57,"props":1068,"children":1070},{"className":1069},[],[1071],{"type":48,"value":1072},"passthrough",{"type":48,"value":1074}," means the SDK supplied costs; ",{"type":43,"tag":57,"props":1076,"children":1078},{"className":1077},[],[1079],{"type":48,"value":1080},"custom",{"type":48,"value":1082}," means custom token prices; ",{"type":43,"tag":57,"props":1084,"children":1086},{"className":1085},[],[1087],{"type":48,"value":1088},"openrouter",{"type":48,"value":994},{"type":43,"tag":57,"props":1091,"children":1093},{"className":1092},[],[1094],{"type":48,"value":1095},"manual",{"type":48,"value":1097}," mean automatic lookup; missing means the model wasn't matched (unusual custom model, fine-tune). Grep: ",{"type":43,"tag":57,"props":1099,"children":1101},{"className":1100},[],[1102],{"type":48,"value":1103},"countIf(properties.$ai_total_cost_usd IS NULL)",{"type":48,"value":1105}," per ",{"type":43,"tag":57,"props":1107,"children":1109},{"className":1108},[],[1110],{"type":48,"value":1111},"(model, source)",{"type":43,"tag":248,"props":1113,"children":1114},{},[1115,1117,1122],{"type":48,"value":1116},"Custom pricing uses ",{"type":43,"tag":252,"props":1118,"children":1119},{},[1120],{"type":48,"value":1121},"per-token",{"type":48,"value":1123}," prices, not per-million — if a custom-priced model looks ~1M× too expensive or too cheap, that's almost always the bug",{"type":43,"tag":248,"props":1125,"children":1126},{},[1127],{"type":48,"value":1128},"Exclude errored calls from cost totals only when explicitly asked — providers still charge for many error modes, and including them gives the truthful bill",{"type":43,"tag":248,"props":1130,"children":1131},{},[1132,1134,1140],{"type":48,"value":1133},"For per-user totals, exclude rows where ",{"type":43,"tag":57,"props":1135,"children":1137},{"className":1136},[],[1138],{"type":48,"value":1139},"distinct_id = properties.$ai_trace_id",{"type":48,"value":1141}," — some SDKs default distinct_id to the trace ID when no user is set",{"type":43,"tag":248,"props":1143,"children":1144},{},[1145,1147,1152,1154,1159,1161,1166,1168,1173,1175,1180,1182,1188],{"type":48,"value":1146},"Cost is additive across ",{"type":43,"tag":57,"props":1148,"children":1150},{"className":1149},[],[1151],{"type":48,"value":62},{"type":48,"value":1153}," + ",{"type":43,"tag":57,"props":1155,"children":1157},{"className":1156},[],[1158],{"type":48,"value":70},{"type":48,"value":1160}," events within a trace; summing on ",{"type":43,"tag":57,"props":1162,"children":1164},{"className":1163},[],[1165],{"type":48,"value":324},{"type":48,"value":1167}," gives zero. ",{"type":43,"tag":57,"props":1169,"children":1171},{"className":1170},[],[1172],{"type":48,"value":317},{"type":48,"value":1174}," may carry ",{"type":43,"tag":57,"props":1176,"children":1178},{"className":1177},[],[1179],{"type":48,"value":262},{"type":48,"value":1181}," from some SDK wrappers — don't include it in rollups or you'll double-count. ",{"type":43,"tag":57,"props":1183,"children":1185},{"className":1184},[],[1186],{"type":48,"value":1187},"$ai_evaluation",{"type":48,"value":1189}," events also carry cost but are not part of the stock UI rollups; include them only when the user explicitly wants evaluation spend in the total",{"type":43,"tag":248,"props":1191,"children":1192},{},[1193,1195,1200],{"type":48,"value":1194},"Cache-hit rate depends on ",{"type":43,"tag":57,"props":1196,"children":1198},{"className":1197},[],[1199],{"type":48,"value":395},{"type":48,"value":1201}," — branch on the event-level flag rather than on provider or model name. Provider behavior and SDK versions drift; the flag is ingestion's resolved answer for that specific event",{"type":43,"tag":248,"props":1203,"children":1204},{},[1205,1207,1212],{"type":48,"value":1206},"When answering \"why is X expensive?\", show the cost ",{"type":43,"tag":252,"props":1208,"children":1209},{},[1210],{"type":48,"value":1211},"and",{"type":48,"value":1213}," the token split — the user almost always wants to know whether to shrink prompts, shrink outputs, or switch models",{"type":43,"tag":248,"props":1215,"children":1216},{},[1217,1219,1225],{"type":48,"value":1218},"Before building a custom dashboard, check whether the stock ",{"type":43,"tag":57,"props":1220,"children":1222},{"className":1221},[],[1223],{"type":48,"value":1224},"\u002Fai-observability\u002Fdashboard",{"type":48,"value":1226}," tiles already answer the question — re-creating them is churn",{"type":43,"tag":248,"props":1228,"children":1229},{},[1230,1232,1238],{"type":48,"value":1231},"For large tenants, materialize common cost queries as insights and reuse via ",{"type":43,"tag":57,"props":1233,"children":1235},{"className":1234},[],[1236],{"type":48,"value":1237},"insight-query",{"type":48,"value":1239},"; ad-hoc SQL is fine for one-offs but re-running it on every dashboard load is expensive",{"type":43,"tag":79,"props":1241,"children":1243},{"id":1242},"references",[1244],{"type":48,"value":1245},"References",{"type":43,"tag":244,"props":1247,"children":1248},{},[1249,1258,1267,1276,1285,1294],{"type":43,"tag":248,"props":1250,"children":1251},{},[1252,1256],{"type":43,"tag":283,"props":1253,"children":1254},{"href":285},[1255],{"type":48,"value":288},{"type":48,"value":1257}," — full property schema, total-cost rationale, event-set rules",{"type":43,"tag":248,"props":1259,"children":1260},{},[1261,1265],{"type":43,"tag":283,"props":1262,"children":1263},{"href":371},[1264],{"type":48,"value":374},{"type":48,"value":1266}," — how costs get set at ingestion plus a diagnostic query",{"type":43,"tag":248,"props":1268,"children":1269},{},[1270,1274],{"type":43,"tag":283,"props":1271,"children":1272},{"href":400},[1273],{"type":48,"value":403},{"type":48,"value":1275}," — exclusive vs inclusive providers, cache-hit-rate formula",{"type":43,"tag":248,"props":1277,"children":1278},{},[1279,1283],{"type":43,"tag":283,"props":1280,"children":1281},{"href":530},[1282],{"type":48,"value":533},{"type":48,"value":1284}," — SQL recipes for every common breakdown",{"type":43,"tag":248,"props":1286,"children":1287},{},[1288,1292],{"type":43,"tag":283,"props":1289,"children":1290},{"href":747},[1291],{"type":48,"value":750},{"type":48,"value":1293}," — 5-step playbook for cost spikes",{"type":43,"tag":248,"props":1295,"children":1296},{},[1297,1301],{"type":43,"tag":283,"props":1298,"children":1299},{"href":766},[1300],{"type":48,"value":769},{"type":48,"value":1302}," — insight, dashboard, and alert JSON",{"type":43,"tag":1304,"props":1305,"children":1306},"style",{},[1307],{"type":48,"value":1308},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1310,"total":1477},[1311,1324,1336,1349,1362,1377,1393,1410,1424,1439,1449,1467],{"slug":1312,"name":1312,"fn":1313,"description":1314,"org":1315,"tags":1316,"stars":1321,"repoUrl":1322,"updatedAt":1323},"analyzing-expensive-users","analyze expensive users in AI observability","Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1317,1318,1319,1320],{"name":24,"slug":25,"type":15},{"name":21,"slug":22,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},35568,"https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog","2026-07-28T05:34:11.117757",{"slug":1325,"name":1325,"fn":1326,"description":1327,"org":1328,"tags":1329,"stars":1321,"repoUrl":1322,"updatedAt":1335},"auditing-endpoints","audit PostHog project endpoints","Audit every endpoint in a PostHog project for staleness, failed materialisations, and unused materialised versions. Use when the user asks \"what endpoints can I clean up?\", \"are any of my endpoints broken?\", \"which materialised versions are still being called?\", or wants a one-shot cleanup pass over the Endpoints product. Produces a prioritised report grouped by issue type, with recommended actions but does not modify anything without explicit confirmation.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1330,1331,1334],{"name":24,"slug":25,"type":15},{"name":1332,"slug":1333,"type":15},"Audit","audit",{"name":9,"slug":8,"type":15},"2026-06-08T08:08:33.693989",{"slug":1337,"name":1337,"fn":1338,"description":1339,"org":1340,"tags":1341,"stars":1321,"repoUrl":1322,"updatedAt":1348},"auditing-warehouse-source-health","audit PostHog data warehouse source health","Audit the health of a PostHog project's data warehouse sources and syncs — find every broken or degraded source connection, sync schema, and webhook channel. Use when the user asks \"why are my imports failing?\", \"what's broken with my sources?\", \"why is my warehouse data stale?\", or wants a one-shot triage of source\u002Fsync health before deciding where to dig in. Produces a prioritized report grouped by severity, with recommended next steps. For materialized-view health use `auditing-warehouse-view-health`; for a single failing sync use `diagnosing-failed-warehouse-syncs`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1342,1343,1346,1347],{"name":1332,"slug":1333,"type":15},{"name":1344,"slug":1345,"type":15},"Data Warehouse","data-warehouse",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:22:57.67984",{"slug":1350,"name":1350,"fn":1351,"description":1352,"org":1353,"tags":1354,"stars":1321,"repoUrl":1322,"updatedAt":1361},"auditing-warehouse-view-health","audit PostHog materialized view health","Audit the health of a PostHog project's materialized views (saved queries) — find every failed materialization and flag unused or stale materialized views that cost storage and compute. Use when the user asks \"which of my views are broken?\", \"why is this materialized view failing?\", \"are any of my views wasting compute?\", or wants a one-shot triage of view health. For source\u002Fsync health use `auditing-warehouse-source-health`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1355,1356,1357,1360],{"name":1332,"slug":1333,"type":15},{"name":1344,"slug":1345,"type":15},{"name":1358,"slug":1359,"type":15},"Performance","performance",{"name":9,"slug":8,"type":15},"2026-06-18T08:25:10.936787",{"slug":1363,"name":1363,"fn":1364,"description":1365,"org":1366,"tags":1367,"stars":1321,"repoUrl":1322,"updatedAt":1376},"authoring-error-tracking-alerts","author PostHog error tracking alerts","Author error tracking alerts that fire when an issue is created, reopened, or starts spiking. Use when the user asks to set up error notifications, route exceptions to Slack\u002Fwebhook\u002FLinear, or evaluate which error events are worth alerting on. Covers trigger-event selection, integration choice, dedup against existing alerts, and shipping with the canonical message body shape.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1368,1371,1374,1375],{"name":1369,"slug":1370,"type":15},"Alerting","alerting",{"name":1372,"slug":1373,"type":15},"Debugging","debugging",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:24:40.318583",{"slug":1378,"name":1378,"fn":1379,"description":1380,"org":1381,"tags":1382,"stars":1321,"repoUrl":1322,"updatedAt":1392},"authoring-log-alerts","author log alerts in PostHog","Author useful, low-noise log alerts on services in a PostHog project. Use when the user asks to set up alerts for their logs, suggest alerts they should add, or evaluate whether a service is worth monitoring. Covers service triage, baseline characterisation, threshold drafting, back-testing via simulate, and shipping with a notification destination.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1383,1384,1387,1388,1391],{"name":24,"slug":25,"type":15},{"name":1385,"slug":1386,"type":15},"Monitoring","monitoring",{"name":13,"slug":14,"type":15},{"name":1389,"slug":1390,"type":15},"Operations","operations",{"name":9,"slug":8,"type":15},"2026-07-18T05:10:54.430898",{"slug":1394,"name":1394,"fn":1395,"description":1396,"org":1397,"tags":1398,"stars":1321,"repoUrl":1322,"updatedAt":1409},"building-workflows","build and edit PostHog workflows","Build, edit, test, enable, and monitor PostHog workflows over MCP. Author the action\u002Fedge graph so it runs and opens cleanly in the visual editor, then change drafts surgically with patch operations. Use when asked to build, set up, automate, change, fix, or debug a workflow, campaign, broadcast, drip sequence, or event-triggered automation in the workflows product.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1399,1402,1405,1406],{"name":1400,"slug":1401,"type":15},"Automation","automation",{"name":1403,"slug":1404,"type":15},"MCP","mcp",{"name":9,"slug":8,"type":15},{"name":1407,"slug":1408,"type":15},"Workflow Automation","workflow-automation","2026-07-28T05:34:12.167015",{"slug":1411,"name":1411,"fn":1412,"description":1413,"org":1414,"tags":1415,"stars":1321,"repoUrl":1322,"updatedAt":1423},"check-posthog-loading","inspect PostHog SDK loading across URLs","Inspect how the PostHog JavaScript SDK is loaded across a list of URLs. Use to confirm consistent installation across pages, find pages missing the snippet, detect mismatched API keys or hosts between pages, and verify the load method (head snippet vs deferred vs array.js).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1416,1417,1418,1421,1422],{"name":24,"slug":25,"type":15},{"name":1372,"slug":1373,"type":15},{"name":1419,"slug":1420,"type":15},"Frontend","frontend",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-05-07T05:56:19.828048",{"slug":1425,"name":1425,"fn":1426,"description":1427,"org":1428,"tags":1429,"stars":1321,"repoUrl":1322,"updatedAt":1438},"consuming-endpoints-from-client-code","integrate PostHog endpoints into client applications","Wire a PostHog endpoint into a client app or SDK. Covers fetching the OpenAPI spec, generating a typed client with openapi-generator or @hey-api\u002Fopenapi-ts, sending the right auth header, shaping the variables payload (HogQL code_name vs insight breakdown property), handling rate-limit and materialised-endpoint error responses. Use when the user says \"how do I call my endpoint\", \"generate a client for this\", or \"what auth header do I use\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1430,1433,1434,1435],{"name":1431,"slug":1432,"type":15},"API Development","api-development",{"name":1419,"slug":1420,"type":15},{"name":9,"slug":8,"type":15},{"name":1436,"slug":1437,"type":15},"SDK","sdk","2026-06-08T08:08:34.929454",{"slug":1440,"name":1440,"fn":1441,"description":1442,"org":1443,"tags":1444,"stars":1321,"repoUrl":1322,"updatedAt":1448},"copying-endpoints-across-projects","copy PostHog endpoints across projects","Copy a PostHog endpoint (a saved HogQL\u002Finsight query exposed as an API route) to another project in the same organization, or duplicate it under a new name in the same project. Use when the user wants to duplicate an endpoint, promote an endpoint from staging to production, replicate an endpoint's query\u002Fvariables\u002Ffreshness config in another workspace, or clone an endpoint to iterate on it. Unlike feature flags and experiments, endpoints have NO native cross-project copy tool — this skill covers the read-then-recreate flow (endpoint-get then endpoint-create), the active-project switching it requires, name-collision checks, and the safe defaults (land unmaterialised in the target, verify with endpoint-run). Does not cover editing endpoint versions (see managing-endpoint-versions) or authoring a brand-new endpoint from scratch (see creating-an-endpoint).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1445,1446,1447],{"name":1431,"slug":1432,"type":15},{"name":1389,"slug":1390,"type":15},{"name":9,"slug":8,"type":15},"2026-07-15T05:29:58.442727",{"slug":1450,"name":1450,"fn":1451,"description":1452,"org":1453,"tags":1454,"stars":1321,"repoUrl":1322,"updatedAt":1466},"creating-ai-subscription","schedule recurring AI-generated PostHog reports","Create a recurring AI-generated PostHog report — schedule a free-text prompt to run on a cron, with the LLM-synthesized markdown delivered to email or Slack on each tick. Use when the user wants a recurring AI summary of X on any cadence (daily, weekly, monthly, yearly) rather than a one-off report. (To attach an AI summary to an existing insight\u002Fdashboard subscription instead of a free-text prompt, see `managing-subscriptions` and its `summary_enabled` option.)\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1455,1456,1459,1460,1463],{"name":1400,"slug":1401,"type":15},{"name":1457,"slug":1458,"type":15},"Email","email",{"name":9,"slug":8,"type":15},{"name":1461,"slug":1462,"type":15},"Reporting","reporting",{"name":1464,"slug":1465,"type":15},"Slack","slack","2026-06-09T07:32:27.935712",{"slug":1468,"name":1468,"fn":1469,"description":1470,"org":1471,"tags":1472,"stars":1321,"repoUrl":1322,"updatedAt":1476},"creating-an-endpoint","create PostHog API endpoints","Create a PostHog endpoint with the right shape on the first try — covers query kind choice, name conventions, what to expose as variables (HogQL code_name vs insight breakdown), data_freshness_seconds, and whether to materialise on day one. Use when the user says \"create an endpoint\", \"expose this query as an API\", \"turn this insight into an endpoint\", or asks for help structuring a new endpoint. Steers away from common mistakes: materialising a query with cohort breakdowns or compare mode, inline-only variables on a materialised endpoint, unbounded date ranges, ambiguous names.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1473,1474,1475],{"name":24,"slug":25,"type":15},{"name":1431,"slug":1432,"type":15},{"name":9,"slug":8,"type":15},"2026-06-08T08:08:29.624498",231,{"items":1479,"total":1582},[1480,1497,1513,1527,1543,1555,1566],{"slug":1481,"name":1481,"fn":1482,"description":1483,"org":1484,"tags":1485,"stars":26,"repoUrl":27,"updatedAt":1496},"account-handover","draft sales account handover notes","Draft structured handover notes for transitioning a PostHog account from one TAM or CSM to another. Use this skill when a TAM needs to hand over an account, prepare a transition briefing, write handover notes, create an account summary for a new owner, or any request involving account transitions between TAMs or CSMs. Triggers on \"hand over this account\", \"transition account to\", \"draft handover notes\", \"account briefing for new TAM\", \"prepare account transition\", or when a TAM names an account and says they're leaving or reassigning it.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1486,1489,1492,1493],{"name":1487,"slug":1488,"type":15},"Communications","communications",{"name":1490,"slug":1491,"type":15},"CRM","crm",{"name":9,"slug":8,"type":15},{"name":1494,"slug":1495,"type":15},"Sales","sales","2026-04-16T05:13:00.172732",{"slug":1498,"name":1498,"fn":1499,"description":1500,"org":1501,"tags":1502,"stars":26,"repoUrl":27,"updatedAt":1512},"auditing-warehouse-data-health","audit PostHog data warehouse health","Audit the health of a PostHog project's data warehouse — find every broken or degraded pipeline item across sources, sync schemas, materialized views, batch exports, and transformations. Use when the user asks \"what's broken in my warehouse?\", \"give me a health check\", \"audit my data pipeline\", \"why are some dashboards stale?\", or wants a one-shot triage summary before deciding where to spend time. Produces a prioritized report of issues grouped by severity and type, with recommended next steps.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1503,1504,1507,1510,1511],{"name":1332,"slug":1333,"type":15},{"name":1505,"slug":1506,"type":15},"Data Engineering","data-engineering",{"name":1508,"slug":1509,"type":15},"Data Quality","data-quality",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-21T08:19:05.85849",{"slug":1514,"name":1514,"fn":1515,"description":1516,"org":1517,"tags":1518,"stars":26,"repoUrl":27,"updatedAt":1526},"copying-flags-across-projects","copy feature flags across PostHog projects","Copy a feature flag from one PostHog project to one or more target projects in the same organization. Use when the user wants to duplicate a flag, promote a flag from staging to production, sync flags across projects, or replicate a flag configuration in a different workspace. Covers cohort remapping, scheduled-change handling, encrypted payloads, and the safe defaults (disabled in target, no scheduled changes).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1519,1522,1525],{"name":1520,"slug":1521,"type":15},"Deployment","deployment",{"name":1523,"slug":1524,"type":15},"Feature Flags","feature-flags",{"name":9,"slug":8,"type":15},"2026-05-04T05:56:44.484909",{"slug":1528,"name":1528,"fn":1529,"description":1530,"org":1531,"tags":1532,"stars":26,"repoUrl":27,"updatedAt":1542},"diagnosing-experiment-results","diagnose PostHog experiment results and anomalies","Diagnoses bias, anomalies, and strange-looking results on a specific PostHog experiment. Covers empty \u002F 0-exposure experiments, sample ratio mismatch, identity fragmentation, multi-variant exposure, uneven-split exclusion bias, significance traps (peeking, A\u002FA, Bayesian vs Frequentist), PostHog-vs-SQL discrepancies, and surprises after mid-run edits. Symptom-driven dispatch to the right diagnostic.\nTRIGGER when: user asks 'is my experiment biased?' or 'why 0 exposures?', references the bias banner, says a variant looks strange \u002F wrong \u002F off, sees significance flipping, notices PostHog numbers disagreeing with their SQL, sees an A\u002FA test showing significance, or reports surprises after mid-run edits.\nDO NOT TRIGGER when: creating a new experiment (use creating-experiments), only configuring rollout (use configuring-experiment-rollout) or metrics (use configuring-experiment-analytics), or only asking lifecycle questions (use managing-experiment-lifecycle).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1533,1536,1537,1540,1541],{"name":1534,"slug":1535,"type":15},"A\u002FB Testing","a-b-testing",{"name":24,"slug":25,"type":15},{"name":1538,"slug":1539,"type":15},"Data Analysis","data-analysis",{"name":1372,"slug":1373,"type":15},{"name":9,"slug":8,"type":15},"2026-05-22T06:59:58.103867",{"slug":1544,"name":1544,"fn":1545,"description":1546,"org":1547,"tags":1548,"stars":26,"repoUrl":27,"updatedAt":1554},"diagnosing-missing-recordings","diagnose missing PostHog session recordings","Diagnoses why a session recording is missing or was not captured. Use when a user asks why a session has no replay, why recordings aren't appearing, or wants to troubleshoot session replay capture issues for a specific session ID or across their project. Covers SDK diagnostic signals, project settings, sampling, triggers, ad blockers, and quota\u002Fbilling scenarios.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1549,1550,1551,1552,1553],{"name":24,"slug":25,"type":15},{"name":1372,"slug":1373,"type":15},{"name":1419,"slug":1420,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-04-22T05:06:51.989772",{"slug":1556,"name":1556,"fn":1557,"description":1558,"org":1559,"tags":1560,"stars":26,"repoUrl":27,"updatedAt":1565},"diagnosing-sdk-health","diagnose PostHog SDK health","Diagnoses the health of a project's PostHog SDK integrations — which SDKs are out of date and how to fix them. Use when a user asks about PostHog SDK versions, outdated SDKs, upgrade recommendations, \"SDK health\", \"SDK doctor\" (the former name), or when events or features seem off and it might be due to an old SDK.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1561,1562,1563,1564],{"name":24,"slug":25,"type":15},{"name":1372,"slug":1373,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-04-27T05:46:14.554016",{"slug":1567,"name":1567,"fn":1568,"description":1569,"org":1570,"tags":1571,"stars":26,"repoUrl":27,"updatedAt":1581},"error-tracking-android","track Android errors with PostHog","PostHog error tracking for Android",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1572,1575,1576,1579,1580],{"name":1573,"slug":1574,"type":15},"Android","android",{"name":1372,"slug":1373,"type":15},{"name":1577,"slug":1578,"type":15},"Mobile","mobile",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-04-06T18:46:26.982494",110]