Privacy-conscious participation analytics experiment for online language classes.
SpeakBalance was a short technical feasibility prototype. It explored whether Zoom active-speaker metadata could estimate participation balance without recording or transcribing lesson content.
Project status: Technical feasibility prototype - concluded after identifying a platform-data limitation.
Language teachers and teacher trainers often discuss Teacher Talk Time and Student Talk Time, but measuring that balance objectively during a live online lesson is difficult.
Recording or transcribing lessons can create privacy, consent, and data handling concerns. SpeakBalance explored whether a lighter metadata-only signal could support teacher reflection.
Could Zoom active-speaker metadata estimate participation balance without using lesson audio, video, transcripts, chat, or content analysis?
The intended data boundary was:
- participant display name
- participant metadata needed for in-session event identity
- active-speaker event time
- teacher/student role mapping
- estimated active-speaker duration
- React/Vite frontend
- Zoom Apps SDK
onActiveSpeakerChangeintegration - local active-speaker capture flow
- event normalisation and duplicate-event handling
- speaking-segment generation
- inactivity-timeout estimation for unclear gaps
- teacher/student/unknown role mapping
- per-speaker and per-role participation summaries
- final session report view
- plain text report export
- sample-data demo pipeline for local review
The Zoom integration was tested in real Zoom desktop meetings, not only against mocked data.
The tests checked whether active-speaker events fired, whether they included usable participant metadata, how duplicate events behaved, how silence was represented, and whether speaker handovers could be detected.
onActiveSpeakerChangesuccessfully identified active participants.- Repeated and duplicate events required cleaning before analytics.
- Same-speaker events could be sparse during continuous speech.
- Zoom did not provide a sufficiently reliable stop/silence signal for exact stopwatch-style timing in this implementation.
- Timeout logic could estimate unclear gaps, but it could not measure silence exactly.
- Additional Zoom SDK event paths were investigated, but they did not provide a reliable replacement for exact start/stop timing.
The result is best described as estimated participation analytics, not exact talk-time measurement.
Development stopped at the feasibility stage.
The prototype proved that the app could integrate with Zoom and capture useful active-speaker metadata. It also showed that the available metadata was not granular or consistent enough for accurate speaking-duration measurement.
Building authentication, databases, backend storage, payments, deployment, or a larger product workflow on top of that assumption would have been premature. Stopping was a deliberate scope-control decision based on the technical finding.
The prototype does not record, store, upload, transcribe, or analyse lesson audio/video/content. It is designed around active-speaker metadata and local prototype processing.
SpeakBalance is privacy-conscious, not privacy-free: participant metadata still needs careful handling, consent, and clear disclosure in any future product.
- React
- Vite
- JavaScript
- Zoom Apps SDK
Install dependencies:
npm installRun the local app:
npm run devRun the sample analytics demos:
node src/analytics/demoCalculateDurations.js
node src/analytics/demoNormaliseZoomSpeakerEvents.js
node src/analytics/demoSummariseSpeakerSegments.js
node src/analytics/demoApplySpeakerRoles.js
node src/reporting/demoGenerateTextReport.jsBuild the app:
npm run buildGenerated text reports are written to reports/ and ignored by Git.