Live Data
Push real-time score updates, clock values, and other live data to productions.
Live data is the real-time, frequently-updated state of a production — scores, clock, period, game state, and any other values that change during a broadcast. Updating live data instantly propagates through the snapshot pipeline to all connected graphics.
Update Live Data
Merge new values into a production's live data. Only the provided keys are updated; existing keys are preserved.
POST /api/cms/productions/liveAuth: readwrite
Request:
curl -X POST https://ideal-heron-677.convex.site/api/cms/productions/live \
-H "Authorization: Bearer lw_your_key" \
-H "Content-Type: application/json" \
-d '{
"productionId": "j572prod1...",
"data": {
"homeScore": 28,
"period": "4th",
"clock": "12:00"
}
}'| Field | Type | Required | Description |
|---|---|---|---|
productionId | string | Yes | The production ID |
data | object | Yes | Key-value pairs to merge into live data |
Response:
{
"ok": true
}How It Works
When you update live data:
- The new values are merged into the production's
liveDataobject - If the production has a
liveDataSchema, the merged data is validated against it - The production's snapshot is updated atomically
- All playout manifests for the production are regenerated in the background
- Connected LiveWing devices receive the updated manifest via their real-time subscription
This entire pipeline typically completes in under 200ms.
Typical Integration: Score Feed
A common use case is feeding scores from an external source (StatBroadcast, manual scoreboard, custom app) into LiveWing productions:
import requests
API_KEY = "lw_your_key_here"
BASE_URL = "https://ideal-heron-677.convex.site"
PRODUCTION_ID = "j572prod1..."
def update_score(home_score: int, away_score: int, period: str, clock: str):
requests.post(
f"{BASE_URL}/api/cms/productions/live",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={
"productionId": PRODUCTION_ID,
"data": {
"homeScore": home_score,
"awayScore": away_score,
"period": period,
"clock": clock,
},
},
)
# Called whenever the score changes
update_score(28, 21, "4th", "5:32")Typical Integration: Clock Controller
For a running clock that updates every second:
const API_KEY = "lw_your_key_here";
const BASE_URL = "https://ideal-heron-677.convex.site";
const PRODUCTION_ID = "j572prod1...";
async function updateClock(clock) {
await fetch(`${BASE_URL}/api/cms/productions/live`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
productionId: PRODUCTION_ID,
data: { clock },
}),
});
}
// Update every second during live play
let seconds = 720; // 12:00
const interval = setInterval(() => {
seconds--;
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
updateClock(`${mins}:${secs.toString().padStart(2, "0")}`);
if (seconds <= 0) clearInterval(interval);
}, 1000);Validation
If the production has a liveDataSchema, all values are validated against the field definitions. For example, if homeScore is defined as a number field, passing a string value will return an error.
Productions without a schema accept any key-value pairs in live data.
Restrictions
- You cannot update live data on an archived production (returns
400) - Live data updates do not generate audit log entries (too frequent during live broadcasts)
- There is no rate limit on live data updates, but Convex applies a natural throughput limit (~100 mutations/second per production)