SevyDevy

Guide · System design

Design a Live Cricket Score System That Survives an IPL Final

20 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

  • Good live score system design writes each ball once, then pushes copies to every phone watching that match. Push means the server sends news the moment it exists, so phones stop asking.
  • Writes are tiny and rare, a few a minute per match. Reads are huge: millions of phones want the same 1 KB scoreboard in the same second, often right after a wicket.
  • One score service numbers and saves each ball. An ordered log such as Kafka, a list of messages kept in arrival order, carries it to fan-out servers. They copy each update down connections that phones keep open.
  • Every update carries a sequence number, a counter that goes up by one, plus the full scoreboard. Phones ignore repeats and repair gaps from a short replay or a fresh snapshot, the full current scoreboard.
  • Beginners can stop after the section on polling or push. Engineers get the rest: the Kafka settings that keep a match in order, why browsers stop reconnecting after a server-busy reply, and a tested resume function.

What goes wrong when millions of phones poll for a live cricket score?

The servers drown in questions that all have the same answer. Polling means each phone asks the server again and again on a timer. This is the first problem live score system design has to solve.

Picture a common setup. A small team runs a cricket score app that shows ball-by-ball scores and one-line commentary for IPL (Indian Premier League) and international matches. On every phone, it asks the servers for the score every 5 seconds. The setup is made up, but the problem is real.

In a final, about 8 million people have the app open during the last five overs. That is 8 million divided by 5, or 1.6 million requests a second. A new ball arrives only about every 40 seconds, so almost every reply repeats what the phone already has.

This polling design is the naive version. On the big night it fails in three linked ways:

  • The score API runs out of database connections. Phones see errors and retry at once, which makes the overload worse.
  • Caches hold old copies too long. Some fans see the winning six 40 seconds after their neighbours cheer.
  • Commentary arrives out of order. A wicket shows on screen before the ball that led up to it.

The wrong idea underneath is that asking more often keeps fans fresher. The fix is the reverse: write each ball once, in one place, and push copies only to the phones that are watching.

Which words do you need before designing a live score system?

You need seven words. Each one is explained here once and used the same way in every later section.

  • Polling: the phone asks the server on a timer, whether or not anything changed.
  • Push: the server sends new data the moment it exists, without waiting to be asked.
  • Persistent connection: a network connection the phone keeps open for minutes or hours, so the server can push down it at any time.
  • Fan-out: one message copied out to many receivers.
  • Sequence number: a counter that goes up by one with every update for a match. A phone uses it to spot a missing or repeated update.
  • Snapshot: the full current scoreboard of one match. It is about 1 KB, small enough to send whole every time.
  • CDN (content delivery network): servers in many cities that keep copies of responses close to users, so most requests never reach your own servers.

How does live score system design work?

A live score system records each ball in one trusted place, then pushes copies through a layer of fan-out servers to every connected phone. Phones never read from the place where balls are written. Only a cache rebuild does.

Think of a state lottery draw. The draw happens once, in one hall, under watch. Within the hour, the winning number is chalked onto boards at thousands of roadside stalls. Buyers read the nearest stall, and nobody phones the lottery office.

Each part of the picture maps to a part of the design:

  • The draw hall is the score service: the one place where a ball becomes official.
  • The district agents and their runners are the log and the fan-out servers: they copy the result outward.
  • The stall boards are the open connections and the CDN copies that phones read.
  • The draw number written above the result is the sequence number.

Where the picture breaks: a stall board waits for a runner, but a phone's connection is already open, so a new ball arrives in about a second. Chalk is also wiped and rewritten, while every score update is a new, numbered message.

What does a live cricket score system need to do?

It needs to take in each ball, store it safely and show it on millions of phones within a couple of seconds. It must also survive sudden crowds, such as when a wicket falls in the last over.

What fans and the scoring team need

  • Take in each ball: runs, extras, wickets and one line of commentary.
  • Show the live scoreboard and ball-by-ball commentary for any match.
  • Show a home screen listing all live matches with their current scores.
  • Fix mistakes, such as four runs off the bat corrected to four leg-byes.
  • Alert fans who are not in the app about big moments. A separate notification system does this, so it stays out of scope here.

