SofaScore Scraper icon

SofaScore Scraper

From $1/1K. Pull structured sports data from SofaScore across football, basketball, tennis, and 20+ sports. Search by keyword, paste URLs, fetch live…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

SofaScore Scraper at a glance

SofaScore Scraper is a ready-to-run Apify actor from abotapi for collecting web data. Its documented output includes type, id, sport, name and url, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.

Runs on
Apify cloud: console, API, schedules and integrations
Data type
Other, Developer Tools, News
Pricing
$1.80 per 1,000 results (Free plan), from $1.00 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
29 options

From $1/1K. Pull structured sports data from SofaScore across football, basketball, tennis, and 20+ sports. Search by keyword, paste URLs, fetch live matches, or download fixtures by date. Returns scores, stats, lineups, incidents, odds, teams, players, tournaments, and more.

What SofaScore Scraper ⚽ Live Scores, Stats, Players & Odds can do

  • Four ways to find data. Search by keyword, paste SofaScore links, pull every live match, or list all fixtures on a date. No need to build URLs by hand.
  • Four record types, fully expanded. Matches, teams, players and tournaments each come with 100+ named fields, plus the complete source object so nothing is lost.
  • Match depth on demand. Switch statistics, lineups, incidents, odds, fan votes, head-to-head history, the shot-level xG map and per-player touch heatmaps on or off per run, and pay only for what you use.
  • League tables and squads. Tournament records can carry full standings; team records can carry the whole squad.
  • 20+ sports. Football, basketball, tennis, ice hockey, American football, baseball, cricket, rugby, MMA and more.
  • Built for schedules. Incremental mode returns only new and changed matches on recurring runs, and a refused run fails loudly instead of returning an empty dataset.

Choose what to collect

These inputs let you configure SofaScore Scraper ⚽ Live Scores, Stats, Players & Odds. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestring · requiredHow to discover what to scrape. SEARCH looks up teams/players/tournaments/matches by keyword. URL takes SofaScore links you paste. LIVE pulls every in-play match for the chosen sports. SCHEDULED pulls all fixtures for a date.

Choices: search, url, live, scheduled

searchQueriesarrayKeywords to look up: team, player, tournament, or match names. Each query resolves to the top matching entities, which are then scraped in full.
searchTypestringLimit which entity types a query resolves to. 'all' returns the best mix of teams, players, tournaments and matches.

Choices: all, team, player, tournament, match

