Skip to content
Somewhere to look

Every league gets a page fans can just open

Flip a league to public and it gets its own address at balloball.com/l/your-league — the fixtures, the table, team and player pages, and a match page that updates itself while the game is on. No account, no download, no asking in the group chat. A parent taps a link and sees the thing they came for.

Right now the answer lives in a chat thread

Somebody wants to know what time the under-14s play on Saturday, and where. Today that answer is buried in a chat thread, or in a PDF that was correct three reschedules ago, or in a post nobody can find twice. The same four questions come back every week — when, where, who won, where are we in the table — and one volunteer answers all of them by hand. When that volunteer is away, the season goes quiet. Fans are not asking for an app. They are asking for a link that is still right on Saturday morning.

How it works

Four steps, no configuration

  1. Publish the league

    A league admin flips the league to public. It gets its own address at balloball.com/l/your-league, and the fixtures, the table, team pages and match pages open to anyone holding the link. Public player stat lines and the stats tab sit behind the paid Leaderboards module rather than the base plan. Draft seasons stay invisible until somebody makes that call.

  2. Send one link

    Put the address in the team chat, on the club site, on the printed fixture card. Anyone who opens it reads the schedule, the table, team pages and player pages with no sign-up in the way, and published leagues also turn up in the public discover directory by sport and city.

  3. The game goes live

    When the scorekeeper starts the match, its match page updates the score and play-by-play on its own, with nobody reloading. The league page shows the current score and links straight through — that card is a snapshot taken when the page loads, so the match page is the one to watch.

  4. Let them keep it

    Fans can subscribe the fixtures into Apple Calendar, Google Calendar or Outlook, so a reschedule lands in their calendar instead of a new post. They can also install the page to a phone home screen from the browser, where it still shows the last public data it loaded when the signal dies in the car park.

Capabilities

What lives on the fan page

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.

