AI
Build Log: Call Intelligence Dashboard for 20+ Dental Clinics
How I built the Call Intelligence Platform — a real-time call-scoring dashboard — from the first webhook to a live multi-tenant system processing every inbound call across 20+ locations.
The brief was simple: every inbound call to every clinic, scored automatically, visible in a single dashboard. No manual review, no sampling. 100% coverage.
Here's how I built it.
The Starting Point
The client ran 20+ dental practices through GoHighLevel. Every location had its own sub-account, its own call log, its own staff. The existing process: a manager would occasionally listen to random calls and score them manually. Coverage was maybe 5% on a good week. The rest was invisible.
The ask: make every call visible, scored, and reportable — without adding headcount.
Architecture Overview
The system has four layers:
- Ingestion — GoHighLevel webhooks fire on every call completion
- Transcription — Audio is passed to a transcription service and converted to text
- Scoring — Google Gemini evaluates the transcript against an 8-step framework
- Reporting — Results land in a central database and push to three delivery channels
Each layer is a separate n8n workflow. They communicate via an internal queue so a transcription delay doesn't block the scoring step from starting.
The Webhook Setup
GoHighLevel supports outbound webhooks at the sub-account level. With 20+ sub-accounts, I wrote a setup script that configured identical webhooks across all of them pointing to a single n8n endpoint.
The webhook payload includes: call direction (inbound/outbound), duration, caller ID, the sub-account ID, and — critically — a link to the call recording.
The first n8n workflow receives the webhook, validates the payload, filters out calls under 30 seconds (voicemails and hang-ups), and queues the rest for processing.
Transcription
Call recordings come as GHL-hosted audio files. The workflow downloads each file, sends it to a transcription API, and stores the result with the call metadata in a Postgres database. Typical turnaround: under 60 seconds per call.
One edge case: calls where the patient speaks in a mix of English and Tagalog (common in some of the clinic's markets). The transcription model handles code-switching reasonably well, but Gemini needed explicit instruction to handle mixed-language transcripts gracefully rather than flagging them as low-confidence.
The Scoring Framework
The scoring workflow takes each transcript and passes it to Gemini with a structured prompt built around an 8-step call quality framework:
- Greeting and identification
- Active listening — does the staff acknowledge the patient's concern before offering information?
- Appointment pitch — is a booking offered within the first two minutes?
- Objection handling — price, timing, fear
- Confirmation — is the appointment confirmed with full details?
- Follow-up intent — is a follow-up mentioned if no booking happens?
- Closing — professional close with next steps
- Overall sentiment
The output is a JSON object with a score per step (0–2), a flag for any critical failure, and a one-sentence summary of what went well and what to improve.
Getting Gemini to return consistent JSON took iteration. The final prompt uses a chain-of-thought prefix that asks the model to reason through each step before outputting, which dramatically reduced hallucinated scores on edge cases.
The Dashboard
Scored calls land in a Postgres database with 16+ tables covering calls, scores, agents, locations, and aggregated metrics. The frontend is a custom dashboard that shows:
- Call volume by location, by day
- Average score per location and per staff member
- Missed vs. answered ratio
- Flagged calls (critical failures) highlighted for review
- Trend lines for booking rate over time
One addition that the client specifically asked for: a comparison panel showing AI-handled calls (the clinic also uses a voice agent) vs. human-handled calls, with side-by-side scoring. This surfaced something interesting — the AI agent scored higher on steps 1, 3, and 5 consistently, while human agents scored higher on steps 2 and 4 (active listening and objection handling).
Reporting Delivery
The daily report runs at 7:00 AM via a scheduled n8n workflow. It queries the prior day's data, formats a structured summary per location, and delivers via:
- SMS — a short scorecard text to each location manager
- Email — a formatted HTML email with location breakdown and flagged calls
- Dashboard — the persistent web dashboard for deeper drill-down
The weekly report aggregates seven days of data and adds trend analysis — whether scores are improving or declining week-over-week at each location.
What I'd Do Differently
The transcription step is the slowest part of the pipeline. Average 45–90 seconds, which is fine for a daily reporting context but would be too slow for a real-time alert system. If the client wanted same-minute alerts on critical call failures, I'd move to a streaming transcription approach instead of batch.
The dashboard is custom-built, which gave full control over the data model and display. In retrospect, for a simpler reporting need, a Retool or Metabase setup on top of the same Postgres schema would have been faster to deploy — though it would have been less flexible for the location-vs-AI comparison panel.
Current State
The system has been running for several months across all 20+ locations. Every inbound call is scored. The client's operations team now has a weekly review meeting that runs entirely off the dashboard data — no manual listening, no sampling. Coverage went from under 5% to 100%.
Related Reading
Build Log
The AI Peak Myth: Why Your Ops Should Be Doubling Down on Automation Now
Reacting to the 'AI peak' narrative with evidence from the battlefield and a playbook for ops leaders to keep investing in automation.
Build Log
Don't Pause Your Automation: A Playbook for Ops Leaders Navigating AI Regulation Noise
Reacting to the 'pause AI' letter without losing momentum on practical automations that actually serve your B2B team.