Skip to content

About

Scrape SofaScore live scores, fixtures, match stats, lineups with player ratings, xG shot maps, league tables, season player leaderboards, players, teams and rankings as clean JSON or CSV - CLI + Python library via the ScrapeUnblocker API.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SofaScore Scraper

CI Python 3.9+ License: MIT Powered by ScrapeUnblocker

Scrape SofaScore sports data into clean JSON or CSV: live scores, fixtures and results, match statistics, lineups with player ratings, xG shot maps, league tables, season player stats, player and team profiles, and rankings. Get every match in play right now for football, basketball, tennis or any other sport SofaScore covers, or leave watch running to get kick-offs, goals, period changes and final results as they happen. List fixtures and results by date, round, team or season. For a single match you get the score by period, venue, attendance, referee and managers, plus SofaScore's team statistics (possession, xG, shots, passes, duels...), both lineups with formations, ratings and per-player match stats, every incident (goals with assists, cards, substitutions) and the shot map with xG, xGOT and pitch coordinates. Pull league tables (total, home or away), season leaderboards with any statistic, per-game or per-90 values and position, team or appearance filters, player profiles with market value and season stats, squads, and FIFA, UEFA, ATP and WTA rankings.

Powered by ScrapeUnblocker: the getPageSource API fetches the same JSON endpoints the sofascore.com site loads, and this package turns their responses into typed records. You don't need a SofaScore account, cookies, proxies, a headless browser or retry logic of your own.

