Show live audience activity
Use this when many users should see the same live activity state: who is present, how often an action is happening, or the current intensity of a continuous signal.
What you implement: clients submit small telemetry actions and poll one aggregate context for display. TalkLabs maintains the synchronized counters, gauges, presence windows, and normalized intensity values.
Choose the signal for the UI
Section titled “Choose the signal for the UI”| Experience | Signal | Client writes | UI reads |
|---|---|---|---|
| “People here now” | Presence | Periodic heartbeat per user | Active user count |
| Reaction pulse or applause | Metric | Increment on each action | Window value, total, intensity |
| Sound or interaction meter | Gauge | Normalized sample from 0 to 1 | Average, active contributors, intensity |
| Mobile client with several signals | Batch | Buffer mixed operations for 1–2 seconds | Same context aggregate |
contextid is a customer-defined ID. Use a value your product already knows,
such as live-event-chat, so chat and telemetry screens can address the same
experience without another lookup.
Operation map
Section titled “Operation map”| Task | Operation |
|---|---|
| Mark a user present | Record presence heartbeat |
| Record an action | Increment a counter |
| Record a continuous value | Record a gauge sample |
| Flush several actions | Submit a telemetry batch |
| Render synchronized state | Read the live meter |
Example: presence plus reaction pulse
Section titled “Example: presence plus reaction pulse”const origin = 'https://api.sportstalk247.com';const contextId = 'live-event-chat';const headers = { 'x-api-token': API_TOKEN, 'Content-Type': 'application/json',};
async function post(path, body) { const response = await fetch( `${origin}/api/v3/${APP_ID}/telemetry/contexts/${contextId}/${path}`, { method: 'POST', headers, body: JSON.stringify(body) }, ); if (!response.ok) throw new Error(`telemetry failed: ${response.status}`);}
export function heartbeat() { return post('presence/viewers/heartbeat', { userId: 'u-8842' });}
export function react() { return post('metrics/reaction.primary/increment', { userId: 'u-8842', by: 1, });}Send presence heartbeats while the experience is visible. Stop when the user leaves; the active count falls as the presence window expires.
Read one aggregate for every viewer
Section titled “Read one aggregate for every viewer”export async function readActivity() { const response = await fetch( `${origin}/api/v3/${APP_ID}/telemetry/contexts/${contextId}`, { headers }, ); if (!response.ok) throw new Error(`meter failed: ${response.status}`);
const { data } = await response.json(); activityStore.replace(data);}Bind each reading’s normalized intensity to animation scale, opacity, or meter
fill. Use the raw fields when the UI needs an exact count or average.
Batch high-frequency clients
Section titled “Batch high-frequency clients”Buffer increments, samples, and heartbeats locally, then send them together:
await post('batch', { userId: 'u-8842', ops: [ { op: 'heartbeat', key: 'viewers' }, { op: 'increment', key: 'reaction.primary', by: 3 }, { op: 'sample', key: 'interaction.level', value: 0.72 }, ],});The batch endpoint reports invalid items without discarding valid items in the same request. Inspect per-item results before clearing a retry buffer.
UX checklist
Section titled “UX checklist”- Label exact counts differently from normalized intensity.
- Reduce motion when the user requests it.
- Pause visual polling in hidden tabs when a stale display is acceptable.
- Stop microphone or sensor sampling immediately when the feature is inactive.
- Use stable customer-defined context and signal keys.
- Buffer rapid actions and flush them with the batch operation.