LoL Esports Webhooks: Stop Polling Live Matches

Why polling LoL live matches burns rate limits — and how Cito LoL webhooks deliver gold swings, objectives, and live state to your app.

Author:
Cito Team

The Polling Trap

A live match center that hits /lol/live every 3–5 seconds looks fine in demos. In production it:

  • Burns your rate limit during LCS/LEC nights
  • Still lags between polls
  • Scales poorly when you track many matches

Webhooks flip the model: Cito pushes events when something changes.

What LoL Webhooks Cover

One Game Starter (and above) includes LoL-scoped live webhooks for events like:

  • Live state updates
  • Gold swings (lol.live.gold_swing)
  • Objectives (lol.live.objective)
  • Kills and related live signals

Always pre-check coverage before relying on live-state delivery:

bash
curl -H "x-api-key: cito_live_your_key" \  https://api.citoapi.com/api/v1/lol/matches/lol-match-116520394663535912/coverage

Or inspect the matrix:

bash
curl -H "x-api-key: cito_live_your_key" \  https://api.citoapi.com/api/v1/lol/coverage

Create a Webhook

  • Open Dashboard → Webhooks
  • Create webhook → set your HTTPS URL
  • Subscribe to LoL live events
  • Save the webhook secret (shown once)
  • Example subscription shape:

    JSON
    {  "events": ["lol.live.gold_swing", "lol.live.objective"],  "filters": {    "league": "LCS",    "matchId": "lol-match-115564793879469312",    "gameId": "115564793879469313",    "side": "red"  }}

    Filters let you scope by league, match, game, or side so you don't process every event globally.

    Example Payload

    JSON
    {  "id": "1c11131a-2d74-4b06-b4be-ec873861854b",  "event": "lol.live.gold_swing",  "timestamp": "2026-06-01T15:42:12.647Z",  "data": {    "matchId": "lol-match-115564793879469312",    "gameId": "115564793879469313",    "league": "LCS",    "gameTime": 1716,    "source": "vision",    "previousGoldDiff": -1900,    "goldDiff": -3300,    "swing": -1400,    "leadingSide": "red"  }}

    Use id / X-Cito-Event-Id as your dedupe key.

    Receive + Verify (Node)

    JavaScript
    import express from "express";import crypto from "crypto"; const app = express();app.use(express.raw({ type: "application/json" })); function verifySignature(rawBody, signature, secret) {  const expected = crypto    .createHmac("sha256", secret)    .update(rawBody)    .digest("hex");  return crypto.timingSafeEqual(    Buffer.from(signature || ""),    Buffer.from(expected)  );} app.post("/webhook", (req, res) => {  const signature = req.header("X-Cito-Signature") || "";  const ok = verifySignature(req.body, signature, process.env.CITO_WEBHOOK_SECRET);   if (!ok) return res.status(401).send("invalid signature");   const event = JSON.parse(req.body.toString("utf8"));  // enqueue work — respond fast  console.log(event.event, event.data?.goldDiff);  res.status(200).send("OK");});

    Confirm the exact signature header name in the webhook docs.

    Delivery + Retries

    • Up to 3 delivery attempts
    • 10s request timeout
    • X-Cito-Delivery-Attempt on retries
    • Pause / edit / test from the dashboard when failures pile up

    Polling vs Webhooks (When to Use Each)

    Use casePrefer
    Scoreboard that must update on gold/objectivesWebhooks
    One-off "is anything live?" checkGET /lol/live
    Historical match statsREST
    Building a first prototypeShort poll OK, then migrate

    Next Steps

    • Verify signature handling against the live docs
    • Add a Next.js Route Handler receiver
    • Move your match center off the poll loop
    • Upgrade to One Game Starter if you need LoL live webhooks

    Start building with esports data today

    Free tier available. Same API shape across Call of Duty, Fortnite, LoL, Dota 2, and more.