Features

  • Live scores. Every match in play for a sport, with the score, the score by period and the match minute (football). Filter by tournament or team.
  • Live watcher. watch polls the live feed and prints one JSON line per change: kickoff, score, status (half-time, second half, ...) and final (the match left the live feed; it is fetched once to report the final score).
  • Fixtures and results. By UTC date for a tournament or a country, by round (matchday), or as a team's or a season's latest results / upcoming fixtures (30 per page, as many pages as you ask for, de-duplicated).
  • Match details. Score, score by period, extra time, penalty shoot-out and aggregate, winner, venue and capacity, attendance, referee, managers and the sofascore.com URL.
  • Team statistics. Every statistic SofaScore shows (possession, expected goals, big chances, shots inside/outside the box, passes, long balls, duels, tackles, saves, ...) for the full match and each half, as display text and as numbers.
  • Lineups. Formations, starters and substitutes, captain, shirt numbers, rating, minutes, goals, assists, xG, xA and every per-player match statistic SofaScore records, plus injured and suspended players with the reason and expected return date.
  • Incidents. Goals with assists and the running score, yellow and red cards (manager cards included), substitutions (injury subs flagged), added time and period ends, in match order.
  • Shot maps. Every shot with minute, outcome (goal, save, miss, block, post), situation, body part, xG, xGOT, shooter coordinates, goal-mouth location and goalkeeper.
  • Head-to-head. Previous results between the two teams and the two managers.
  • League tables. Total, home or away; position, played, won, drawn, lost, goals, goal difference, points and the promotion / relegation zone. Group stages (World Cup, ...) return every group's table, named in group.
  • Season leaderboards. SofaScore's player statistics for a season: the five stat groups (summary, attack, defence, passing, goalkeeper) or any statistics you name, sorted by any of them, as totals, per game or per 90 minutes, filtered by position, team and minimum appearances, 100 players per request.
  • Players. Profile (position, detailed positions, shirt number, height, preferred foot, date of birth, age, nationality, team, contract end, SofaScore's market value estimate), every season with statistics, and the full statistics for any tournament season.
  • Teams and squads. Team profile (country, league, manager, venue, founding date) and the squad with positions, ages, nationalities and market values.
  • Rankings. FIFA, UEFA country coefficients, ATP and WTA.
  • Discovery. Search teams, players and tournaments; list a sport's countries and their competitions; built-in aliases for popular competitions (premier-league, laliga, champions-league, nba, ...).
  • IDs or URLs. Every command takes SofaScore IDs or the sofascore.com page URL.
  • Output as JSON, JSON Lines, CSV (Excel-friendly) or a terminal table.
  • Robust: retries throttled, blocked or timed-out requests with backoff, refetches a response that is not JSON, and returns empty sections when a match has no data for them.

Install

git clone https://github.com/ScrapeUnblocker/sofascore-scraper.git
cd sofascore-scraper
pip install .

Get an API key at scrapeunblocker.com and put it in the environment (or in a .env file, see .env.example):

export SCRAPEUNBLOCKER_KEY=your_key_here

Python 3.9 or newer. The only dependency is the official scrapeunblocker SDK.

CLI usage

# Every football match in play right now (or basketball, tennis, ice-hockey, ...)
sofascore-scraper live
sofascore-scraper live --sport basketball -f json

# Stream kick-offs, goals, period changes and final scores (JSON Lines)
sofascore-scraper watch -t premier-league -t champions-league --interval 60

# Fixtures and results
sofascore-scraper matches -t premier-league --date today
sofascore-scraper matches -t premier-league --round 9
sofascore-scraper matches --team 42 --results --pages 2
sofascore-scraper matches -t laliga --fixtures -f csv -o laliga-fixtures.csv

# One match: details + statistics, lineups and incidents (JSON), or every section
sofascore-scraper match 16363891
sofascore-scraper match 16363891 -i all
sofascore-scraper match 16363891 16363902 -f csv -o matches.csv   # one row per match

# The parts of a match as tables or CSV
sofascore-scraper stats 16363891
sofascore-scraper lineups 16363891 -f csv -o player-stats.csv
sofascore-scraper lineups 16363891 --missing
sofascore-scraper incidents 16363891 --type goal
sofascore-scraper shotmap 16363891 -f csv -o shots.csv

# League table (total / home / away), current or any season
sofascore-scraper standings premier-league
sofascore-scraper standings serie-a --table home --season 25/26
sofascore-scraper seasons premier-league

# Season leaderboards
sofascore-scraper leaderboard premier-league
sofascore-scraper leaderboard premier-league -g attack --per per-90 --min-apps 5
sofascore-scraper leaderboard bundesliga --fields goals,expectedGoals,assists --order goals \
    --position F -n 20 -f csv -o strikers.csv

# Players and teams
sofascore-scraper player 934235 -t premier-league
sofascore-scraper player https://www.sofascore.com/football/player/declan-rice/856714 --seasons
sofascore-scraper team 42 --squad
sofascore-scraper squad 42 --position F

# Rankings, search and discovery
sofascore-scraper rankings fifa -n 20
sofascore-scraper rankings atp
sofascore-scraper search "bukayo saka" --type players
sofascore-scraper tournaments --country Spain
sofascore-scraper aliases

Common options: -f json|jsonl|csv|table, -o FILE, --proxy-country, --retries N and -v (log each request to stderr). --season takes a season year as SofaScore writes it (25/26, 2025/26, 2026) or a season ID; the default is the current season. Run sofascore-scraper <command> --help for every option.

Library usage

from sofascore_scraper import SofascoreScraper

sofa = SofascoreScraper()  # reads SCRAPEUNBLOCKER_KEY

# Live scores
for m in sofa.live("football"):
    print(m.tournament, m.home_team, m.score, m.away_team, m.minute)

# League table and recent results
table = sofa.standings("premier-league")
results = sofa.team_matches(42, "last", pages=2)  # Arsenal, newest first
round_9 = sofa.round("premier-league", 9)
today = sofa.scheduled("today", tournament="laliga")

# A full match
game = sofa.match(16363891, ["statistics", "lineups", "incidents", "shotmap", "h2h"])
game.stat("expectedGoals")  # (1.96, 0.63)
best = max(game.players(), key=lambda p: p.rating or 0)
goals = [i for i in game.incidents if i.type == "goal"]
big_chances = [s for s in game.shots if (s.xg or 0) > 0.3]

# Season leaderboard: forwards with 5+ appearances, goals per 90
top = sofa.leaderboard(
    "premier-league",
    fields=["goals", "expectedGoals", "minutesPlayed"],
    order="-goals",
    accumulation="per-90",
    positions=["F"],
    min_appearances=5,
    limit=20,
)

# Player profile with this season's league statistics
saka = sofa.player(934235, tournament="premier-league")
saka.market_value, saka.season_stats.statistics["rating"]

# Live watcher (runs until interrupted, or until max_polls)
for update in sofa.watch(tournaments=["premier-league"], interval=60):
    print(update.kind, update.match.home_team, update.match.score, update.match.away_team)

Every record is a dataclass with to_dict(); sofascore_scraper.write(records, "csv", path) and to_csv_file(records, path) save any list of them.

Examples

Example output

sofascore-scraper live -n 5:

id        start (UTC)       status          tournament                                    home                 score  away
16318018  2026-11-01 03:10  1st half 18'    Liga MX, Apertura                             Club América         0-0    CD Toluca
15171751  2026-11-01 01:30  2nd half 90+4'  MLS                                           Colorado Rapids      2-4    Chicago Fire
17200581  2026-11-01 03:00  Started         Fraser Valley Soccer League Championship - A  Akal Pacific United  0-0    Mission SC
17200617  2026-11-01 03:15  Started         Fraser Valley Soccer League Championship - A  GVU Punjab           0-0    RHO FC B
17438693  2026-11-01 02:20  Started         Knockout Cup                                  Avatiu FC            1-0    Matavera-Ngatangiia FC

sofascore-scraper live --sport tennis -n 3:

id        start (UTC)       status   tournament         home              score  away
17377213  2026-11-01 03:00  1st set  Tokyo              Leylah Fernandez  0-0    Diana Shnaider
17452141  2026-11-01 03:25  1st set  Hong Kong          Himeno Sakatsume  0-0    Elena Pridankina
17377176  2026-11-01 02:25  2nd set  Queretaro, Mexico  Bianca Andreescu  1-0    Carole Monnet

sofascore-scraper standings premier-league:

#   team                    P  W  D  L  GF  GA  GD   Pts  zone
1   Manchester City         9  7  0  2  20  10  +10  21   Champions League
2   Arsenal                 8  7  0  1  13  5   +8   21   Champions League
3   Brighton & Hove Albion  9  6  1  2  24  7   +17  19   Champions League
4   Chelsea                 9  5  1  3  19  15  +4   16   Champions League
5   Liverpool FC            8  4  3  1  11  8   +3   15   Europa League
6   Brentford               9  3  5  1  16  9   +7   14

sofascore-scraper matches --team 42 --results -n 3:

id        start (UTC)       status  tournament             home               score           away
17118366  2026-10-27 20:00  AP      EFL Cup                Fleetwood Town     1-1 (pens 5-3)  Arsenal
16363891  2026-10-24 14:00  Ended   Premier League         Arsenal            2-0             Everton
16938859  2026-10-21 19:00  Ended   UEFA Champions League  FC Bayern München  2-2             Arsenal

sofascore-scraper leaderboard premier-league --fields goals,expectedGoals,assists,minutesPlayed --order goals --position F --min-apps 5 -n 5:

#  player           team             statistics
1  Erling Haaland   Manchester City  goals=9 expectedGoals=6.57 assists=0 minutesPlayed=800
2  Alexander Isak   Liverpool FC     goals=6 expectedGoals=4.27 assists=0 minutesPlayed=571
3  João Pedro       Chelsea          goals=5 expectedGoals=3.03 assists=3 minutesPlayed=521
4  Nicolas Jackson  Aston Villa      goals=5 expectedGoals=2.31 assists=0 minutesPlayed=641
5  Evanilson        Bournemouth      goals=4 expectedGoals=3.59 assists=4 minutesPlayed=757

sofascore-scraper match 16363891 -i all (trimmed):

{
  "match": {
    "id": 16363891,
    "sport": "football",
    "tournament": "Premier League",
    "tournament_id": 17,
    "season": "Premier League 26/27",
    "round": 8,
    "start_time": "2026-10-24T14:00:00Z",
    "status": "finished",
    "home_team": "Arsenal",
    "away_team": "Everton",
    "home_score": 2,
    "away_score": 0,
    "home_periods": [1, 1],
    "away_periods": [0, 0],
    "winner": "home",
    "url": "https://www.sofascore.com/football/match/everton-arsenal/RY#id:16363891"
  },
  "venue": "Emirates Stadium",
  "venue_city": "London",
  "venue_capacity": 60704,
  "attendance": 60207,
  "referee": "Tony Harrington",
  "home_manager": "Mikel Arteta",
  "away_manager": "David Moyes",
  "statistics": [
    {"period": "ALL", "group": "Match overview", "key": "ballPossession", "name": "Ball possession",
     "home": "58%", "away": "42%", "home_value": 58, "away_value": 42}
  ],
  "incidents": [
    {"type": "goal", "detail": "regular", "minute": 7, "side": "home", "player": "Ezri Konsa",
     "assist": "Viktor Gyökeres", "home_score": 1, "away_score": 0}
  ],
  "shots": [
    {"side": "home", "team": "Arsenal", "player": "Declan Rice", "minute": 4, "outcome": "block",
     "situation": "assisted", "body_part": "right-foot", "xg": 0.0412, "xgot": 0, "x": 18.1,
     "y": 65.8, "goalkeeper": "Jordan Pickford"}
  ],
  "h2h": {"home_wins": 7, "draws": 2, "away_wins": 1, "manager_home_wins": 9, "manager_draws": 3,
          "manager_away_wins": 2},
  "sections": ["statistics", "lineups", "incidents", "shotmap", "h2h"]
}

python examples/match_report.py 16363891:

Premier League - 2026-10-24T14:00:00Z
Arsenal 2-0 Everton  (Ended)
at Emirates Stadium, London - attendance 60207
 Possession: 58 - 42
         xG: 1.96 - 0.63

Goals
      7'  Ezri Konsa (assist Viktor Gyökeres)  1-0
     68'  Gabriel Magalhães (assist Ben White)  2-0

Best rated
     9  Gabriel Magalhães (Arsenal)
   8.2  Declan Rice (Arsenal)
   8.1  Ezri Konsa (Arsenal)
     8  Martin Ødegaard (Arsenal)
   7.7  Ben White (Arsenal)

Shot map
  Arsenal: 20 shots, 1.96 xG
  Everton: 8 shots, 0.63 xG

How it works

The sofascore.com site is a single-page app that loads its data from JSON endpoints under https://www.sofascore.com/api/v1/ (/event/<id>, /event/<id>/lineups, /unique-tournament/<id>/season/<id>/standings/total, /player/<id>, ...). The scraper asks ScrapeUnblocker's getPageSource for those URLs, decodes the JSON and maps it to dataclasses, so it does not depend on page layout or CSS classes.

A few things worth knowing:

  • Requests. One request per endpoint. match makes one request plus one per section (statistics, lineups and incidents by default; -i all adds shotmap and h2h, --basic skips them). Commands that need the current season look it up once per run. watch makes one request per poll, plus one for each match that finishes.
  • Dates. --date is a UTC date. SofaScore's daily list covers every time zone, so it includes matches from the evening before; the scraper keeps the ones that start on the date you asked for.
  • Scores. home_score / away_score leave out a penalty shoot-out; the shoot-out goals are in home_penalties / away_penalties (shown as 1-1 (pens 5-3)).
  • Match minute. minute is worked out from the time the current half started, the way the site's clock is. It is set for a running half (or extra-time period) of a football match, and it is as fresh as the request.
  • Coverage varies. Top competitions have statistics, lineups, player ratings and shot maps; smaller ones may have only the score. A section SofaScore has no data for comes back empty, not as an error.
  • Leaderboard statistics are SofaScore's own keys (goals, expectedGoals, assists, keyPasses, tackles, saves, rating, ...). Run a stat group once to see the names, or read them from a player's season_stats. A name SofaScore does not know returns no values (the scraper logs a warning).
  • Market values are SofaScore's estimates (usually in EUR), not transfer fees.
  • Manager cards are incidents with is_manager: true; SofaScore stores their minute separately, and the scraper uses it.

Please scrape responsibly: keep request rates and watch intervals modest, respect SofaScore's terms, and use the data for research, analysis and personal projects.

Project layout

sofascore-scraper/
├── src/sofascore_scraper/
│   ├── __init__.py      # public API and __version__
│   ├── scraper.py       # SofascoreScraper: fetch + retries, matches, standings, players, watch
│   ├── parsing.py       # SofaScore JSON -> Match / MatchDetails / Shot / StandingRow / ...
│   ├── models.py        # dataclasses with to_dict / to_row / table layouts
│   ├── urls.py          # API endpoints, sofascore.com URLs, ID and date parsing
│   ├── options.py       # stat groups, rankings, search scopes, tournament aliases
│   ├── export.py        # JSON / JSONL / CSV / table output
│   └── cli.py           # sofascore-scraper command
├── examples/            # league table, match report, shot dataset, live goal alerts
├── tests/               # offline tests with a mocked client (no API credit used)
├── pyproject.toml
├── Makefile
└── .github/workflows/ci.yml

Development

pip install -e ".[dev]"
make lint      # ruff check + ruff format --check
make test      # pytest, offline
make format    # ruff format

The tests use synthetic responses shaped like SofaScore's and a fake client, so they run without an API key or network access.

Links

License

MIT - Copyright (c) 2026 ScrapeUnblocker. This project is not affiliated with or endorsed by SofaScore.

About

Scrape SofaScore live scores, fixtures, match stats, lineups with player ratings, xG shot maps, league tables, season player leaderboards, players, teams and rankings as clean JSON or CSV - CLI + Python library via the ScrapeUnblocker API.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages