All work

End-to-end call tracking system

A dual-ingestion system — custom Android app for pre-sale, Twilio webhooks for operations — unifying every customer touchpoint from first call to closed deal.

Role
Software Engineer — design, build, operation
Period
2024 — Present
Company
Digital marketing agency (confidential)

100%

of calls logged with audio, transcript & AI summary

2→1

capture flows (Android + Twilio) converging into one timeline

1 click

to re-transcribe & re-summarize any call on demand

#Context

The agency runs sales operations for multiple clients, with two teams that call customers in completely different ways. The pre-sale team works from agency-owned, rooted Android phones; the operations team calls from a web system with an embedded phone. None of that activity was visible: no record of who called whom, for how long, or what was said. Quotes moved through Kommo CRM with no connection to the calls that drove them, and management couldn't measure sales performance beyond closed deals.

#Problem & constraints

  • Pre-sale calls happen on rooted agency Android phones — no Play Store recording APIs work there; capturing audio requires a custom app with root access (Magisk/superuser).
  • On the Android flow there was nowhere else to keep the recordings — the audio only exists on the device, so full audio has to live on our own server, and storage cost grows with call volume.
  • Operations calls run through an embedded Twilio phone in the web system — a completely separate capture path, with recordings hosted by the provider.
  • Call data, quote status changes and customer identity lived in disconnected systems (phones, Twilio, Kommo) — no end-to-end traceability from pre-sale to post-sale.

#Architecture

Android approot · Magisk · loginOwn serverfull audio storedWeb phoneembedded · operationsTwiliowebhook · URL onlyWhisper + LLMtranscript & summaryMongoDBunified timelineKommo CRMquote webhooksKPI dashboardReact
Two capture flows — pre-sale Android (full audio) and operations Twilio (URL only) — converge on one customer timeline.

Flow 1 — pre-sale: a custom Android app on the rooted phones tracks the device's call state in real time (ringing / offhook / idle via TelephonyManager). The rep logs in with their agency account, so every call is bound to their worker ID. When a call ends, the app uploads the metadata (duration, number, direction) plus the full audio to our server — the recording only exists on the device, so our server is its permanent home. Flow 2 — operations: reps call from the web system's embedded Twilio phone; when the call ends, Twilio fires a webhook at our endpoint, and we store only the provider's recording URL. A background pipeline downloads the audio temporarily, transcribes it with Whisper, summarizes it with an LLM, and discards the local copy. Both flows — plus Kommo webhooks mirroring quote status changes — converge into the same unified per-customer timeline in MongoDB, giving full pre-sale → post-sale traceability, including signals of interest in other agency services. Any call in the timeline can be re-transcribed and re-summarized on demand with one button, reusing the same pipeline. A React dashboard renders the funnel (lead → prospect → client) with per-salesperson KPIs: calls made, quotes by status, meetings booked.

sales.internal/dashboard

117

Calls

28

Quotes

12

Meetings

Lead
100%
Prospect
58%
Client
24%
SellerCallsQuotesMeetings
A. Torres
47
125
M. Quispe
39
94
L. Ramos
31
73

* Interface recreated with synthetic data — the production system holds client-confidential data.

#Key decisions & tradeoffs

01Custom Android app with root access

Decision
Build a purpose-built app that captures call state (ringing / offhook / idle) via root access (Magisk), with agency login binding every call to a worker ID.
Alternatives
Off-the-shelf call tracking platforms, or forcing reps to log calls manually in the CRM.
Why
No commercial tool can capture audio on this hardware, and manual logging fails on day one. Root access was a constraint we could turn into full control over capture — and the login requirement turned attribution into a solved problem instead of a mapping table.
Cost of being wrong
We own Android maintenance forever — OS updates can break capture, and there's no vendor to escalate to.

02Android flow: store full audio on our own server

Decision
Persist the complete recording of every pre-sale call on our own storage, alongside its transcript and summary.
Alternatives
Process the audio on-device and discard it, or upload-then-delete after transcription (keeping only text).
Why
These are native cellular calls — there is no provider holding a copy; the recording exists only on the phone. Without server-side storage there is no audio to re-transcribe, audit a conversation with a client, or resolve a dispute. Keeping it also powers the on-demand re-processing button.
Cost of being wrong
Storage cost grows linearly with call volume — the exact tradeoff we rejected in the Twilio flow, accepted here because there was no alternative. It needs retention policies and monitoring the other flow doesn't.

03Twilio flow: keep recording URLs, not audio files

Decision
Store only the provider-hosted recording URL; download the audio temporarily for transcription, then discard the local copy.
Alternatives
Downloading every recording permanently to our own object storage for full control.
Why
Here the provider already hosts the audio durably — the transcript + summary is what the business actually reads. Duplicating the audio into our storage would multiply costs for near-zero marginal value.
Cost of being wrong
If Twilio purges old recordings, the original audio is gone — accepted, because transcripts and summaries are the durable record on this flow.

04One customer timeline across the funnel

Decision
Model both call flows, transcripts and CRM quote events as entries on a single per-customer timeline in MongoDB, instead of separate collections per source.
Alternatives
Keep Android calls, Twilio calls and CRM events in separate schemas and join them in the dashboard.
Why
Every consumer of this data — the dashboard, reports, future automations — wants 'everything that happened with this customer', chronologically, regardless of which team or channel touched them. A unified event model makes that the cheap query and preserves pre-sale → post-sale traceability, including interest signals in other agency services.
Cost of being wrong
Ingestion has to normalize two very different event shapes (device-uploaded vs. provider webhook) upfront — more schema design work, and migrations when a source changes its payload.

#Results

100%

call visibility — every call logged, transcribed and summarized

3→1

systems consolidated into one customer timeline

Live

KPI dashboard used daily to manage the sales team

#What I'd do differently

I'd design the event schema for the unified timeline earlier — we migrated it once when Kommo payloads changed, and a versioned event envelope from day one would have made that free. I'd also add storage retention policies for the Android flow's audio from the start; we bolted them on after volume made the cost visible. And dead-letter queues on webhook ingestion sooner — transient Twilio retries taught us that lesson in production.

#Stack

AndroidMagisk (root)TwilioNode.jsTypeScriptMongoDBWhisperOpenAIKommo CRMReact