From 6707dd45e1f9faf6dd104ef9004f761e151d0ec1 Mon Sep 17 00:00:00 2001 From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:04:10 +0000 Subject: [PATCH 1/2] fix(pricing): show AI Observability on the pricing page After renaming "LLM analytics" to "AI Observability", the product's `handle` was changed to `ai_observability`, but the billing service still exposes it under its original type `llm_analytics`. `useProducts` joins static product data to live billing data on `billingProduct.type === product.handle`, so the join returned `undefined`, leaving the product with no `billingData`/`unit`. Both pricing surfaces filter those out (calculator requires `unit`, accordion requires `billingData`), so AI Observability silently disappeared from /pricing. Decouple the billing-API key from the display handle via a new optional `billingType` field (falling back to `handle` for every other product) and set `billingType: 'llm_analytics'` on AI Observability. Also fix a stale `llm_analytics` reference in a customer's `toolsUsed`. Verified locally: AI Observability now renders in the calculator tabs and the rates accordion with its billing tiers (From $0.00006/event, first 100k free). Generated-By: PostHog Code Task-Id: e5d5edce-1e9b-4f40-9a88-3f53b5ba945f --- src/hooks/productData/ai_observability.tsx | 4 ++++ src/hooks/useCustomers.tsx | 2 +- src/hooks/useProducts.tsx | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/hooks/productData/ai_observability.tsx b/src/hooks/productData/ai_observability.tsx index 5ac24bfc51e0..349c76063d56 100644 --- a/src/hooks/productData/ai_observability.tsx +++ b/src/hooks/productData/ai_observability.tsx @@ -47,6 +47,10 @@ export const aiObservability = { description: 'Track costs, performance, and usage of your AI features', handle: 'ai_observability', type: 'ai_observability', + // The billing service still exposes this product under its original type + // (`llm_analytics`) from before the "AI Observability" rename. Billing data is + // joined on this value so pricing/calculator surfaces can find it. + billingType: 'llm_analytics', slug: 'ai-observability', color: 'purple', colorSecondary: 'green-2', diff --git a/src/hooks/useCustomers.tsx b/src/hooks/useCustomers.tsx index 423e99424fbd..16dab8533a2a 100644 --- a/src/hooks/useCustomers.tsx +++ b/src/hooks/useCustomers.tsx @@ -758,7 +758,7 @@ const CUSTOMER_DATA: Record = { 'product_analytics', 'session_replay', 'surveys', - 'llm_analytics', + 'ai_observability', 'warehouse_sources', ], industries: ['Ad Tech', 'Hospitality', 'Digital Signage'], diff --git a/src/hooks/useProducts.tsx b/src/hooks/useProducts.tsx index d16f46847c0a..a6361ab71b52 100644 --- a/src/hooks/useProducts.tsx +++ b/src/hooks/useProducts.tsx @@ -50,7 +50,10 @@ export default function useProducts() { initialProducts.map((product) => { const billingData = product.billingData || - billingProducts.find((billingProduct: any) => billingProduct.type === product.handle) + billingProducts.find( + (billingProduct: any) => + billingProduct.type === ((product as any).billingType || product.handle) + ) const paidPlan = billingData?.plans.find((plan: any) => plan.tiers) const startsAt = paidPlan?.tiers?.find((tier: any) => tier.unit_amount_usd !== '0')?.unit_amount_usd const freeLimit = paidPlan?.tiers?.find((tier: any) => tier.unit_amount_usd === '0')?.up_to From 856718c0d06af0915f39fde08fe00a4a09b34ff9 Mon Sep 17 00:00:00 2001 From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 18:07:29 +0000 Subject: [PATCH 2/2] refactor(pricing): replace `as any` with a typed billingType lookup Use a precise structural assertion (`{ billingType?: string }`) instead of `as any` when resolving the billing-data join key, and pull it into a named `billingType` local for readability. No behavior change. Generated-By: PostHog Code Task-Id: e5d5edce-1e9b-4f40-9a88-3f53b5ba945f --- src/hooks/useProducts.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hooks/useProducts.tsx b/src/hooks/useProducts.tsx index a6361ab71b52..93983b0289b4 100644 --- a/src/hooks/useProducts.tsx +++ b/src/hooks/useProducts.tsx @@ -48,12 +48,13 @@ export default function useProducts() { const [products, setProducts] = useState( initialProducts.map((product) => { + // Products are joined to live billing data by type. A product can override + // the key the billing service uses via `billingType` (e.g. AI Observability + // is still `llm_analytics` upstream); otherwise the handle is the key. + const billingType = (product as { billingType?: string }).billingType || product.handle const billingData = product.billingData || - billingProducts.find( - (billingProduct: any) => - billingProduct.type === ((product as any).billingType || product.handle) - ) + billingProducts.find((billingProduct: any) => billingProduct.type === billingType) const paidPlan = billingData?.plans.find((plan: any) => plan.tiers) const startsAt = paidPlan?.tiers?.find((tier: any) => tier.unit_amount_usd !== '0')?.unit_amount_usd const freeLimit = paidPlan?.tiers?.find((tier: any) => tier.unit_amount_usd === '0')?.up_to