How well it must work

  • Fast: a ball reaches most phones within 2 seconds of being entered.
  • In order: a phone must never show ball 18.3 after ball 18.4.
  • Available: scores keep flowing even if the database slows down for a while.
  • Elastic: the system handles ten times the normal crowd within minutes.
  • Correct in the end: a second of delay is fine, a wrong final score is not.

Rough numbers for the next final

The team plans for 10 million connected phones at peak. Each update is a small JSON message (structured text) of about 1 KB. A ball, its commentary and the odd correction come to about 3 messages a minute per match.

Now multiply. If every phone polled every 5 seconds, that is 2 million requests a second. One ball sent to 10 million phones is about 10 GB, and sending it within 2 seconds is a burst of about 40 gigabits a second.

You can check the maths yourself. This prints each number with its unit:

python
phones = 10_000_000      # connected at peak
update_bytes = 1_000     # one scoreboard, about 1 KB
poll_every_s = 5
burst_s = 2              # target: every phone within 2 seconds

print(phones / poll_every_s, "requests a second if every phone polls")
print(phones * update_bytes / 1e9, "GB to send one update to every phone")
print(phones * update_bytes * 8 / burst_s / 1e9, "Gbit/s if sent within 2 seconds")

It prints 2000000.0 requests a second, 10.0 GB and 40.0 Gbit/s. The units are decimal, so 1 KB here means 1,000 bytes and 1 GB means a billion bytes.

So writes are tiny and reads are enormous. The database is not the hard part; the copying is.

How does a ball update travel from the stadium to millions of phones?

A ball update is entered, checked, numbered, saved and logged, then pushed to every phone watching that match. Each step has exactly one job, and only the last step deals with millions.

The app gets each ball from two places. A paid data feed from the ground is the main one. A backup scorer watches the broadcast and keys in each ball, in case the feed stalls.

Follow the writes down to the log in the diagram, then notice that phones only ever talk to the fan-out servers and the CDN.

Live score architecture for the cricket app

Writes take one narrow path to the log. Reads spread across fan-out servers and the CDN, and never reach the database directly. Phone counts are made up.

Diagram connections:

  • Ground data feed to Score service (Each ball)
  • Backup scorer app to Score service (Backup entry)
  • Score service to Match database (Save)
  • Match database to Kafka score topic (Outbox relay publishes)
  • Kafka score topic to Fan-out servers (Every server reads all)
  • Fan-out servers to Fans' phones (Push over SSE)
  • Fans' phones to CDN snapshot cache (Snapshot on open)
  • CDN snapshot cache to Snapshot API (Cache miss)
  • Snapshot API to Match database (Rebuild if cache is empty)
  • Ground data feed: Main source of every ball
  • Backup scorer app: Keyed in by hand if the feed stalls
  • Score service: Checks, dedupes and numbers each update
  • Match database: Every ball and its number, stored for good
  • Kafka score topic: Ordered log, keyed by match id
  • Fan-out servers: Hold open connections, push each update
  • Fans' phones: About 10 million at peak
  • CDN snapshot cache: Usually 1 to 2 seconds old, up to about 6
  • Snapshot API: Builds scoreboards from a fast cache

Here is one delivery moving through it: the fourth ball of the 19th over, written 18.4 in cricket.

  1. The ball is entered

    The ground feed reports four runs, driven through cover, at 18.4. A second later, the backup scorer enters the same ball.

  2. Checked and deduped

    The score service keys each delivery by match, innings, over and its position in that over. The backup copy has the same key, so it is dropped.

  3. Numbered

    The service gives the update the next sequence number for this match, say 412. Only this service hands out numbers for a match.

  4. Saved, then logged

    It writes the ball, its number and the new full scoreboard to the match database in one transaction, a group of writes that succeed or fail together. A relay then publishes that scoreboard to the Kafka score topic, keyed by match id.

  5. Pushed to phones

    Every fan-out server reads update 412 and pushes it down each open connection watching this match. Most phones show it within a second.

The key uses the position in the over, not just the label 18.4. Under Law 17 of the Laws of Cricket, only valid balls count towards the six in an over. A wide or a no-ball does not count, so two deliveries can both carry the label 18.4.

Kafka is a durable log: a list of messages kept on disk in the order they arrived. A topic is one named log, split into partitions, separate logs that share the load. Kafka's introduction says events with the same key are written to the same partition.

It also says any reader of a partition reads its events in exactly the order they were written. So the score service keys every message by match id, and every fan-out server sees ball 18.3 before ball 18.4. The engineer section below adds the two conditions this depends on.

