# ATP & WTA Tennis Rankings - Current & Weekly History (`crawlplant/tennis-rankings`) Actor

ATP and WTA rankings as data: today's top 100, any past week (ATP from 1973, WTA from 2001) or every weekly list of a season, with rank, points and movement. Optional Jeff Sackmann layout, plus every ATP and WTA player. Works as an MCP tool for AI agents.

- **URL**: https://apify.com/crawlplant/tennis-rankings.md
- **Developed by:** [CrawlPlant](https://apify.com/crawlplant) (community)
- **Categories:** Sports, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 ranking rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## ATP & WTA Tennis Rankings - Current & Weekly History

*Independent tool, not affiliated with, endorsed by or connected to Jeff Sackmann, Tennis Abstract, Flashscore, the ATP,
the WTA or the ITF. It reads the official ATP and WTA ranking lists and player profiles.*

**The ATP and WTA rankings as data: today's top 100, the list of any past week, or every weekly list of a whole season.**
One row per player with rank, points, movement since the previous list, country and age; ATP lists go back to **1973**, WTA
lists to **2001**. Ask for the **layout of Jeff Sackmann's `atp_rankings` / `wta_rankings` CSV files** and code that reads
his files keeps working. A second mode returns **every ATP and WTA player** in the columns of his `atp_players` /
`wta_players` files.

### Related runnable examples

Explore the same tennis research workflows in our example repository. These recipes currently call the broader Flashscore Tennis Scraper or Match Dataset Actor; they are companion examples, not direct calls to this specialized Actor.

- [Export a bounded ATP/WTA ranking snapshot](https://github.com/CrawlPlant/examples/blob/main/docs/recipes/tennis-rankings.md)
- [Retrieve a dated ranking list](https://github.com/CrawlPlant/examples/blob/main/docs/recipes/tennis-historical-rankings.md)
- [Retrieve grass-court Elo ratings](https://github.com/CrawlPlant/examples/blob/main/docs/recipes/tennis-surface-elo.md)

Follow the [Python setup and `.env` guide](https://github.com/CrawlPlant/examples/blob/main/docs/LIVE-QUICKSTART.md) with your own `APIFY_TOKEN`, or browse the [complete catalog](https://github.com/CrawlPlant/examples/blob/main/docs/CATALOG.md) and [AI assistant instructions](https://github.com/CrawlPlant/examples/blob/main/docs/AI-AGENTS.md). Actor runs follow Apify pricing; the quickstart explains per-run spending limits.

### Why this one

- **Any week since 1973 (ATP) and 2001 (WTA).** Set a date and get that week's list; set a second date and get every
  weekly list in between, in one run.
- **A whole season in one run.** Every weekly top-100 list of 2024 is 4,400 rows per tour and costs about $4.40.
- **Top N only.** `maxRank: 100` keeps the top 100 of each list and you pay only for those rows.
- **Same columns as the open dataset.** With `rankingFormat: "sackmann"` the rows carry `ranking_date`, `rank`, `player`,
  `points`, plus the player's `name`, `official_id` and `list`: drop-in for notebooks written against his files.
- **Every list.** Singles, season race and doubles rankings for both tours.
- **Player lists.** Every official ATP and WTA player with ids and names, plus playing hand, birth date, height and
  country where known, in his `atp_players` / `wta_players` columns, to join ids to names.
- **Current.** The latest list is read the week it is published.
- **See it live.** The ranking weeks stored for each tour, from the same database your runs read:
  [crawlplant.com/tennis-rankings](https://crawlplant.com/tennis-rankings/).

### What can you use it for?

- **Prediction models**: the rank and points a player had in the week of a match.
- **Journalism and research**: rank histories, how long a player stayed in the top 10, ranking movement by season.
- **Apps and fantasy sites**: a current top-100 table without maintaining your own scraper.
- **AI agents**: "who was number 1 on 1 January 2000?" answered from the list itself.

### Quick start

1. Click **Try for free** with the default input (the current ATP and WTA top 100, 200 rows).
2. Pick **Ranking lists**, a **Ranking date** (and **Ranking date to** for a range), and set **Max results** above the
   rows you expect.
3. Download the table as CSV, Excel or JSON, or save the input as a **task** and schedule it weekly to keep a dataset
   current.

#### Copy to your AI assistant

Paste this into ChatGPT, Claude or any agent so it knows how to use the Actor:

```
crawlplant/tennis-rankings on Apify: ATP / WTA rankings. Input: mode (rankings | playerList), rankingLists (atp, wta,
atp-race, wta-race, atp-doubles, wta-doubles; default atp + wta), rankingDate (YYYY-MM-DD; ATP from 1973, WTA from 2001;
empty = latest), rankingDateTo (every weekly list from rankingDate to it), maxRank (top N only, default 100),
rankingFormat (standard | sackmann = his atp_rankings columns), maxItems (default 200).
Row (standard): list, rankingDate, rank, previousRank, rankChange, name, playerId, country, points, officialId, birthDate.
Row (sackmann): ranking_date, rank, player, points, name, official_id, list. playerList row: player_id, name_first,
name_last, hand, dob, ioc, height, official_id, tour.
Price: $1.00 per 1,000 ranking rows, $3.00 per 1,000 players on the Free plan.
```

### Ready-to-use examples

**1. The current ATP and WTA top 100 (200 rows, $0.20)**

```json
{ "maxRank": 100 }
```

**2. The ATP top 100 of one past week (100 rows, $0.10)**

```json
{ "rankingLists": ["atp"], "rankingDate": "2000-01-01", "maxRank": 100, "maxItems": 100 }
```

**3. Every weekly ATP top-100 list of 2024 in Jeff Sackmann's atp_rankings columns (4,400 rows, ~$4.40)**

```json
{ "rankingLists": ["atp"], "rankingDate": "2024-01-01", "rankingDateTo": "2024-12-31", "maxRank": 100, "rankingFormat": "sackmann", "maxItems": 6000 }
```

**4. The ATP player list in Jeff Sackmann's atp_players columns (500 players, $1.50)**

```json
{ "mode": "playerList", "rankingLists": ["atp"], "maxItems": 500 }
```

**5. Every weekly WTA top-50 list of 2025 in Jeff Sackmann's wta_rankings columns (~2,600 rows, ~$2.60)**

```json
{ "rankingLists": ["wta"], "rankingDate": "2025-01-01", "rankingDateTo": "2025-12-31", "maxRank": 50, "rankingFormat": "sackmann", "maxItems": 3000 }
```

**6. The race rankings (season points), top 50 of each (100 rows, $0.10)**

```json
{ "rankingLists": ["atp-race", "wta-race"], "maxRank": 50 }
```

### How to…

#### Get the current ATP and WTA rankings

Run the default input: the top 100 of both singles lists. Use `rankingLists` for one tour, the race or the doubles lists.

#### Get the ranking of a past date

Set `rankingDate` to any day (example 2): you get the list of the week containing it. ATP lists start in 1973, WTA lists
in 2001.

#### Download every weekly ranking list of a season

Set `rankingDate` and `rankingDateTo` (example 3). Each weekly list is a set of rows with its own `ranking_date`; raise
`maxItems` above the total (52 lists x the top N you keep).

#### Get the list of all ATP or WTA players

Use `mode: "playerList"` (example 4): ids and names, plus hand, birth date, country and height where known, in his
player-file columns.

### Input options

| Option | Default | Description |
|---|---|---|
| `mode` | `rankings` | `rankings` or `playerList` |
| `rankingLists` | `atp`, `wta` | `atp`, `wta`, `atp-race`, `wta-race`, `atp-doubles`, `wta-doubles` (player list: `atp`, `wta`) |
| `rankingDate` | latest | A date (YYYY-MM-DD): the list of that week |
| `rankingDateTo` | none | With a date: every weekly list up to this date |
| `maxRank` | `100` | Only players ranked this high or better; set 5000 for every ranked player, and raise `maxItems` above the row count too |
| `rankingFormat` | `standard` | `standard` or `sackmann` |
| `maxItems` | `200` | Maximum rows in total |

### Output fields

| Field | Description |
|---|---|
| `list`, `rankingDate` | `atp`, `wta`, `atp-race`...; the date of the list |
| `rank`, `previousRank`, `rankChange` | Rank, rank on the previous list, movement |
| `name`, `playerId`, `officialId`, `country`, `birthDate` | The player and the id on the official ATP / WTA site |
| `points`, `tournamentsPlayed` | Ranking points and tournaments counted, where the list has them |
| `ranking_date`, `player`, `official_id` | Sackmann layout: the date as YYYYMMDD, the player's id and the id on the official site |
| `player_id`, `name_first`, `name_last`, `hand`, `dob`, `ioc`, `height`, `tour` | Player list, in his player-file columns |

### How much do tennis rankings data cost?

Pay per result: platform usage is included. One price per ranking row, one per player.

| Event | No discount (Free plan) | Bronze (Starter) | Silver (Scale) | Gold (Business) |
|---|---|---|---|---|
| Ranking row (per 1,000) | $1.00 | $0.90 | $0.80 | $0.70 |
| Player (per 1,000) | $3.00 | $2.70 | $2.40 | $2.10 |
| Actor start (per run) | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

| Example on the Free plan | Rows | Cost |
|---|---|---|
| Default run: current ATP + WTA top 100 | 200 | ~$0.20 |
| One past week, ATP top 100 | 100 | ~$0.10 |
| Every weekly ATP top-100 list of 2024 | 4,400 | ~$4.40 |
| Every weekly WTA top-50 list of 2025 | ~2,600 | ~$2.60 |
| 500 players of the ATP list | 500 | ~$1.50 |

Set a **maximum cost per run** in the run options to stop a large run at your budget.

### Run it through the API

JavaScript:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('crawlplant/tennis-rankings').call({ rankingLists: ['atp'], rankingDate: '2000-01-01', maxRank: 10 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("crawlplant/tennis-rankings").call(run_input={"rankingLists": ["wta"], "maxRank": 10})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["rank"], row["name"], row["points"])
```

### Use with AI agents

The Actor works as a tool in the [Apify MCP server](https://mcp.apify.com) for Claude, ChatGPT, Cursor and others:

```
https://mcp.apify.com?tools=crawlplant/tennis-rankings
```

Try *"who was ranked number 1 on the ATP list on 1 January 2000?"*.

**Use it when** you need rankings by week or season, or the list of all players with ids.

**Not for** match results, odds or Elo (use the [Flashscore Tennis Scraper](https://apify.com/crawlplant/flashscore-tennis)).

### More tennis data

- [Flashscore Tennis Scraper](https://apify.com/crawlplant/flashscore-tennis): every match of any day with odds from about
  20 bookmakers, head-to-head, form, rankings, player statistics and Elo lists.
- [Tennis Live Scores](https://apify.com/crawlplant/tennis-live-scores): matches in play now and any day's scores, ATP, WTA, Challenger and ITF.
- [Tennis Match History](https://apify.com/crawlplant/tennis-match-history): a player's whole career, match by match, with Elo and serve statistics.
- [Tennis Odds Dataset](https://apify.com/crawlplant/tennis-odds-dataset): closing odds with results and Elo, in tennis-data.co.uk's columns.
- [ATP & WTA Tennis Match Dataset](https://apify.com/crawlplant/tennis-match-dataset): whole seasons in Jeff Sackmann's CSV columns.

### FAQ

#### How far back does it go?

ATP lists from 1973, WTA lists from 2001.

#### Which date do I give for a weekly list?

Any day: you get the list of the week containing it. For every list in a period, give `rankingDate` and `rankingDateTo`.

#### Does `maxRank` apply to the player list?

No: the player list returns players, not ranks. Use `maxItems` to cap it.

#### Is it legal?

The data is public sporting results read without logging in, at a polite pace. How you use and publish them is your
responsibility, so check the source's terms for your use case.

Questions, a missing field or a source you need? Open an issue on this Actor: we reply within a day. If it saved you time, a short review helps others find it.

### Privacy

The data is about professional players' public sporting results and ranking lists. Each run sends the developer anonymous feature-usage
statistics (the options used, never the players you asked for); your Apify account id is replaced by a one-way hash.

# Actor input Schema

## `mode` (type: `string`):

rankings = the ATP / WTA ranking lists, one row per player: the latest, the list of a past week (ATP back to 1973, WTA back to 2001) or every weekly list of a date range; playerList = every ATP and / or WTA player (from "Ranking lists") with ids and names, plus playing hand, birth date, height and country where known, in the columns of Jeff Sackmann's atp_players / wta_players files.

## `rankingLists` (type: `array`):

Which lists. atp / wta = singles, atp-race / wta-race = season points, atp-doubles / wta-doubles. Each singles list has about 2,000 players. In playerList mode: atp and / or wta.

## `rankingDate` (type: `string`):

Rankings: the list of this date (YYYY-MM-DD; ATP back to 1973, WTA back to 2001); the week containing it. Empty = the latest list.

## `rankingDateTo` (type: `string`):

Rankings: with a ranking date, every weekly list from that date up to this one (YYYY-MM-DD), e.g. 2024-01-01 to 2024-12-31 = the whole 2024 season. Empty = just the one list.

## `maxRank` (type: `integer`):

Rankings: only players ranked this high or better, e.g. 100 for the top 100 (the default); set a large number, e.g. 5000, for every ranked player (and raise Max results above the row count too). Does not apply to the player list.

## `rankingFormat` (type: `string`):

standard = one row per player with rank, points and movement; sackmann = the columns of Jeff Sackmann's atp_rankings / wta_rankings files (ranking_date, rank, player, points) plus the name and official id.

## `maxItems` (type: `integer`):

Maximum rows to return in total (ranking rows or players). Every weekly top-100 list of one season is about 5,200 rows; the ATP player list is several thousand.

## Actor input object example

```json
{
  "mode": "rankings",
  "rankingLists": [
    "atp",
    "wta"
  ],
  "maxRank": 100,
  "rankingFormat": "standard",
  "maxItems": 200
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlplant/tennis-rankings").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("crawlplant/tennis-rankings").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call crawlplant/tennis-rankings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlplant/tennis-rankings"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/nzP9xIBtEHC5JZyeE/builds/QqhSadWxAHpCUsKEt/openapi.json