16 of these are included on every plan.

  • Public league fan page (league microsite)

    Every league can publish a branded public page at balloball.com/l/<league-slug> that fans open in a browser.

    Opt-in, not automatic: a league admin must flip the league to public (POST /leagues/{id}/visibility), which auto-enables the free PUBLIC_STATS module. Only leagues in ACTIVE or COMPLETED status are served; DRAFT and soft-deleted leagues 404. An unlisted league also 404s for anonymous visitors and for signed-in non-followers — only a signed-in follower (they redeemed the join code or accepted an invite) can read it.

  • No account and no app download needed to view a fan page

    Fans can open a public league page, its standings, schedule, teams, players and individual match pages in any web browser without creating an account or installing anything.

    Following a league/team/player, the personalised feed, notifications, loyalty and ticket wallet all require a signed-in account.

  • Live match page with auto-updating score

    Anyone with a match link can open a live match page that updates the score and play-by-play automatically while the game is in progress, without signing in.

    Updates use HTTP long-polling (the server holds the request open for up to 8 seconds and returns a batch), not WebSockets or server-sent events — API Gateway buffers responses so true streaming is not available. Polling stops once the match is FINAL, CANCELED or POSTPONED; alongside the stream the page refetches the score every 4 seconds, backing off to 20 seconds while the long-poll is healthy.

  • Live scores on the league fan page itself

    The league fan page shows the current score of a live game and links straight through to the auto-updating full match page.

    The score cards on /l/<slug> have no refetch interval and the app-wide default is staleTime 2 minutes with refetchOnWindowFocus disabled — so the fan page score is a snapshot that refreshes on navigation/reload, not a continuously ticking scoreboard. Continuously updating scores come from the linked match page at /matches/<id>/live, which long-polls the event stream and is reachable without signing in.

  • Public schedule / fixtures

    A published league's fixture list and upcoming games are readable on its public fan page without signing in.

    Gated on the league's SCHEDULING module (FREE tier, default on) plus the PUBLIC_STATS anonymous-read gate.

  • Public standings table

    Anonymous fans can read a published league's standings table on its fan page.

    Gated on the league's STANDINGS module. STANDINGS is a FREE-tier module that is enabled by default (backend/prisma/seed.ts:88), but a league admin can turn it off, in which case the tab disappears and the anonymous read returns an empty list.

  • Public team pages with roster

    Each team in a published league has a public page with its record, schedule and roster.

    Roster names are only returned when the league admin has enabled showRosterNames; with it off, teams render without player names (a deliberate youth-privacy control). Gated on the TEAMS module and the league's public/PUBLIC_STATS gate.

  • Public player pages with game log and season stats

    Players in a published league get a public profile page showing season stats and a per-game log.

    Same public-league + PUBLIC_STATS gate as the rest of the fan surface; a private or DRAFT league's players 404 for anonymous visitors.

  • Calendar subscription for schedules (iCal / webcal)

    Fans can subscribe a league, team, venue or single match schedule into Apple Calendar, Google Calendar or Outlook, and reschedules flow through to their calendar.

    Public feeds honour the same public-league gate; private league feeds return 401 in the fan's calendar client. Each feed returns a sliding window of the last 90 days plus the next 365 days, capped at 1000 events.

  • Installable web app (PWA) with offline reading of public data

    BallOBall installs to a phone's home screen as a progressive web app and, once installed, still shows the last-loaded public league data when the device is offline.

    This is a browser-installed PWA (Add to Home Screen), not an app-store download. The offline cache is NetworkFirst and covers GET requests under /public/* only — authenticated and tenant-scoped data is never persisted to the device.

  • Join a private league with a code

    A league can hand fans an 8-character code that unlocks its page, including for leagues that are not listed publicly.

    Rate-limited to 30 attempts per minute per IP. Redeeming persists a durable follow only for a signed-in caller; an anonymous redeemer gets the league details for that session but no saved membership.

  • Followers can read an unlisted league

    A league can stay off the public directory and still give its own followers full access to scores, standings and match pages via a join code or invitation.

    Requires the fan to be signed in and to hold a follow row; anonymous visitors still get a 404 for an unlisted league.

  • Discover directory of public leagues

    A public /discover page lets anyone browse and search published leagues by name, city and sport.

    Lists only leagues that are ACTIVE, published, and have the PUBLIC_STATS module on; the query returns at most 100 leagues (take: 100) with no pagination. The 'code-gated' filter chip reads a `visibility` field the public API does not return, so that filter yields an empty grid — and so does the 'public' chip for the same reason; only the 'all' chip shows the directory.

  • League news and announcements on the fan page

    Leagues can post news and announcements that appear on their public fan page.

    Gated on the FAN_NEWS module (FREE tier, defaultEnabled true); a league admin can switch it off.

  • League branding on the fan page (logo, header image, colours, font)

    A league's logo, header image, brand colours and web font are applied to its public fan page.

    Branding falls back through club and tenant defaults; a league that has not set colours renders the platform defaults.

  • Roster-name privacy control for youth leagues

    A league admin can hide player names from the public fan pages with a single setting, and the public API then omits them.

    A per-league toggle; it is not a per-player consent flow and it does not retroactively remove names from anything already cached by a third party.

Questions

Before you ask

Do fans need an account to read any of this?

No, not to read. The league page, the schedule, the standings, team and player pages and the live match page all render for an anonymous visitor. An account only matters when a fan wants to follow leagues, teams and players and get a personalised feed of their own — the reading is open to anyone with the link.

Is there an app to download from the App Store?

No, and this page will not pretend otherwise. BallOBall has no native listing in the App Store or the Play Store. What fans get is the web page, which can be installed to a phone home screen through the browser's own Add to Home Screen — it opens full-screen and keeps the last-loaded public league data readable when the device is offline. If your fans specifically expect a store download, that is a thing BallOBall does not do.

We do not want the league listed publicly. Parents still need it.

A league can stay off the discover directory and hand out an eight-character join code that opens its page. A signed-in fan who redeems the code keeps that access and gets the whole fan surface afterwards — scores, standings, match pages — while the league stays out of the public directory. An anonymous redeemer sees the league for that session but nothing is saved for them.

Does the league page show live scores as they happen?

The match page does. Open a game in progress and the score and play-by-play update themselves while it runs. The score card on the league page itself is a snapshot — correct when the page loads, refreshed when a fan navigates or reloads, not a ticking scoreboard. Point people at the match link for a game they are actually following.

We run youth sport. Can we publish results without publishing children's names?

Yes. Roster names sit behind a per-league setting. With it off, team pages still show records and schedules but no player names, and the public API omits them as well. It is one toggle for the whole league rather than a per-player consent flow, and it cannot pull back anything a third party has already copied or cached.

Can the page look like our league instead of like BallOBall?

Your logo, header image, brand colours and web font are applied to the fan page, and a league can publish its own extra pages — an About page, a sponsors page — alongside the standard tabs. Two further steps are paid add-ons rather than part of the base plan: removing the BallOBall name from the browser title, and pointing your own domain at the page. The custom-domain piece also needs the edge routing configured before it can be provisioned.

Publish your league page

Public leagues need no account to open.