Should a live score app use polling or push?

Use push for the live match screen and cached polling for screens that change slowly. Push gets a ball to phones in about a second. Cached polling is simpler, and a CDN absorbs nearly all of its load.

Cached polling is the naive design with one change: phones ask a CDN, not the app's own servers. The HTTP caching standard, RFC 9111, defines a shared cache: one that stores responses for reuse by more than one user. A CDN is one such cache.

The same standard defines max-age, which says how many seconds a stored response stays fresh. The team sets the home-screen match list to max-age=2. Each CDN server then goes back to the origin, the app's own server behind the CDN, about once every 2 seconds for that list.

There is a catch. When a copy expires, many phones can miss at the same moment. RFC 9111 allows a cache to combine those misses into one request to the origin, so check that your CDN does this.

A second document, RFC 5861, adds stale-while-revalidate. It lets a cache keep serving a just-expired copy for a few more seconds while it fetches a fresh one in the background. Caches may do this but are not required to, so check your CDN supports it.

To check a snapshot response, run curl -sI on its address and read two headers. You should see cache-control: public, max-age=1, stale-while-revalidate=5, and an age header of 0 or 1 while the copy is fresh. While the CDN serves a just-expired copy and refreshes it, Age can reach about 6, which is still normal. Age counts seconds since the origin made or last confirmed that copy. The exact headers depend on your CDN and origin settings.

Server-sent events for the live match screen

Server-sent events (SSE) are a web standard for one-way push. The server answers one HTTP request but keeps the response open, writing a new event whenever there is news.

Each event can carry an id field. If the connection drops, a browser's EventSource, its built-in SSE client, reconnects by itself. It sends the last id it saw in a Last-Event-ID header, so the server can send only what was missed.

A native phone app has no built-in EventSource. It uses an SSE client library, so check that yours resends the last id and obeys the retry field described later.

On the web over HTTP/1.1, the standard warns that browsers limit connections per server. Open one EventSource per tab and send every match the tab needs down it.

WebSockets are the other common choice. Under RFC 6455, a WebSocket starts as an HTTP/1.1 request that asks to upgrade, then becomes a two-way channel where either side can send at any time. That suits live chat or fan polls, but scores flow one way.

Ways to get a live score to 10 million phones, with delays and loads for the cricket app (made up)
Direct pollingCached polling via CDNServer-sent eventsWebSockets
How it worksPhone asks the origin every 5 sPhone asks the CDN every 5 sServer pushes down one long HTTP responseTwo-way channel after an HTTP upgrade
Delay for a new ballUp to 5 s, more under loadUp to about 7 s: 5 s poll gap plus 2 s cache timeAbout 1 sAbout 1 s
Origin load2 million requests a secondAbout 150 a second per cached page, if 300 CDN servers each refetch every 2 sFan-out servers onlyFan-out servers only
Catching up after a dropNext poll gets the latestNext poll gets the latestBuilt in through Last-Event-IDYou build it yourself
Use in this designNowhere any moreHome screen and fallbackLive match screenA future watch-along chat

How do you fan out one score update to millions of phones?

Split the connections across many fan-out servers, and have every server read every update from the log. One update becomes about 70 server copies, then millions of phone copies.

Back at the lottery, the office does not send runners to every stall. It gives the result to district agents, and each agent's runners chalk it onto the boards in that area. That is two-level fan-out.

The team sizes the fleet from load tests with fake clients. One fan-out server held about 200,000 mostly idle connections before memory ran short (made up). Ten million phones need 50 such servers, so the team runs 70 to leave room for failures mid-match.

At 70 servers, each holds about 143,000 phones. One update is then about 143 MB out of each server, roughly 1.1 gigabits if sent within a second. A 10-gigabit network card has room for that.

Pause and predict: should each fan-out server read only its share of the log, or all of it?

All of it. Each server reads the score topic under its own consumer group name. A consumer group is a set of readers that split a topic's partitions between them. Kafka's design docs say each partition goes to exactly one consumer in each subscribing group.

So a group with one server in it gets every partition. Seventy copies sounds wasteful, but the topic carries only a few messages a second. In return, a load balancer, the front door that spreads connections across servers, can send any phone to any server.

Two-level fan-out for one ball

