Skip to content
At the table

Score the game the way the game is actually played

A basketball game is not a cricket innings and neither is a curling end. BallOBall ships a different scorekeeper console for each of its 23 sports, tuned to that sport’s own events, period structure and discipline rules — so the person at the table taps what just happened instead of translating it into someone else’s data model.

The paper book was never the problem. Retyping it was.

Most leagues score on paper because the software fights them: a generic “add points” box that cannot express a wicket, a bonus situation, or a bowling frame. So the book gets kept by hand, then typed up afterwards — and until somebody types it, the standings are wrong, the fans have nothing to look at, and the stats do not exist. Score it once, in the right shape, and everything downstream stops being a chore.

How it works

Four steps, no configuration

  1. Pick the match

    The console for a match is chosen from that match’s sport automatically. Nobody configures a scoring template.

  2. Tap what happened

    Each sport has its own event buttons — a try and conversion, a wicket, a spare, a set won — and the server rejects anything that sport does not recognise.

  3. Keep going offline

    If the venue Wi-Fi drops the taps keep landing in a durable on-device queue, then send themselves in order when the signal returns.

  4. Close the book

    Ending the game locks it. The server refuses further scoring events, so the official result cannot move afterwards.

Capabilities

What the console does

Everything below is built and running today. Unbadged items are included on every plan; a badge means the capability needs a module added to your plan, a higher plan tier, or a piece of setup finished first.

14 of these are included on every plan.

  • Sport-aware scorekeeper console for 23 sports

    BallOBall ships a scorekeeper console for every one of its 23 supported sports, and the console for a given match is selected automatically from that match's sport.

    Twenty-two sports render a dedicated sport-pack console; basketball uses the original ScorekeeperPage (frontend/src/sports/basketball/slots.ts:9 deliberately ships no console slot). The route is role-gated to SUPER_ADMIN, PLATFORM_SUPPORT, LEAGUE_ADMIN and SCOREKEEPER — coaches, players and fans cannot open it.

  • Sport-specific one-tap event capture

    Each sport declares its own event catalogue — soccer records goals, own goals, cards, corners, offsides and shootout kicks — and the server rejects any event type the match's sport does not recognise.

    Which events exist, and how many, differs per sport; there is no single universal event set. Event capture is refused when the league's LIVE_SCORING module is switched off (backend/src/handlers/matchHandler.ts:900).

  • Offline-tolerant scoring with a durable queue

    If the connection drops mid-game the scorekeeper keeps tapping: events are written to a durable on-device queue that survives closing the tab, and they are sent in order automatically when connectivity returns.

    The queue protects events captured after the console has loaded. The service worker caches only public read endpoints, never authenticated data (frontend/src/pwa/runtimeCaching.ts:7), so a console cannot be opened cold with no connectivity. Deterministic failures — a 4xx — mark the queued row errored and surface it to the operator instead of retrying forever, and a write that cannot reach IndexedDB at all rejects rather than silently dropping the event.

  • Duplicate-proof event replay (idempotency)

    Every scoring tap carries a unique key, so an event re-sent after a dropped connection is matched to the record that already exists rather than being counted a second time, and two browser tabs on the same device are serialised by an origin-wide lock.

    Protection is per logical tap; it does not reconcile two different operators independently scoring the same match.

  • Server-backed undo of a recorded event

    Any recorded event can be undone from the play-by-play log; the server deletes the event and reverses its score and timeout effects in the same database transaction.

    On a match already marked FINAL, undo is refused unless the caller is platform staff (SUPER_ADMIN / PLATFORM_SUPPORT) — a scorekeeper must ask for the match to be reopened. Archived leagues are read-only.

  • Correcting a recorded event in place

    A mis-recorded event can be retyped or reassigned to a different player without deleting and re-entering it.

    The edit control only appears on rows that have already synced to the server; unsynced rows must be undone locally. Editing an event on a FINAL match is restricted to platform staff.

  • Finalized-match lock ("book closed")

    Once a scorekeeper ends the game, the server refuses any further scoring events on that match, so the official result cannot be moved after the book is closed.

    Reopening a finalized match to score again is restricted to platform staff. The End-game dialog warns when locally queued events are still syncing, but finalizing is not blocked on the queue draining.

  • Timeouts, fouls, cards and timed suspensions

    Consoles track the discipline model each sport actually uses — team timeouts that decrement, personal fouls and foul-outs, yellow and red cards with send-offs, and timed temporary suspensions that count down and return the player automatically.

    Which of these apply is per sport; not every sport has timeouts, and several sports (basketball, American football, flag football, handball) use bespoke timeout controls with their own budget rules rather than the shared one.

  • Per-player attribution and shot/location capture

    Events can be attributed to the individual player who made them, and a scoring event can carry a court or field location that feeds shot charts and event maps.

    Location capture is an optional annotation on an already-recorded event, not automatic tracking.

  • Live play-by-play log with running score, rehydrated after reload

    The console shows a running play-by-play with the score after each event, and the log is rebuilt from the server when the console is reloaded or reopened, so undo and correction stay available after a refresh.

  • In-console live box score

    Operators can open a live box score inside the scoring console itself, rendered in each sport's own statistical format, without leaving the console.

  • Keyboard shortcuts for fast capture

    Scorekeepers working on a keyboard can record events with keyboard shortcuts, with an in-console shortcut reference and an on/off toggle.

    Opt-in per operator via the toggle.

  • Installable tablet/phone console (PWA)

    The scorekeeper console installs to a tablet or phone home screen and runs full-screen without browser chrome.

    The dedicated phone-first render tree with screen wake-lock exists for the basketball console only (frontend/src/pages/app/ScorekeeperMobilePage.tsx:170); other sports use their pack console's responsive layout. Installation is a web app install from the browser, not an app-store download.

  • Live win-probability readout

    Live matches carry an in-game win-probability readout computed from the score margin and how much of the game remains.

    A heuristic logistic model computed on read, not a trained or back-tested one. Per-sport scale constants are hand-set and most sports share a single default because there is no calibration data (backend/src/services/liveWinProbabilityService.ts:24). No accuracy claim is made, and the number is never stored — it is recomputed from the match row on every read.

Questions

Before you ask

Does the scorekeeper need to install an app?

No. The console runs in the browser and can be installed to a tablet or phone home screen so it opens full-screen without browser chrome. There is nothing to fetch from an app store.

What happens when the gym Wi-Fi drops mid-game?

Scoring continues. Events are written to a durable on-device queue that survives closing the tab, and they are sent in order once the connection returns. Each tap carries a unique key, so an event re-sent after a dropped connection is matched to the record that already exists instead of being counted twice.

Someone recorded the wrong thing. Can we fix it?

Yes, two ways. Any event can be undone from the play-by-play log — the server deletes it and reverses its score and timeout effects in the same transaction — or it can be retyped or reassigned to a different player in place, without deleting and re-entering it.

Can two people score the same match at once?

The console detects a concurrent write rather than silently overwriting, so a second tablet or a second browser tab cannot quietly clobber the first one’s work.

How quickly do fans see the score?

The broadcast overlay is driven by a WebSocket push, so it follows the scorekeeper directly rather than checking on a timer. Public fan pages refresh themselves in the background — fans do not pull to reload, but the fan page is a periodic refresh, not the same instant push the overlay gets.

Hand a tablet to your table crew

Public leagues need no account to open.