How to use it: 3 steps
- Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
- Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example:
rankingsin Data to get. Each start is one run. - Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.
This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.
What it does
Get ATP and WTA tennis matches, set scores, seeds, player career stats, and rankings from public ESPN JSON data. Choose one of five modes in one Actor, singles and doubles. No login or API key is needed.
Who uses it
Sports writers
Make a daily match roundup with set scores and winners.
Fantasy and stats fans
Follow weekly ranking changes and player points.
App developers
Add player profiles and match data to your sports app.
Price
Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.
| What you pay for | Price | When |
|---|---|---|
| Start fee | $0.002 | Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more. |
| Data row | $0.007 (from $0.0055 on paid Apify plans) | Charged for each saved match, player profile or ranking row. RUN_SUMMARY is free. |
Examples
- One row: about $0.009.
- 1,000 rows: about $7.00.
- Every day 100 rows, for 30 days: about $21.06 a month.
Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 710 rows.
Prices checked on 24 October 2026. See the current price on Apify.
Questions
Does it include doubles?
Yes. Doubles rows show the team and both partners.
Can I get old results?
You can pick dates, up to 7 per run. ESPN may not have every old result.
Are the player IDs the same as on other sites?
No. These are ESPN IDs.
Do I need an API key?
No. No login or key is needed.
Details
Step by step on Apify
- Open the Input tab. The form starts with
mode=rankings,tour=ATP,maxItems=20. Click Start to get the top 20 of the current ATP ranking. - For match results, choose Finished match results. Leave both date fields empty to get yesterday's UTC date. This is also the API default when
modeis not sent. - Open the run's Dataset. Use the matches, players or rankings view for a flat table.
- For full set scores and doubles team members, export the original JSON.
Use cases
| Goal | Recommended input | Main output |
|---|---|---|
| Daily ATP match roundup | results + chosen date | Tournament, players, winners, set scores |
| Upcoming WTA matches | fixtures + chosen date | Start times and source match status |
| Enrich a sports article | match + matchId | One match with sets and player IDs |
| Profile a player | player + ID in players | Bio, career win-loss, titles, prize money |
| Weekly ranking change | rankings | Current/previous rank and points |
Tips for better results
- Leave the dates empty to get yesterday's results in UTC.
- Copy player IDs from a ranking run to look up profiles.
- Run twice for both tours. One run reads ATP or WTA.
Limits and good to know
The status is complete when rows were delivered normally, including a run that stopped at maxItems (raise it to get more rows), not_found for a valid input with no matching records, and partial / CHARGE_LIMIT when a paid limit stops new rows. A source failure can also leave previously saved rows; in that case the run fails, and its RUN_SUMMARY shows partial / SOURCE_ERROR. Invalid input fails before contacting ESPN.
- ESPN may have incomplete or delayed fixtures and scores. Historical coverage is not guaranteed
- ESPN does not publish per-match serve statistics (aces, double faults) or court surface, so this Actor does not return them. Seeds come from ESPN's draw data for scheduled matches and from the result line for finished ones.
startTimeis null while ESPN has not confirmed the order of play. A not-yet-known opponent is namedTBDwith a null ID - Scores and standings can be updated by ESPN after your run.
rankingUpdatedAtis the date ESPN last updated the ranking list (usually weekly), not the time of your run - Ranking rows give
countryas a three-letter code (ITA). In match rows,players[].countryis the country name from ESPN's flag (Italy, sometimesUSA) - An ESPN player ID is different from a SofaScore or ATP site ID. IDs from a different source may give zero matches
- Data is provided without a license from ESPN. ESPN/Disney terms restrict automated collection and commercial reuse. Confirm you have the right to use and distribute the data for your purpose
- The Actor has no betting tips, odds, point-by-point live updates, or guarantee of complete coverage
Troubleshooting
| Problem | What to check |
|---|---|
No records in results | Choose a date with completed matches; try removing name filters. Check RUN_SUMMARY. |
match returns zero rows | Verify the match's ESPN matchId, tour, and UTC date window. |
| Player lookup returns zero rows | Enter a numeric ESPN player ID from a ranking or match row. |
| Seeds are null | The player is unseeded. Career fields are null when ESPN has no career statistics for that player. |
| The run ends early | Check reason=CHARGE_LIMIT in RUN_SUMMARY and your run's allowed charge budget. |
| The run fails | Check run logs and RUN_SUMMARY; ESPN may have returned an error or exceeded the request limit. Retry later with a smaller date window. |
For developers
Sample result
One result from a real test run, in JSON. Real values change from run to run. Some values are changed for privacy. In Excel or CSV each field is a column.
{
"type": "match",
"tour": "ATP",
"matchId": "184950",
"tournament": "Rolex Shanghai Masters",
"matchType": "Men's Singles",
"round": "Round 4",
"player1Name": "Player One",
"player2Name": "Player Two",
"player1Seed": 26,
"player2Seed": 9,
"scoreText": "3:6 4:6",
"winnerName": "Player Two",
"resultNote": "(9) Player Two (AUS) bt (26) Player One (RUS) 6-3 6-4",
"source": "ESPN public JSON",
"sourceUrl": "https://site.api.espn.com/apis/site/v2/sports/tennis/atp/scoreboard?dates=20261013"
}Use it from code
Actor ID: cliqtomedia/tennis-stats-scraper. You need your Apify API token from Apify Console → Settings → API & Integrations.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/tennis-stats-scraper").call(run_input={
"mode": "rankings",
"tour": "ATP"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~tennis-stats-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode": "rankings", "tour": "ATP"}'# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("cliqtomedia/tennis-stats-scraper")
result = tool.invoke({"run_input": {"mode": "rankings", "tour": "ATP"}})
print(result)The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.
Data fields (40)
| Field | Type | Meaning |
|---|---|---|
type | string | The data kind. |
tour | string | ATP or WTA. |
matchId | string | ESPN competition ID in match rows. |
tournamentId | string | ESPN tournament ID. |
tournament | string | Name of event. |
matchType | string | ESPN draw type, such as Men's Singles or Women's Doubles. |
round | string | Event round name. |
startTime | string | UTC match start ISO timestamp; null while ESPN has no confirmed time. |
status | string | ESPN competition status, such as Final. |
player1Name | string | First player name, for flat tables. |
player2Name | string | Second player name, for flat tables. |
player1Seed | number | Tournament seed of player 1 from ESPN draw data or the result note; null for unseeded players. |
player2Seed | number | Tournament seed of player 2 from ESPN draw data or the result note; null for unseeded players. |
scoreText | string | Set score text, in player1:player2 order. |
winnerName | string | Winner of a completed match, if present. |
resultNote | string | ESPN result line with seeds and countries, such as (9) Player Two (AUS) bt ... 6-3 6-4. |
players | array | Two competitors: ID, name, country, seed, winner flag and members (two athletes for doubles). |
score | object | Game scores, tiebreaks and sets. |
playerId | string | ESPN athlete ID. |
name | string | Player display name. |
country | string | Country code in ranking rows. |
age | number | Player age, if provided by ESPN. |
dateOfBirth | string | Player birthday YYYY-MM-DD. |
birthPlace | string | Birthplace text from the ESPN athlete profile. |
heightCm | number | Centimeters converted from source inches. |
weightKg | number | Kilograms converted from source pounds. |
plays | string | Playing hand, such as Right or Left. |
turnedPro | number | Year the player turned professional. |
careerSinglesWon | number | Career singles match wins (ESPN career statistics). |
careerSinglesLost | number | Career singles match losses. |
singlesTitles | number | Career singles titles. |
doublesTitles | number | Career doubles titles. |
careerPrizeMoneyUsd | number | Career prize money in US dollars. |
rank | number | Current ranking place. |
previousRank | number | Prior ranking position. |
points | number | Ranking points. |
rankingUpdatedAt | string | Ranking update date. |
source | string | Provider: ESPN public data. |
sourceUrl | string | Origin endpoint without credentials. |
fetchedAt | string | ISO UTC fetch time. |
Input settings (8)
The main fields of the input form. With the API you send them as JSON.
| Setting | Name in the API | Type | Example value |
|---|---|---|---|
| Data to get | mode | string | "rankings" |
| Tour | tour | string | "ATP" |
| Start date (UTC) | dateFrom | string | |
| End date (UTC) | dateTo | string | |
| Tournament filters (optional) | tournaments | array | |
| Player filters or ESPN IDs | players | array | |
| Match competition ID | matchId | string | |
| Maximum output records | maxItems | integer | 20 |