One publish reaches all 70 servers. Each server copies it only into its own room for that match, and other rooms are untouched. Counts are made up.

Diagram connections:

  • Score service to Kafka score topic (Publish once)
  • Kafka score topic to Fan-out server 1 (Reads every update)
  • Kafka score topic to Fan-out server 2 (Reads every update)
  • Kafka score topic to Fan-out server 70 (Reads every update)
  • Fan-out server 1 to Final room, server 1 (Push 412)
  • Fan-out server 1 to Other match, server 1 (Its own updates only)
  • Fan-out server 2 to Final room, server 2 (Push 412)
  • Fan-out server 70 to Final room, server 70 (Push 412)
  • Score service: Publishes update 412 once
  • Kafka score topic: Final's partition, in order
  • Fan-out server 1: About 143,000 connections
  • Fan-out server 2: About 143,000 connections
  • Fan-out server 70: About 143,000 connections
  • Final room, server 1: 132,000 phones get update 412
  • Other match, server 1: 11,000 phones, untouched by 412
  • Final room, server 2: 135,000 phones get update 412
  • Final room, server 70: 128,000 phones get update 412

Inside a server, connections watching the same match are grouped into a room. A room holds the latest scoreboard and the set of connections. In the code, conn is a made-up connection object: send queues bytes without waiting, and backlog counts messages not yet delivered.

python
class MatchRoom:
    def __init__(self, snapshot):
        self.latest = snapshot          # full scoreboard with its "seq" number
        self.conns = set()              # open connections watching this match

    def join(self, conn):
        conn.send(self.latest)          # a new joiner gets the scoreboard first
        self.conns.add(conn)

    def publish(self, update):
        if update["seq"] <= self.latest["seq"]:
            return                      # a repeat or a late arrival: ignore it
        self.latest = update
        for conn in list(self.conns):
            if conn.backlog() > 20:     # too slow: cut it, the phone resyncs
                self.conns.discard(conn)
                conn.close()
            else:
                conn.send(update)

What just happened? A new joiner gets the latest scoreboard at once, so the screen fills instantly. Any update numbered at or below the latest is ignored, which makes repeats harmless.

The third choice protects everyone else. A phone on a weak signal falls behind, and the room cuts it off once 20 messages pile up. It reconnects and catches up through the resume code in the next section.

Each update carries the whole scoreboard, not only the change. At about 1 KB, sending it whole costs little. If a phone misses one update, the next one still shows the right score.

Some teams put Redis Pub/Sub between the log and the fan-out servers. Its documentation says delivery is at-most-once: a message that a subscriber misses during a disconnect is lost forever. The same page points to Redis Streams, which keep messages, when you need more.

You can see the loss on a local Redis. With no subscriber connected, redis-cli PUBLISH score:final seq412 prints (integer) 0, the number of receivers. Subscribe again and publish seq413, and only seq413 arrives. We ran this on Redis 7.0.15.

Losing a message is acceptable only because phones repair gaps, which is the next section.

How do you keep score updates in order and never miss a ball?

Give every update a sequence number and let each phone check it. A phone that sees a jump, or reconnects after a drop, catches up from a short replay list or a fresh snapshot.

What keeps one match in order inside Kafka

Keying by match id keeps a match in one partition, in order, only under two conditions. Both come from the Java client's documentation and source code at Kafka 4.3.1, the newest 4.3 release as of 19 October 2026. Other clients differ, as the last point shows.

  • The partition count must not change mid-match. With a key, the Java client's default partitioner computes a murmur2 hash, a number made from the key, and takes it modulo the number of partitions. Add partitions, and a match can move to a different log. In our run of Kafka's hash, going from 6 to 12 partitions moved 502 of 1,000 sample match ids.
  • Retries must not reorder messages. The producer docs warn that with enable.idempotence set to false and more than one request in flight, a retried send can land after a later one.
  • Idempotence means the broker, the Kafka server, drops retried copies using sequence numbers the producer sends. The Java client turns it on by default when no conflicting settings are set, so do not switch it off.
  • Check your client's defaults. The C library librdkafka 2.16.0, used by many non-Java clients, defaults to idempotence off and a CRC32 key hash. Turn idempotence on. If Java and non-Java producers share the topic, set the murmur2_random partitioner, which matches the Java hash.

How a phone checks each update