urlsarrayPaste SofaScore links: match pages (with the #id: part, or /event/), team, player or tournament pages, or a daily fixtures page like /football/2026-10-15. To get every match of a league, turn on 'List every match of a tournament' below and paste the tournament link. Any host works (www, m., sofascore.app). Left untouched, one sample each of a match, team, tournament, player and daily fixtures page is scraped. The match link without the #id: part cannot be resolved and is skipped with a warning.
expandTournamentMatchesbooleanURL mode only. Turn a tournament link into all of that tournament's matches instead of the single tournament record. Paste the league page, e.g. .../football/tournament/england/championship/18. A link that ends in #id: (the season the page shows) lists that one season; otherwise the Seasons option below decides. Each match is returned as a normal match record, so the detail options (statistics, lineups, incidents and so on) apply to every match. A full season is a few hundred matches, so set Max items to 0 for no limit.
tournamentSeasonsstringWhich seasons to list when a tournament link names no season and 'List every match of a tournament' is on. 'Latest season' lists the season the site currently shows. 'All seasons' lists every season the site holds for that tournament, newest first, which can be thousands of matches. Ignored when the link ends in #id:.

Choices: current, all

sportsarrayWhich sports to pull for Live and Scheduled modes.
Show 22 more inputs
More input fields
InputWhat it controls
datestringDay to pull fixtures for, in YYYY-MM-DD. Leave blank to use today (UTC). A busy day holds several hundred fixtures across roughly a hundred competitions, so Max items decides how much of it this run collects.
daysAheadintegerAlso pull fixtures for this many days after the chosen date. 0 = just the one day.
includeStatisticsbooleanInclude full match statistics (possession, shots, passes, xG, etc.) for match records. Adds one request per match.
includeLineupsbooleanInclude starting XI, substitutes, formations and per-player ratings for match records. Adds one request per match.
includeIncidentsbooleanInclude goals, cards, substitutions and period scores for match records. Adds one request per match.
includeOddsbooleanInclude pre-match betting odds markets for match records. Adds one request per match.
includeVotesbooleanInclude the fan prediction poll for match records: how many fans voted home win / draw / away win, both-teams-to-score, and first-to-score. The community sentiment signal. Adds one lightweight request per match.
includeH2HbooleanInclude the head-to-head record between the two teams (past meeting win/draw/loss totals, plus the two managers' record) for match records. Adds one request per match.
includeShotmapbooleanInclude the shot-by-shot map for football match records: every shot's xG and xGoT value, pitch coordinates, situation (open play, penalty, direct free kick, set piece, corner), outcome (goal, saved, blocked, off target, post), body part, shooter and goalkeeper. Adds one request per match.
includePlayerHeatmapsbooleanInclude the touch heatmap for every football player who took part in the match (the map the site draws on a player's card): every touch's pitch coordinate plus the total touch count per player. Football only; needs the lineups data and adds one request per player (typically 25-30 per match), so enable it only when you need it. Billed as one detail-enrichment event for every 10 players mapped.
includeStandingsbooleanInclude the league table for tournament records. Adds one request per tournament.
includeSquadbooleanInclude the full player squad for team records. Adds one request per team.
maxItemsintegerThe single cap: stop after this many entity records (0 = no limit). In Search mode it is spread fairly across your queries (each query returns up to 20, the SofaScore maximum). Add more queries to raise the realistic total. In Scheduled mode a day is collected competition by competition, most important first, and stops here, so a low cap returns the day's most prominent fixtures and a whole day needs a high cap or 0. Competitions are taken whole, so a run can return slightly more than this.
resumeFromRunIdstringPaste a previous run ID or dataset ID to continue an interrupted crawl without returning or charging for entities already collected there. For recurring monitoring of the same search/URLs, use Incremental mode below instead.
incrementalModebooleanTurn this on for daily or recurring monitoring. The first run returns all matching entities as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED entities. An entity is UPDATED when any returned field changed (score, status, teams, venue, standings, squad, incidents, statistics and so on); odds, fan votes and live-clock/change-feed bookkeeping are excluded and never trigger UPDATED, nor do fields you list in "Ignore fields when detecting changes" below. Turn on "Emit unchanged" or "Emit expired" only when you also want those entities returned (and billed). State is kept separately for each mode/scope/detail-toggle setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.
stateKeystringOptional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode, search/URL scope, and detail toggles, different setups then never mix state with each other.
emitUnchangedbooleanOff by default. Turn on to also return entities that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run.
emitExpiredbooleanOff by default. Turn on to also return entities that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked scope, not in Search mode (which returns only top relevance-ranked matches, never a full listing), and not when Max items capped the run or Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.
ignoreFieldsForChangesarrayOptional. Field names to exclude from UPDATED change detection, in addition to the built-in handling (odds, votes and the live-clock/change-feed bookkeeping inside the raw event never trigger UPDATED). Nested fields use dots, e.g. raw.venue. Ignored fields are still returned in the row, just not compared.
mcpConnectorsarrayOptionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).
notionParentPageUrlstringURL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap on items written to each connector per run. Does not affect the dataset.

Fields in the output

The documented dataset includes the fields below. Availability can depend on the source page and selected mode.

typeType (text)
idID (number)
sportSport (text)
nameName (text)
urlURL (link)
countryCountry (text)
tournamentTournament (text)
homeTeamHome (text)
awayTeamAway (text)
homeScoreH (number)
awayScoreA (number)
statusTypeStatus (text)
Show 47 more fields
startTimestampStart (number)
nameCodeName Code (text)
nationalNational (boolean)
venueVenue (text)
teamTeam (text)
positionPosition (text)
nationalityNationality (text)
tierTier (text)
genderGender (text)
startDateStart Date (number)
homeTeamLogoHome logo (link)
awayTeamLogoAway logo (link)
logoLogo (link)
photoPhoto (link)
changeTypeChange type (incremental mode) (text)
changedFieldsChanged fields (incremental mode) (array)
firstSeenAtFirst seen (incremental mode) (date)
lastSeenAtLast seen (incremental mode) (date)
uniqueTournamentUnique tournament (text)
seasonSeason (text)
roundRound (number)
homeScoreHalftimeHome score halftime (number)
awayScoreHalftimeAway score halftime (number)
statusDescriptionStatus description (text)
winnerCodeWinner code (number)
venueCityVenue city (text)
refereeReferee (text)
attendanceAttendance (number)
fullNameFull name (text)
shortNameShort name (text)
managerNameManager name (text)
venueCapacityVenue capacity (number)
foundationDateFoundation date (number)
rankingRanking (number)
heightHeight (number)
dateOfBirthDate of birth (number)
preferredFootPreferred foot (text)
shirtNumberShirt number (number)
contractUntilContract until (number)
marketValueMarket value (number)
marketValueCurrencyMarket value currency (text)
endDateEnd date (number)
titleHolderNameTitle holder name (text)
titleHolderTitlesTitle holder titles (number)
mostTitlesMost titles (number)
mostTitlesTeamMost titles team (array)
hasGroupsHas groups (boolean)

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "type": "match",
  "id": 10000001,
  "sport": "football",
  "name": "Home Team - Away Team",
  "homeTeam": "Home Team",
  "awayTeam": "Away Team",
  "homeTeamLogo": "https://img.sofascore.com/api/v1/team/2000001/image",
  "awayTeamLogo": "https://img.sofascore.com/api/v1/team/2000002/image",
  "homeScore": 2,
  "awayScore": 1,
  "statusType": "finished",
  "winnerCode": 1,
  "startTimestamp": 1700000000,
  "tournament": "Sample League",
  "season": "24/25",
  "round": 12,
  "venue": "Sample Stadium",
  "referee": "Referee Name",
  "attendance": 40000,
  "country": "Country",
  "url": "https://www.sofascore.com/football/match/home-team-away-team/AbCdEf#id:10000001",
  "statistics": [
    {
      "period": "ALL",
      "groups": []
    }
  ],
  "incidents": [
    {
      "incidentType": "goal",
      "time": 23,
      "player": {
        "name": "Player Name"
      }
    }
  ],
  "raw": {}
}

Ways to use this data

  • Sports betting and odds research: collect pre-match odds, fan prediction votes and head-to-head records to build and backtest models.
  • Live score apps and dashboards: feed live matches, incidents and statistics into your own site, bot or alerting tool.
  • Fantasy sports and scouting: track player ratings, positions, market values and squad changes across leagues.
  • Sports analytics and data science: build historical datasets of results, xG-bearing statistics and lineups for machine learning. The shotmap gives shot-level xG with pitch coordinates, and player heatmaps give raw touch coordinates for spatial models.
  • Media and content teams: generate match previews, reports and league tables automatically.

Before you run

Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.

Questions about this actor

What data does SofaScore Scraper return?

The documented output for SofaScore Scraper includes type, id, sport, name, url, country, tournament and home. Availability of each field depends on the source page and the selected mode.

How much does SofaScore Scraper cost?

It costs $1.80 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.

Can I get only new or changed matches on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated records, and unchanged ones are not billed.

Why did a run return fewer matches than a full day?

Scheduled mode stops at Max items, most important competitions first. Set it higher, or to 0, to collect the whole day.

How do I get all matches of a league?

Use URL mode, paste the league page link, turn on expandTournamentMatches and set Max items to 0. Add #id: to the link (copy it from the address bar) for one particular season, or set tournamentSeasons to all for every season. Cup rounds and league rounds are both included.

Why did my run fail instead of returning an empty dataset?

If the site refuses every request, the run stops with a clear message so "no matches today" is never confused with "nothing could be read". Run it again in a few minutes. If only some sports or dates could be read, you still get what was found.

Ready to collect with SofaScore Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.