TacosScore - football analytics from Sofascore. Typed models, DataFrames, and rate-limited API access for analysts.
Project description
TacosScore
Football analytics from Sofascore — typed Python models, pandas DataFrames, rate-limited HTTP access, and a full CLI for analysts and developers.
PyPI · GitHub · API Reference · MIT License
Author: Md. Tariquzzamana
Version: 0.1.0
Python: 3.9+
Disclaimer: TacosScore is not affiliated with Sofascore. The Sofascore API is undocumented and may change without notice. Use responsibly for research and personal analysis. See Operational considerations.
Table of contents
- Why TacosScore?
- Features
- Installation
- Quick start
- World Cup 2026 extraction example
- Finding matches and IDs
- Client configuration
- API methods reference
- Full-match pipeline
- Data models
- Player statistics
- Pandas and DataFrames
- Analytics extraction
- Coordinate systems
- Command-line interface
- Interactive help
- Async client
- Serialization and export
- Exceptions
- Project structure
- Development and testing
- Operational considerations
- License
Why TacosScore?
Sofascore exposes rich match data — xG, shot maps, heatmaps, action streams, ~60 per-player stats — but the API is reverse-engineered, JSON-heavy, and protected by Akamai. TacosScore gives you:
| Problem | TacosScore solution |
|---|---|
| Raw JSON with UI clutter | Typed dataclass models + strip_ui_fields() |
| 403 errors from plain HTTP | curl_cffi Chrome TLS impersonation |
| Rate-limit bans | Built-in rate limiter + exponential backoff on 429 |
| Inconsistent field names | Snake_case Python fields mapped from camelCase API |
| Notebook / warehouse workflows | .to_dataframe() on models + standalone helpers |
| Discoverability | tacoscore help interactive guide + full CLI |
Inspired by the breadth of tools like Match ScraperFC, TacosScore focuses on football analytics only — media streams, highlights, betting UI, and comment feeds are intentionally excluded.
Features
- Sync and async clients —
SofascoreClientandAsyncSofascoreClient - Match-level data — metadata, lineups, team stats, incidents, graph, H2H, pregame form, match shotmap
- Player-level spatial data — heatmap, action stream (rating-breakdown), per-player shotmap
- Tournament discovery — rounds, round fixtures, standings, season-wide fetch
- Profiles — team, player, season stats, transfers, rankings, fixture lists
fetch_full_match()— orchestrated multi-endpoint pipeline with smart skips- CLI — every major endpoint as a subcommand with
--raw,--pretty,--analytics-only - Interactive help — arrow-key browser (
tacoscore help) - 132+ tests — parsers, client, CLI, extraction rules
Installation
From PyPI
pip install tacoscore
With pandas and Jupyter (recommended for analysts)
pip install "tacoscore[analysis]"
From source (development)
git clone https://github.com/Tariq-15/TacosScore.git
cd TacosScore
pip install -e ".[dev,analysis]"
Optional dependency groups
| Extra | Packages | Use case |
|---|---|---|
| (default) | curl_cffi, httpx |
Core client + CLI |
analysis |
pandas, jupyter, ipykernel |
DataFrames and notebooks |
dev |
pytest, ruff, mypy, respx, … |
Contributing and CI |
Quick start
Python — one match
from tacoscore import SofascoreClient
client = SofascoreClient()
# Team stats and full lineups (~60 stats per player)
stats = client.event_statistics(15186861)
lineups = client.event_lineups(15186861)
print(f"{lineups.home.formation} vs {lineups.away.formation}")
print(f"Possession: {stats.by_period['ALL']['ballPossession'].home_value}%")
# Spatial data for one player
heatmap = client.player_heatmap(15186861, 868812)
actions = client.player_actions(15186861, 868812)
shots = client.player_shotmap(15186861, 868812)
for shot in shots.shots:
if shot.shot_type == "goal":
print(f"Goal {shot.minute}' — xG={shot.xg:.3f}")
client.close()
Python — full match in one call
match = client.fetch_full_match(15186861)
print(match.event_detail) # venue, referee, score
print(match.team_statistics) # by period
print(match.lineups.home.players) # all home players + stats
print(match.match_shotmap) # every shot in the match
print(match.player_data[868812]) # heatmap, actions, shotmap per player
CLI — fastest way to inspect JSON
tacoscore lineups 15186861 --pretty
tacoscore event-stats 15186861
tacoscore fetch-match 15186861 --out match.json --pretty
tacoscore help
World Cup 2026 extraction example
Use this ready-to-copy flow to extract World Cup 2026 data using 58210 as requested.
from tacoscore import SofascoreClient
client = SofascoreClient()
# World Cup 2026 extraction example
# tournament_id = 16, 58210 used here for World Cup 2026 season data
rounds = client.tournament_rounds(16, 58210)
round_6 = client.round_events(16, 58210, 6, slug="round-of-32")
for match in round_6.events:
event_id = match.event_id
full = client.fetch_full_match(
event_id,
include_match_shotmap=True,
include_h2h=True,
include_pregame_form=True,
)
print(
event_id,
full.lineups.home.team.name,
"vs",
full.lineups.away.team.name,
"| players:",
len(full.player_data),
)
client.close()
CLI version:
tacoscore rounds 16 58210
tacoscore round-events 16 58210 6 --slug round-of-32 --table
tacoscore fetch-match 15186861 --pretty --out wc2026_match.json
Finding matches and IDs
Sofascore uses numeric IDs everywhere. You typically discover event_id values from tournament rounds or team fixture lists.
Common tournament IDs
| Tournament | tournament_id |
Example season_id |
|---|---|---|
| FIFA World Cup | 16 |
58210 (2026) |
| Premier League | 17 |
varies by season |
| UEFA Champions League | 7 |
varies by season |
Workflow: list rounds → list matches → fetch match
from tacoscore import SofascoreClient
client = SofascoreClient()
# 1. All rounds in a season
rounds = client.tournament_rounds(16, 58210)
print(rounds.current_round)
for r in rounds.rounds:
print(r.round, r.name, r.slug)
# 2. Matches in a knockout round (slug required for named rounds)
r32 = rounds.by_slug("round-of-32")
matches = client.round_events(16, 58210, r32.round, r32.slug)
for m in matches.events:
print(m.event_id, m.home_team.name, "vs", m.away_team.name)
# 3. Use event_id for any match endpoint
event_id = matches.events[0].event_id
lineups = client.event_lineups(event_id)
CLI equivalent
tacoscore rounds 16 58210
tacoscore round-events 16 58210 6 --slug round-of-32 --table
The --table flag prints event_id | Home vs Away per line instead of JSON.
Extract event ID from a Sofascore URL
Match URLs look like:
https://www.sofascore.com/scotland-brazil/xxxxx#id:15186861
The number after id: is the event_id.
Client configuration
from tacoscore import SofascoreClient
client = SofascoreClient(
rate_limit_seconds=1.5, # minimum gap between requests (default 1.5)
rate_jitter_seconds=0.5, # random extra delay (default 0.5)
timeout=30.0, # per-request timeout in seconds
max_retries=3, # retries on HTTP 429 with backoff
user_agent=None, # optional custom User-Agent
)
| Parameter | Default | Description |
|---|---|---|
rate_limit_seconds |
1.5 |
Minimum seconds between API calls |
rate_jitter_seconds |
0.5 |
Random jitter added to spacing |
timeout |
30.0 |
Request timeout |
max_retries |
3 |
Retries on rate-limit (429) responses |
user_agent |
built-in | Override User-Agent header |
Always call client.close() when done (or use AsyncSofascoreClient as a context manager).
API methods reference
Base URL: https://www.sofascore.com/api/v1
Match endpoints
| Python method | Returns | API path | CLI command |
|---|---|---|---|
event(event_id) |
EventDetail |
GET event/{id} |
tacoscore event ID |
event_lineups(event_id) |
Lineups |
GET event/{id}/lineups |
tacoscore lineups ID |
event_statistics(event_id) |
TeamStatistics |
GET event/{id}/statistics |
tacoscore event-stats ID |
event_incidents(event_id) |
Incidents |
GET event/{id}/incidents |
tacoscore incidents ID |
event_graph(event_id) |
MatchGraph |
GET event/{id}/graph |
tacoscore graph ID |
event_managers(event_id) |
EventManagers |
GET event/{id}/managers |
tacoscore managers ID |
event_shotmap(event_id) |
Shotmap |
GET event/{id}/shotmap |
tacoscore event-shotmap ID |
event_h2h(event_id) |
HeadToHead |
GET event/{id}/h2h |
tacoscore h2h ID |
event_pregame_form(event_id) |
PregameForm |
GET event/{id}/pregame-form |
tacoscore pregame-form ID |
Player endpoints (per match)
| Python method | Returns | API path | CLI command |
|---|---|---|---|
player_heatmap(event_id, player_id) |
Heatmap |
GET event/{id}/player/{pid}/heatmap |
tacoscore heatmap ID PID |
player_actions(event_id, player_id) |
ActionStream |
GET event/{id}/player/{pid}/rating-breakdown |
tacoscore actions ID PID |
player_shotmap(event_id, player_id) |
Shotmap |
GET event/{id}/shotmap/player/{pid} |
tacoscore shotmap ID PID |
player_statistics(event_id, player_id) |
SinglePlayerStats |
GET event/{id}/player/{pid}/statistics |
tacoscore player-stats ID PID |
Tip: Prefer
event_lineups()when you need stats for the entire squad.player_statistics()returns the same block for one player only.
Tournament and standings
| Python method | Returns | CLI command |
|---|---|---|
tournament_rounds(tournament_id, season_id) |
RoundList |
tacoscore rounds TID SID |
round_events(tid, sid, round_num, slug=None) |
MatchList |
tacoscore round-events TID SID ROUND [--slug] |
season_events(tid, sid) |
dict[int, MatchList] |
(Python only — one request per round) |
tournament_standings(tid, sid, table_type="total") |
Standings |
tacoscore standings TID SID [--type] |
table_type for standings: "total", "home", or "away".
Profiles and history
| Python method | Returns | CLI command |
|---|---|---|
team(team_id) |
TeamProfile |
tacoscore team ID |
player(player_id) |
PlayerProfile |
tacoscore player ID |
player_season_statistics(pid, tid, sid) |
SeasonPlayerStatistics |
tacoscore player-season-stats PID TID SID |
team_events(team_id, page=0) |
MatchList |
tacoscore team-events ID [--page] |
team_events_next(team_id, page=0) |
MatchList |
(Python only) |
team_rankings(team_id) |
TeamRankings |
tacoscore team-rankings ID |
player_transfer_history(player_id) |
TransferHistory |
(Python only) |
player_events_last(player_id, page=0) |
MatchList |
(Python only) |
Low-level access
raw = client.get_raw("event/15186861/lineups")
Any CLI subcommand also supports --raw to bypass parsers and emit original API JSON.
Full-match pipeline
fetch_full_match() implements the recommended analytics order from docs/sofascore-api-reference.md (Section 10).
Fetch order
event → lineups → statistics → incidents → managers → graph
→ h2h → pregame_form → match_shotmap
→ per-player: heatmap → actions → shotmap
Parameters
match = client.fetch_full_match(
event_id=15186861,
skip_no_minutes=True, # skip spatial calls for 0-minute players
skip_no_shots=True, # skip shotmap when total_shots == 0
skip_sparse_heatmap=True, # skip heatmap when touches <= threshold
min_touches_for_heatmap=5, # minimum touches for heatmap
include_match_shotmap=True, # fetch event/{id}/shotmap
include_h2h=True,
include_pregame_form=True,
)
| Parameter | Default | Effect |
|---|---|---|
skip_no_minutes |
True |
No heatmap/actions/shotmap for unused subs |
skip_no_shots |
True |
No per-player shotmap when total_shots == 0 |
skip_sparse_heatmap |
True |
No heatmap when touches <= min_touches |
min_touches_for_heatmap |
5 |
Touch threshold for heatmap |
include_match_shotmap |
True |
Fetch all shots in the match |
include_h2h |
True |
Head-to-head aggregates |
include_pregame_form |
True |
Pre-match form strings |
FullMatch structure
match.event_id # int
match.event_detail # EventDetail | None
match.team_statistics # TeamStatistics
match.lineups # Lineups
match.incidents # Incidents | None
match.graph # MatchGraph | None
match.managers # EventManagers | None
match.head_to_head # HeadToHead | None
match.pregame_form # PregameForm | None
match.match_shotmap # Shotmap | None
match.player_data # dict[int, PlayerMatchData]
Each PlayerMatchData holds:
pmd = match.player_data[868812]
pmd.player_id # int
pmd.heatmap # Heatmap | None
pmd.actions # ActionStream | None
pmd.shotmap # Shotmap | None
CLI
tacoscore fetch-match 15186861 --out match.json --pretty
tacoscore fetch-match 15186861 --include-bench --fetch-empty-shotmaps
Data models
All models are immutable-style dataclasses with typed fields. Parsers map Sofascore camelCase JSON to snake_case Python.
Core match models
| Model | Description |
|---|---|
EventDetail |
Teams, score, status, venue, referee, attendance |
Lineups |
Confirmed flag, home/away LineupSide (formation + players) |
LineupEntry |
Player, shirt number, position, captain, PlayerStats |
TeamStatistics |
Stats keyed by period (ALL, 1ST, 2ND) then stat name |
Incidents |
Goals, cards, subs, period markers |
MatchGraph |
Minute-by-minute attack momentum |
Shotmap / Shot |
xG, coordinates, body part, situation, outcome |
Heatmap / HeatmapPoint |
Normalized touch coordinates |
ActionStream / Action |
Passes, dribbles, defensive actions, carries |
HeadToHead |
Team and manager duel records |
PregameForm |
Form strings and table context |
Discovery models
| Model | Description |
|---|---|
RoundList / Round |
Season rounds with optional knockout slug |
MatchList / MatchSummary |
Fixture lists with event_id |
Standings / StandingRow |
League table rows |
TeamProfile / PlayerProfile |
Bio, market value, venue |
SeasonPlayerStatistics |
Season aggregate stats |
TransferHistory / Transfer |
Career transfers |
TeamRankings |
FIFA-style ranking rows |
Accessing raw JSON
Every parsed model stores the original payload:
lineups = client.event_lineups(15186861)
lineups.raw # full API dict on Lineups
lineups.home.players[0].stats.raw # per-player raw stats block
Use --include-raw on the CLI to include raw fields in JSON output.
Player statistics
PlayerStats exposes ~60 fields per player. Sofascore omits zero values in JSON; TacosScore defaults missing fields to 0 / 0.0.
Categories
| Category | Example fields |
|---|---|
| Passing | total_pass, accurate_pass, key_pass, goal_assist, expected_assists |
| Shooting | total_shots, goals, expected_goals, expected_goals_on_target, big_chance_created |
| Dribbling | total_contest, won_contest, dispossessed |
| Duels | duel_won, duel_lost, aerial_won, aerial_lost |
| Defending | total_tackle, interception_won, ball_recovery, error_lead_to_a_goal |
| Fouls | fouls, was_fouled, total_offside |
| Goalkeeping | saves, goals_prevented, keeper_save_value |
| Physical | top_speed, kilometers_covered, number_of_sprints |
| Ball carries | ball_carries_count, total_progression, progressive_ball_carries_count |
| Engagement | touches, minutes_played, possession_lost_ctrl |
| Rating | rating, shot_value_normalized, pass_value_normalized, goalkeeper_value_normalized |
Example — top xG in a match
lineups = client.event_lineups(15186861)
rows = []
for side in (lineups.home, lineups.away):
for entry in side.players:
s = entry.stats
rows.append((entry.player.name, s.expected_goals, s.minutes_played))
for name, xg, mins in sorted(rows, key=lambda r: r[1], reverse=True)[:5]:
print(f"{name:20s} xG={xg:.2f} ({mins} min)")
Pandas and DataFrames
Install the analysis extra:
pip install "tacoscore[analysis]"
Method on models (.to_dataframe())
Most models expose a convenience method:
lineups = client.event_lineups(15186861)
df = lineups.to_dataframe() # player_id is the first column
stats_df = client.event_statistics(15186861).to_dataframe() # long format by period
shots_df = client.player_shotmap(15186861, 868812).to_dataframe(player_id=868812)
Module-level helpers
from tacoscore import (
lineups_to_dataframe,
team_stats_to_dataframe,
player_stats_to_dataframe,
heatmap_to_dataframe,
actions_to_dataframe,
shotmap_to_dataframe,
incidents_to_dataframe,
graph_to_dataframe,
matches_to_dataframe,
rounds_to_dataframe,
standings_to_dataframe,
season_player_stats_to_dataframe,
)
df = lineups_to_dataframe(lineups)
| Helper | Input model | Typical use |
|---|---|---|
lineups_to_dataframe |
Lineups |
One row per player, all stat columns |
team_stats_to_dataframe |
TeamStatistics |
Long format: period × stat × home/away |
shotmap_to_dataframe |
Shotmap |
Shot-level xG, coords, body part |
heatmap_to_dataframe |
Heatmap |
Touch coordinates |
actions_to_dataframe |
ActionStream |
Pass/dribble/defensive events |
matches_to_dataframe |
MatchList |
Fixture discovery tables |
standings_to_dataframe |
Standings |
League table |
Notebook and explore script
jupyter notebook notebooks/tacoscore_methods.ipynb
python scripts/explore_data.py --show-raw
Analytics extraction
The tacoscore.extraction module encodes rules from the Sofascore API Reference — which fields to keep, drop, and when to skip endpoints.
Strip UI-only JSON keys
from tacoscore import strip_ui_fields
clean = strip_ui_fields(client.get_raw("event/15186861/lineups"))
Dropped keys include: fieldTranslations, userCount, teamColors, logo, draw, directStreamUrl, thumbnailUrl, and other web/UI fields. See UI_DROP_KEYS in extraction.py.
Pipeline constants
from tacoscore import MATCH_EXTRACTION_ORDER, ANALYTICS_EVENT_ENDPOINTS
print(MATCH_EXTRACTION_ORDER)
# ('event', 'lineups', 'statistics', 'incidents', 'managers', 'graph', ...)
from tacoscore.extraction import should_fetch_shotmap, should_fetch_heatmap
should_fetch_shotmap(total_shots=0) # False
should_fetch_heatmap(touches=3) # False (default min_touches=5)
CLI — analytics-only JSON
tacoscore lineups 15186861 --analytics-only --pretty
This removes UI keys from serialized output before writing to stdout or --out.
Intentionally excluded endpoints
Media and web-only paths are not implemented as typed methods:
| Suffix | Reason |
|---|---|
/media |
Video streams (m3u8), thumbnails |
/highlights |
Video highlights |
/news |
Editorial content |
/tv-channels |
Broadcast listings |
/comments |
User comments |
Use get_raw() only if you explicitly need these; do not use them in analytics pipelines.
Coordinate systems
Sofascore uses two 0–100 grids. TacosScore documents and converts both in coordinates.py.
| System | Used by | X axis | Y axis |
|---|---|---|---|
| A | Heatmap, rating-breakdown | 0 = own goal → 100 = opposition goal | 0/100 = touchlines |
| B | Shotmap | Distance from opposition goal (e.g. x=3 = tap-in) |
Lateral |
from tacoscore.coordinates import (
system_a_to_pitch,
system_b_to_pitch,
to_statsbomb,
STANDARD_PITCH_LENGTH,
STANDARD_PITCH_WIDTH,
)
# Heatmap point → metres on 105×68 pitch
px, py = system_a_to_pitch(63.0, 91.0)
# Shot playerCoords → metres
px, py = system_b_to_pitch(shot.player_coords)
# Project to StatsBomb 120×80 grid
sx, sy = to_statsbomb(px, py)
Default pitch: 105 m × 68 m (FIFA standard). StatsBomb grid: 120 × 80.
Command-line interface
After install, tacoscore is on your PATH.
Global options
tacoscore [--version]
[--rate-limit SEC] [--jitter SEC]
[--max-retries N] [--timeout SEC]
[--user-agent UA]
COMMAND ...
Per-command options
| Flag | Description |
|---|---|
--out PATH |
Write JSON to file instead of stdout |
--raw |
Emit original API JSON (skip parsers) |
--pretty |
Pretty-print JSON (2-space indent) |
--include-raw |
Include each model's raw field in output |
--analytics-only |
Strip UI-only Sofascore keys from output |
All subcommands
# Match
tacoscore event EVENT_ID
tacoscore lineups EVENT_ID
tacoscore event-stats EVENT_ID
tacoscore incidents EVENT_ID
tacoscore graph EVENT_ID
tacoscore managers EVENT_ID
tacoscore h2h EVENT_ID
tacoscore pregame-form EVENT_ID
tacoscore event-shotmap EVENT_ID
tacoscore fetch-match EVENT_ID [--include-bench] [--fetch-empty-shotmaps]
# Player (per match)
tacoscore heatmap EVENT_ID PLAYER_ID
tacoscore actions EVENT_ID PLAYER_ID
tacoscore shotmap EVENT_ID PLAYER_ID
tacoscore player-stats EVENT_ID PLAYER_ID
# Tournament
tacoscore rounds TOURNAMENT_ID SEASON_ID
tacoscore round-events TID SID ROUND [--slug SLUG] [--table]
tacoscore standings TID SID [--type total|home|away]
# Profiles
tacoscore team TEAM_ID
tacoscore player PLAYER_ID
tacoscore player-season-stats PID TID SID
tacoscore team-events TEAM_ID [--page N]
tacoscore team-rankings TEAM_ID
# Help
tacoscore help [TOPIC] [--all] [--no-interactive]
Examples
# Pretty JSON to stdout
tacoscore lineups 15186861 --pretty
# Save full match bundle
tacoscore fetch-match 15186861 --out wc_match.json --pretty
# Raw API passthrough
tacoscore heatmap 15186861 868812 --raw
# List knockout fixtures
tacoscore round-events 16 58210 6 --slug round-of-32 --table
Interactive help
Browse all methods with an arrow-key UI (like an in-terminal notebook index):
tacoscore help
| Key | Action |
|---|---|
| ↑ / ↓ | Navigate list |
| Enter | Open section or method detail |
| Backspace | Go back |
| q / Esc | Quit |
# One topic (plain text)
tacoscore help fetch_full_match
tacoscore help player_heatmap
# Full catalog
tacoscore help --all
From Python
from tacoscore import show_help, get_help_entry, list_help_entries
show_help() # interactive when run in a TTY
show_help("event_lineups") # print one entry
show_help(interactive=False) # print entire catalog
entry = get_help_entry("fetch_full_match")
print(entry.signature)
print(entry.example_cli)
Async client
import asyncio
from tacoscore import AsyncSofascoreClient
async def main():
async with AsyncSofascoreClient() as client:
stats = await client.event_statistics(15186861)
lineups = await client.event_lineups(15186861)
match = await client.fetch_full_match(15186861)
asyncio.run(main())
AsyncSofascoreClient mirrors every method on SofascoreClient. Rate limiting is shared per client instance.
Serialization and export
from tacoscore._serialize import to_jsonable
match = client.fetch_full_match(15186861)
payload = to_jsonable(match, include_raw=False, analytics_only=True)
import json
with open("match_clean.json", "w", encoding="utf-8") as f:
json.dump(payload, f, indent=2, ensure_ascii=False, default=str)
The CLI uses the same serializer internally.
Exceptions
from tacoscore import (
SofascoreError, # base class
APIError, # HTTP errors (4xx/5xx)
RateLimitError, # 429 after retries exhausted
NotFoundError, # 404
ParseError, # JSON shape unexpected
)
try:
match = client.fetch_full_match(99999999)
except NotFoundError:
print("Match not found")
except RateLimitError:
print("Rate limited — increase rate_limit_seconds")
except SofascoreError as e:
print(f"API error: {e}")
Project structure
TacosScore/
├── src/tacoscore/
│ ├── client.py # SofascoreClient (sync)
│ ├── async_client.py # AsyncSofascoreClient
│ ├── cli.py # tacoscore CLI entry point
│ ├── extraction.py # strip_ui_fields, pipeline rules
│ ├── help_catalog.py # Method documentation catalog
│ ├── interactive_help.py # Arrow-key help browser
│ ├── dataframe.py # Pandas export helpers
│ ├── coordinates.py # Pitch / StatsBomb projection
│ ├── _serialize.py # JSON serialization
│ ├── models/ # Typed dataclasses
│ └── parsers/ # API JSON → models
├── docs/
│ └── sofascore-api-reference.md # Field catalog + KEEP/DROP rules
├── notebooks/
│ └── tacoscore_methods.ipynb # Exploration notebook
├── scripts/
│ └── explore_data.py # Live API exploration
├── tests/ # pytest suite (132+ tests)
├── pyproject.toml
├── README.md
├── LICENSE
└── TacosScore.png
Development and testing
git clone https://github.com/Tariq-15/TacosScore.git
cd TacosScore
pip install -e ".[dev,analysis]"
# Run tests
pytest
# Lint
ruff check src tests
# Type check
mypy src/tacoscore
Tests use respx to mock HTTP — no live API calls in CI.
Build and publish (maintainers)
pip install build twine
python -m build
twine upload dist/*
Operational considerations
| Topic | Guidance |
|---|---|
| Akamai / 403 | Plain httpx or requests often get blocked. TacosScore uses curl_cffi with Chrome TLS impersonation by default. |
| Rate limits | Default 1.5 s between requests. Aggressive scraping will get you IP-blocked. Use fetch_full_match() sparingly on large batches. |
| Undocumented API | Field names and shapes can change. Every model keeps .raw for forward compatibility. |
| Legal / ToS | Sofascore's terms may restrict automated access. This library is for research and personal analysis. Not authorized for commercial scraping or redistribution of Sofascore data. |
| National teams | Some team/player sub-endpoints return 404 for certain national-team IDs. |
| Media | Stream URLs (m3u8) exist in /media responses — excluded from analytics pipelines by design. |
Related documentation
| Document | Contents |
|---|---|
docs/sofascore-api-reference.md |
Full endpoint catalog, field KEEP/DROP/UNKNOWN tables, pipeline spec |
tacoscore help |
Interactive in-terminal method guide |
notebooks/tacoscore_methods.ipynb |
Hands-on examples |
License
MIT License — Copyright (c) 2026 Md. Tariquzzaman.
See LICENSE for full text.
Built for football analysts who want typed data, not raw JSON soup.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tacoscore-0.1.0.tar.gz.
File metadata
- Download URL: tacoscore-0.1.0.tar.gz
- Upload date:
- Size: 969.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ceecf2b7f3c4010f44aecd4c3daf8ef352972de903e69b7ef6de2f0ee6b65df
|
|
| MD5 |
47b5ded17c4fd795ac29cdf2edc3f9a3
|
|
| BLAKE2b-256 |
daab5686e68f6a1921d8c8e2e7488537b683fc7a6484059a924a5e80749ea562
|
File details
Details for the file tacoscore-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tacoscore-0.1.0-py3-none-any.whl
- Upload date:
- Size: 82.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dba441c536e68b91f007f225fa32877774472260fe2c0229d0c5d56f322a6e1c
|
|
| MD5 |
d76f49000ebceedfcd74cc25cb6ea609
|
|
| BLAKE2b-256 |
90dcbf70e1d3ecdc7944948ab58842dae5659d0ca82f7542d3cb27de2fd03962
|