(06)Case studyFootball stats platform

Tallytistics

A football website where fans check live scores, league tables and every player's numbers. I built all of it, from the screens people use to the server behind them.

My role
Full-stack developer
Built with
React, Node.js, TypeScript
Premier League top scorers
The Tallytistics home page: the season's top scorers as player cards
Erling Haaland's player page on a phone
(01)In short

01

What the client wanted

One place for football fans to follow live scores, deep stats and the stories behind the numbers, without jumping between apps.

02

What I built

The whole product: the website fans use, the server behind it, and a caching system that keeps it fast and inside its data limits.

03

The result

A live site covering 732 clubs and 502 players, where a live score is never more than 15 seconds old.

clubs to follow
732clubs to follow
players with their own page
502players with their own page
transfers tracked
149transfers tracked
the oldest a live score gets
15sthe oldest a live score gets

Live numbers from the site, October 2026

(02)What I built5 highlights

Built for people who pause the tape.

That's the site's own tagline. Each highlight below says what it does for a fan, and how it works underneath.

01

Every stat, one click away.

The Stat Lab ranks the top 50 players in 12 categories, from goals and assists to expected goals and discipline. Pick a season, league or team, then click any column to sort.

For fans

Settle the argument: who really has the best numbers this season.

Under the hood

One /api/statlab endpoint, cached for 5 minutes and refreshed in the background (stale-while-revalidate).

Stat Lab filters: season, competition, team and 12 stat categories
The Stat Lab table, sorted by goals

02

A page for every player.

Click any of the 502 players for their own page: club and position, playing-style tags, how they rank against players in the same position, and the trophies they've won.

For fans

See at a glance what makes a player special.

Under the hood

Player data comes from Sportmonks through my own API, so the paid API key never reaches the browser.

Erling Haaland's player card
Percentile rankings against other attackers

03

Every match, day by day.

The scoreboard lists each day's fixtures with kick-off times and club crests. On 3 October that meant 40 FA Cup ties.

For fans

Know what's on and when, without searching.

Under the hood

Match data is cached for just 15 seconds, so live scores stay fresh without hammering the paid API.

The day's FA Cup fixtures with kick-off times
The scoreboard on a phone

04

Who's really in form.

Club power rankings score every team by points times two, plus goal difference, so form shows up faster than in the league table.

For fans

A quick read on which teams are flying and which are slipping.

Under the hood

Standings are cached for 5 minutes with stale-while-revalidate, so the table loads instantly.

Club power rankings
Power rankings on a phone

05

The story behind the numbers.

A newsroom of the latest football stories from outlets across the game, right next to the stats and filtered by competition.

For fans

Read the news without leaving the stats.

Under the hood

Stories come from the GNews API through the same backend, cached at the edge for an hour.

A news story card
A news story card
A news story card
(03)How it works

Fast, even on paid data.

The football data comes from two paid services that only allow so many requests. Asking them every time someone opens a page would be slow, and the limit would run out fast.

So my server keeps a fresh copy of each answer, like a shop that keeps popular items on the shelf instead of fetching them from the warehouse every time. Live scores are refreshed every 15 seconds; things that rarely change, like the list of leagues, once an hour.

  1. Step 1

    A fan opens a page

    React front end

  2. Step 2

    My server gets the request

    Node + Express behind Nginx, on Ubuntu

  3. Step 3

    It checks its saved copy first

    Disk cache, refreshed when a copy expires

  4. Step 4

    Only if needed, it asks the data provider

    Sportmonks and GNews, API keys kept on the server

Built withReactNode.jsExpressNginxUbuntuSportmonks APIGNews API
(04)The result

Fast pages, and live scores only seconds old.

Most requests are answered from the saved copies instead of the paid services, so the site stays fast and inside its limits, while a live score is never more than 15 seconds old.

Open to work

Have a project like this in mind?

I build complete web and mobile apps, for full-time roles or freelance work, remote in any time zone. A quick call is the fastest way to start.

I reply within a day, usually less.