apps/server/docs/ai-context/product-analytics-dashboard-setup.md
This document turns product-analytics-instrumentation.md into dashboard setup steps. It intentionally excludes Discord / QQ ingestion and daily / weekly report automation.
After setting up the dashboards, run verifications/product-analytics-smoke.md against the deployed environment.
In scope:
Out of scope for this pass:
| Question | Destination | Reason |
|---|---|---|
| Can a user start chatting? | PostHog | Frontend journey and distinct user funnels |
| Where does provider setup fail? | PostHog | Provider config events are frontend PostHog events |
| Which voice is selected or previewed? | PostHog / Postgres metadata | voice_id is high-cardinality and must not be a Prometheus label |
| Is server TTS healthy right now? | Grafana | Server product events and OTel metrics are Prometheus-safe |
| Are users submitting feedback? | PostHog | App feedback is frontend product analytics |
Create a dashboard named AIRI Activation And Feedback.
Live dashboard created on 2026-06-30:
Project AIRI (Web) (90721)https://us.posthog.com/project/90721/dashboard/1779029AIRI product analytics runbookChat activation funnelOfficial provider usageOfficial TTS activationPaywall exposureProvider config failuresTTS voice selection and previewTop selected TTS voicesVoice input frictionFeedback and bug reportsType: Funnel
Steps:
chat_activation_startedchat_activation_succeededsecond_turn_startedBreakdowns:
provider_modesurfaceFilters:
Watch for:
chat_activation_started.second_turn_started conversion.Type: Trends
Events:
official_provider_selectedBreakdowns:
provider_idsourceauto_selectedWatch for:
second_turn_started.Type: Trends
Events:
chat_activation_failedBreakdowns:
failure_stageerror_codeprovider_modeDisplay:
Watch for:
failure_stage = provider_configfailure_stage = model_listfailure_stage = llm_responseType: Funnel
Steps:
provider_config_startedprovider_config_succeededBreakdowns:
provider_modestepCompanion trend:
provider_config_failederror_codeWatch for:
step = manual_chat_ping failures after auto validation succeeds.Type: Trends
Events:
model_list_loadedmodel_list_failedBreakdowns:
provider_idprovider_modeWatch for:
model_list_failed spikes for one provider.Type: Trends
Events:
voice_selectedvoice_preview_playedvoice_pack_boundofficial_tts_exposedofficial_tts_preview_startedofficial_tts_preview_succeededofficial_tts_auto_enabledBreakdowns:
voice_typetts_provider_idsourceDo not use:
voice_id or voice_pack_id.Use PostHog or SQL when grouping by:
voice_idvoice_pack_idWatch for:
Type: Funnel
Steps:
voice_input_startedstt_succeededCompanion trends:
microphone_permission_deniedaudio_device_unavailablevoice_input_cancelledstt_failedBreakdowns:
stt_provider_iderror_codesurfaceType: Trends
Events:
feedback_submittedbug_report_submittedBreakdowns:
categoryseverityentrypointsurfaceWatch for:
severity = blocker spikes.entrypoint = about_update_error after desktop releases.Source of truth:
apps/server/otel/grafana/dashboards/build.tsapps/server/otel/grafana/dashboards/airi-server-overview-cloud.jsonThe Product Analytics row includes:
Product Events (range)Product Failure %TTS Success %TTS Failed / Blocked (range)TTS Blocked by ReasonTTS Blocked by Flux BucketTop Product Actions (range)Product Event RateTTS Event Rate by SourceLive import status:
https://projairi.grafana.net/d/ad8qbp5/airi-server-overviewAIRI Server Overview - Product Analytics (ad8qbp5)Product Analytics row:
Product Events (range)Product Failure %TTS Success %TTS Failed / Blocked (range)TTS Blocked by ReasonTTS Blocked by Flux BucketTop Product Actions (range)Product Event RateTTS Event Rate by SourcePermission notes from the import retry:
AIRI Server Overview and UID rbr55dn showed duplicate title / UID warnings because it targets the existing dashboard.AIRI Server Overview - Product Analytics Test, airi-product-analytics-test) removed the duplicate warnings, but still did not import.403 Access denied: You'll need additional permissions to perform this action. Permissions needed: any of dashboards:create, dashboards:write.[email protected] has org role Viewer; API metadata for /d/rbr55dn/airi-server-overview reports canSave=false, canEdit=false, canAdmin=false.ad8qbp5 instead of overwriting the earlier rbr55dn dashboard, so the imported dashboard was renamed to AIRI Server Overview - Product Analytics to avoid ambiguity.ad8qbp5 dashboard was updated to include TTS Blocked by Reason and TTS Blocked by Flux Bucket. The live dashboard uses panel id 105 for the Flux bucket panel because id 103 was already occupied by the imported User Engagement row.Regenerate after dashboard changes:
node node_modules/tsx/dist/cli.mjs apps/server/otel/grafana/dashboards/build.ts
Configure these as insight subscriptions or monitor-style alerts.
| Alert | Insight | Trigger |
|---|---|---|
| Activation drop | Chat Activation Funnel | chat_activation_succeeded / chat_activation_started drops by 15% vs previous 24h |
| Provider config regression | Provider Configuration Health | Official provider provider_config_failed is greater than 0 for 15 minutes |
| Voice input spike | Voice Input Friction | stt_failed / voice_input_started exceeds 20% over 1h |
| Feedback spike | Feedback And Bug Reports | bug_report_submitted doubles vs previous 24h |
Use these PromQL expressions from the server dashboard context.
TTS success below 95% over 15 minutes:
100 * sum(increase(airi_product_events_total{feature="tts", action="speech_succeeded", status="succeeded"}[15m]))
/
clamp_min(sum(increase(airi_product_events_total{feature="tts", action="speech_requested", status="started"}[15m])), 1)
< 95
TTS blocked spike over 15 minutes:
sum(increase(airi_product_events_total{feature="tts", action="speech_blocked", status="blocked"}[15m])) > 10
TTS failed spike over 15 minutes:
sum(increase(airi_product_events_total{feature="tts", action="speech_failed", status="failed"}[15m])) > 5
Product failure ratio above 10% over 15 minutes:
100 * sum(increase(airi_product_events_total{feature!="", action!="", status="failed"}[15m]))
/
clamp_min(sum(increase(airi_product_events_total{feature!="", action!=""}[15m])), 1)
> 10
chat_activation_started -> chat_activation_succeeded -> second_turn_started by provider_mode.official_provider_selected by provider_id, source, and auto_selected.voice_selected by voice_type and tts_provider_id.paywall_seen by flux_balance_bucket.feedback_submitted and bug_report_submitted.TTS Success %, TTS Failed / Blocked (range), TTS Blocked by Reason, TTS Blocked by Flux Bucket, and TTS Event Rate by Source.feature, action, status, source, reason, flux_balance_bucket.