At the lottery stalls, each board shows the draw number above the winning number. A buyer can tell at a glance whether the chalk shows today's draw or last week's. The sequence number does the same job on every phone.

The app follows three rules for each update it receives:

  • The next number, such as 412 after 411: show it.
  • The same or a lower number: ignore it. It is a repeat, or it arrived late.
  • A jump, such as 415 after 411: show the new scoreboard, then fetch the missed commentary lines.

SSE makes resuming simple. The fan-out server writes the sequence number in each event's id field. After a drop, the client reconnects and sends that number back in the Last-Event-ID header.

Each fan-out server keeps the last 200 updates per match in memory. In the code below, recent_updates is a made-up helper that reads from that short list.

python
def resume(room, last_event_id):
    text = last_event_id or ""
    ok = text.isascii() and text.isdigit() and len(text) <= 12
    seen = int(text) if ok else 0       # missing or broken id counts as 0
    if seen >= room.latest["seq"]:
        return []                       # already up to date: send nothing
    missed = recent_updates(room, after=seen)   # last 200, in memory
    if missed and missed[0]["seq"] == seen + 1:
        return missed                   # short gap: replay every missed update
    return [room.latest]                # long gap: send the full scoreboard

The first three lines matter more than they look. A missing or broken id counts as zero, so the phone gets the full scoreboard, or every update so far early in a match. The length check matters too. Current Python versions refuse by default to turn a string of more than 4,300 digits into a number, and raise an error.

An unhandled error would reach the phone as an error reply. The WHATWG, the group that maintains the HTML standard, sets the rules for a browser's EventSource. Under those rules, EventSource treats any final reply other than 200 OK as the end and does not try to reconnect.

Replay is used only if the list starts right after what the phone saw. Otherwise the phone gets the full scoreboard and loads older commentary from the CDN.

To check a fan-out server, ask it to resume from update 410 with curl. The -N flag turns off buffering, so events print as they arrive:

bash
curl -N -H "Last-Event-ID: 410" https://SCORE_HOST/live/final

Our local test server printed a retry line, then events 411 and 412. On a real server, curl keeps waiting for more events until you press Ctrl+C. Each event is an id line and a data line, and a blank line ends it:

text
retry: 4200

id: 411
data: {"seq":411,"over":"18.3","score":"171/4"}

id: 412
data: {"seq":412,"over":"18.4","score":"175/4"}

What about corrections?

People keying in balls make mistakes, and umpire reviews can overturn a decision. The team never edits an old update in place. A correction goes out as a new update with a new, higher number, carrying the fixed scoreboard.

Phones just show the newest scoreboard. That ball's commentary line gets a small Corrected tag, so fans know why the total moved.

How do you handle a traffic spike when a wicket falls?

Plan for the spike before it starts. Scale up before the match, serve snapshots from the CDN, spread reconnects with random delays, and turn away extra connections instead of letting servers fall over.

A last-over wicket sends alerts out, and a million people open the app within a minute (made up). The worst spike can be self-made, though. If a fan-out server restarts, its 143,000 phones try to reconnect in the same second.

This is a thundering herd: many clients hitting one place at the same moment. The team's defences:

  • Scale before the toss. Add fan-out servers an hour before big matches, because a crowd forms faster than new servers start.
  • Snapshots from the CDN. Opening the app reads the scoreboard from the CDN with max-age=1 and stale-while-revalidate=5, so the origin sees a trickle.
  • Random reconnect delays. The SSE retry field sets the client's reconnection time in milliseconds. The team sends each phone a random value between 1,000 and 10,000.
  • Admission limits. Each fan-out server accepts connections only up to its safe limit. Extra phones fall back to cached polling and try push again later.
  • Gentle restarts. Before a deploy, a server closes its connections a few thousand at a time, never all at once.

The standard also lets a browser wait longer than the retry value, for example with exponential backoff after a failed attempt. So treat retry as the shortest wait, not an exact one.

One trap sits inside admission limits. If a full server answers an EventSource with 503 (service unavailable), the WHATWG standard says the browser fails the connection and never reconnects, as of 19 October 2026.

The web app must catch that error event, switch to cached polling and open a new EventSource later. A native app's library may behave differently, so test the 503 case on yours.

Here is what a phone does when a fan opens a match, or when its connection drops. Notice that it always has a scoreboard on screen before it tries push.

