← Back to portfolio Sales Calls Analytics Dashboard preview
Stack
PythonStreamlitpandas
Impact
  • 16,891 synthetic calls, deterministic labeling (script markers)
  • 4-step funnel: greeting → offer → meeting → qualification
  • Main leak broken down by type (silence / hang-up / refusal) + weighted contact loss
  • Engagement by hour and weekday — when to call
  • LLM labeling hook (llm_labels.csv) — the pipeline is reproducible without it
Source View on GitHub → Updated: Jun 16, 2026

Sales Calls Analytics Dashboard

Context

An AI call flow is a funnel: greeting → offer → meeting → qualification. The production export stores the calls but does not say which step the bot loses the client on. The goal is to turn the raw export into an answer in a minute: where the drop-off is, for what reasons, when to call, and what to fix.

Data & Method

What the dashboard shows

Block What it answers
KPI + funnel overall picture and where the main break is
Step-1 breakdown the main leak by type: silence / hang-up / refusal
Where to focus funnel transitions by weighted contact loss
Client reactions what to fix in the script from the engaged tail
When to call engagement by hour and weekday
Bot quality ready-made defects: industry bug, looping, dead air
Dialog drill-down filter a slice + read drop-off transcripts

Labeling methodology

The bot script is templated, so the step a conversation reached is determined deterministically from markers in the bot’s replies:

  • 1 — greeting + consent;
  • 2 — offer;
  • 3 — meeting;
  • 4 — qualification.

The step-1 drop reason and the client reaction type are text heuristics. No LLM is used in the pipeline (everything is reproducible), but if an llm_labels.csv with phone, dt_raw, <labels> columns is placed alongside, the labels are merged automatically — reaction labeling can be strengthened via an LLM.

Data

The data/calls_demo.csv dataset is fully synthetic: generated by make_demo_data.py, deterministic on a fixed SEED, and contains no real phone numbers, names, or recordings. The numbers reproduce the shape of a typical production export (funnel, defects, hourly distribution) so the dashboard tells a realistic story on safe data.

Run

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/streamlit run app.py

Impact

  • A minute to an answer — which step loses the client and what to fix.
  • Deterministic labeling — reproducible, no LLM in the critical path.
  • A growth point — weighted contact loss and a first A/B scenario.
  • Safe demo — synthetic data, free public deployment.

Documentation

Case study

Problem

An outbound call flow is a funnel with big drop-off at early steps, but the production export does not answer the key question: which step the bot loses the client on, and what to fix — the script, the timing, or bot quality.

Approach

The step a conversation reached is determined deterministically from markers in the bot's scripted replies (greeting → offer → meeting → qualification). The step-1 drop reason and the client reaction type are text heuristics; no LLM is used in the pipeline, but an llm_labels.csv hook is provided to strengthen reaction labeling. The dashboard breaks the funnel into weighted contact loss, engagement by hour/day, and bot defects, with drill-down into drop-off transcripts.

Result

One minute to an answer to 'where the bot loses the client': a funnel with typed main leak, a growth point, and a first A/B scenario. Labeling is deterministic and reproducible, and the dataset is synthetic — safe for a public demo deploy.

16,891 Calls (synthetic)
4 Funnel steps
deterministic Labeling
no (hook exists) LLM in pipeline

Charts

Source: github.com/NikitaBoyarkin/sales-calls-dashboard: uv run python -c "import data_pipeline as dp; df=dp.load_and_process('data/calls_demo.csv')" (repo pipeline on data/calls_demo.csv, 11486 calls)

Call funnel by bot script step

Cumulative calls that reached each step of the templated bot script: dialed → greeting & consent → offer → meeting → qualification. Steps labeled from bot-script markers.