How a phone joins or rejoins a match

The fan always sees a scoreboard first. Push is preferred, a full server sends the phone to polling, and every retry waits a random delay.

Diagram connections:

  • Fan opens the match to Fetch snapshot from CDN
  • Fetch snapshot from CDN to Push server has room?
  • Push server has room? to Live over SSE (Yes)
  • Push server has room? to Cached polling (No, server full (503))
  • Cached polling to Wait a random delay
  • Live over SSE to Wait a random delay (Connection drops)
  • Wait a random delay to Push server has room? (Try push again)
  • Fan opens the match: Or a tap on a wicket alert
  • Fetch snapshot from CDN: Full scoreboard, usually 1 to 2 seconds old
  • Push server has room?: Below its safe connection limit
  • Live over SSE: Each ball within about a second
  • Cached polling: Asks the CDN every 5 seconds
  • Wait a random delay: 1 to 10 seconds, from the retry field

What can go wrong in a live score system?

Most failures come from the feed, from ordering, or from crowds. Each one needs a guard designed in early, because there is no time to build one during the last over.

  • The ground feed stalls. Guard: if no ball arrives for 90 seconds, the backup scorer's entries take over.
  • Fan-out servers fall behind the log. Guard: alert on consumer lag, the gap between the newest message and what a server has read.
  • Someone adds partitions to the score topic mid-season. Guard: fix the partition count, and change it only when no match is live.
  • A server runs out of memory. Guard: a small queue per phone, and cut off the slowest phones first.
  • Phones show an old score after reconnecting. Guard: snapshot first, then the sequence check on every update.
  • The database slows down. Guard: no phone request waits on it while the fast cache behind the CDN is warm, because the snapshot API reads that cache.

How do you explain live score system design in a system design interview?

Start from the gap between rare writes and huge reads. Then draw one narrow write path and one wide push path, and finish with ordering and spikes.

  1. Ask the questions first

    How many viewers at peak? How fresh must scores be? Which screens need push, and do users only read, or also chat?

  2. Do the rough maths

    Ten million phones, 1 KB updates, a few updates a minute. Say out loud that reads outnumber writes by millions to one.

  3. Draw the write path

    Feed and backup scorer, one score service per match handing out sequence numbers, the database with an outbox, then a log keyed by match id.

  4. Draw the push path

    Fan-out servers that each read the whole log, rooms per match, SSE to phones, and a load balancer in front.

  5. Handle order and gaps

    Sequence numbers, full scoreboards in every update, Last-Event-ID replay, and a snapshot when the gap is too long.

  6. Handle the crowd

    Scaling before the match, CDN snapshots with short cache times, random reconnect delays, admission limits and cached polling as fallback.

Questions people ask

How do live cricket score apps update so fast?
They push each ball to phones instead of waiting for phones to ask. A score service records the ball once, a log carries it to many fan-out servers, and those servers send it down connections that are already open. With this setup, most phones can show a ball within about a second of it being entered.
Is WebSocket or SSE better for a live score app?
SSE is usually the better fit, because scores only flow from server to phone. SSE runs over plain HTTP, and a browser's EventSource reconnects by itself and resends the last event id so the server can fill gaps. Choose WebSockets when phones must also send a lot, such as live chat or fan polls during the match.
How many connections can one server hold?
It depends on memory, operating system settings and how much work each message needs. Idle connections mostly cost memory, so the limit is usually set by memory per connection. Load test your own servers with fake clients, then run well below the limit you find, leaving room for a failed server's phones.
Why not just put the score API behind a CDN and poll it?
You can, and it is a sound starting point. With a cache time of a second or two, the CDN absorbs almost all requests. The cost is delay: a ball can take the poll gap plus the cache time to appear, about 7 seconds with a 5-second poll and max-age=2.
How does a live score app handle many matches at the same time?
Every message is keyed by match id, and each fan-out server groups connections into one room per match. An update for one match only touches that match's room. Matches also have separate sequence numbers, so a busy final never delays or confuses a quieter match running alongside it.
How are wicket alerts different from live score updates?
Alerts reach fans who are not in the app, through the phone's own notification service. Live updates reach fans who have the match screen open, through a connection the app holds. Alerts are fewer and can arrive a little later. Live updates must be fast and in order, so the two are usually built as separate systems.

Sources and further reading

Practise this with Lala

Practise