Набрано: 11486 (100% от макс.) Набрано 11486 Шаг 1 · Приветствие + согласие: 8401 (73.1% от макс.) Шаг 1 · Приветствие + согласие 8401 Шаг 2 · Оффер: 373 (3.2% от макс.) Шаг 2 · Оффер 373 Шаг 3 · Встреча: 137 (1.2% от макс.) Шаг 3 · Встреча 137 Шаг 4 · Квалификация: 32 (0.3% от макс.) Шаг 4 · Квалификация 32
Key takeaways
  • Of 11486 dialed calls only 373 reach the offer (4.4% of dialogs) — the main drop is at the conversation entry.
  • After consent the funnel flows well: 137 of 373 (36.7%) reach a meeting, 32 of 137 (23.4%) reach qualification.
  • 3085 calls (26.9% of all dials) never reach the greeting — roughly one in four is lost at entry.

Step 1 loss breakdown

How all 11486 calls distribute by first-step outcome (greeting & consent): instant drop/answering machine, drop at greeting, silence, answered but stuck, and those that moved on.

0 2000 4000 6000 Сброс на приветствии (клиент не ответил) — Звонки: 5493 5493 Нет диалога (мгновенный сброс/автоответчик) — Звонки: 3085 3085 Молчание (user: ...) — Звонки: 1558 1558 Ответил, но сорвался на шаге 1 — Звонки: 977 977 Дошёл до оффера и дальше — Звонки: 373 373 Сброс на приветствии (клиент не ответил) Нет диалога (мгновенный сброс/автоответчик) Молчание (user: ...) Ответил, но сорвался на шаге 1 Дошёл до оффера и дальше Step 1 outcome Call count
Key takeaways
  • 5493 of 11486 calls (47.8%) end with the bot hanging up before any answer to the greeting — the largest loss bucket.
  • Another 3085 (26.9%) are instant drops or answering machines; together with silence (1558), no-answer cases cover 88.3% of all dials.
  • Only 977 people (8.5%) answer yet the bot loses them on the very first step.

Calls by hour of day

Distribution of 11486 calls by dialing hour. Volume peaks at 17:00, and nearly all traffic is concentrated on Thursday and Friday (99.9%).

0 1000 2000 3000 4000 Звонков в час 09 — Звонков в час: 83 10 — Звонков в час: 24 11 — Звонков в час: 1083 12 — Звонков в час: 1322 13 — Звонков в час: 1044 14 — Звонков в час: 1376 15 — Звонков в час: 751 16 — Звонков в час: 731 17 — Звонков в час: 3053 18 — Звонков в час: 1434 19 — Звонков в час: 582 20 — Звонков в час: 3 09 10 11 12 13 14 15 16 17 18 19 20 Hour of day Call count
Key takeaways
  • 17:00 carries 3053 calls — 26.6% of all dials, the busiest hour.
  • The midday tail 11:00–14:00 totals 4449 calls (38.7%) versus 5069 (44.1%) in 17:00–18:00.
  • Traffic is packed into two days: 5824 calls on Thursday and 5649 on Friday (99.9% combined).

Average duration by conversation step

Average call duration (seconds) by the deepest step the conversation reached. Duration is a function of step: the further the client goes, the longer the dialog.

0 50 100 150 0 · Без приветствия — Средняя длительность, сек: 3.3 3.3 1 · Приветствие + согласие — Средняя длительность, сек: 20.1 20.1 2 · Оффер — Средняя длительность, сек: 71.8 71.8 3 · Встреча — Средняя длительность, сек: 129.9 129.9 4 · Квалификация — Средняя длительность, сек: 141.4 141.4 0 · Без приветствия 1 · Приветствие + согласие 2 · Оффер 3 · Встреча 4 · Квалификация Max reached step Average duration, sec
Key takeaways
  • Calls without a greeting average 3.3 sec — instant drops/answering machines (3085 calls).
  • Moving from step 1 to the offer lengthens the call 3.6×: from 20.1 to 71.8 sec (236 calls).
  • Dialogues reaching a meeting or qualification average 129.9 and 141.4 sec — a quality talk is ~40× longer than an instant drop.

See also

Connection map

Projects, posts and topics connected to this one. Hover a node to see its name; click to open.