# Tennis Abstract Scraper | ATP/WTA Match History, Stats, Elo (`zen-studio/tennis-abstract-scraper`) Actor

Scrape complete ATP and WTA career match logs from Tennis Abstract. Every match a player has played, with aces, double faults, break points, dominance ratio, Elo ratings by surface, head-to-head records and shot-by-shot point-by-point detail. 112 fields per match, back to 1995.

- **URL**: https://apify.com/zen-studio/tennis-abstract-scraper.md
- **Developed by:** [Zen Studio](https://apify.com/zen-studio) (community)
- **Categories:** Sports, Developer tools, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.39 / 1,000 matches

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Tennis Abstract Scraper | ATP & WTA Career Match Stats, Elo Ratings, Point by Point

<a href="https://console.apify.com/actors/aSaCGC6CeIt8UFbft/input"><img src="https://api.apify.com/v2/key-value-stores/pJ7iaZsTFhR3k9tjV/records/tennis-abstract-scraper-hero-r1.png" alt="Tennis Abstract scraper: complete ATP and WTA career match histories for many players in one run, shown on the Roger Federer, Novak Djokovic and Serena Williams pages" style="max-width:100%"></a>

From Zen Studio, creators of [PrizePicks Player Props](https://apify.com/zen-studio/prizepicks-player-props), [Underdog Player Props](https://apify.com/zen-studio/underdog-player-props) and [DraftKings Odds](https://apify.com/zen-studio/draftkings-odds), with **50,000+ combined lifetime runs** across those three.

### Why choose this actor?

- **Every player, one run.** Type names the way you would say them, as many as you need. An owner-measured run returned the complete careers of Roger Federer, Novak Djokovic and Serena Williams, **4,136 matches in 5.5 seconds**.
- **Only the matches you need.** Filter by surface, level, round, result, opponent, opponent ranking and date before anything is saved. Billing is per match delivered, **$1.99 per 1,000**.
- **The numbers behind every result.** Aces, double faults, break points, dominance ratio and more rates for both players, plus shot-by-shot point by point on charted matches and today's rankings and Elo lists.

<a href="https://console.apify.com/actors/aSaCGC6CeIt8UFbft/input" data-demo-cta="true"><img src="https://api.apify.com/v2/key-value-stores/pJ7iaZsTFhR3k9tjV/records/tennis-abstract-scraper-cta-r1.png" alt="Get every career: open the actor input page" width="340"></a>

#### Try three careers

Open the actor's [input page](https://console.apify.com/actors/aSaCGC6CeIt8UFbft/input), switch to JSON and paste this to collect every Grand Slam final of all three players, about 100 matches:

```json
{
  "players": [
    "Roger Federer",
    "Novak Djokovic",
    "Serena Williams"
  ],
  "levels": [
    "G"
  ],
  "rounds": [
    "F"
  ]
}
```

Remove `levels` and `rounds` to take each whole career. Switch on `includePointByPoint` for shot-by-shot detail on the matches that carry it, charged at $19.99 per 1,000 of those matches.

### Related actors

<table>
<tr>
<td colspan="4" style="padding:10px 14px;background:#4C945E;border:none;border-radius:4px 4px 0 0">
<span style="color:#FAFAF9;font-size:14px;font-weight:700;letter-spacing:0.5px">Zen Studio Sports Data</span>
<span style="color:#E8F5E9;font-size:13px">&nbsp;&nbsp;&bull;&nbsp;&nbsp;Scores, stats and odds across every major source</span>
</td>
</tr>
<tr>
<td style="padding:12px 16px;border:1px solid #E7E5E4;border-radius:0 0 0 4px;background:#D3EDD9;border-right:none;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap">&#127934;&nbsp;&nbsp;<a href="https://apify.com/zen-studio/tennis-abstract-scraper" style="color:#4C945E;text-decoration:none;font-weight:700;font-size:13px">Tennis Abstract</a></span><br>
<span style="color:#4C945E;font-size:12px;font-weight:600">&#10148; You are here</span>
</td>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#E8F5E9;border-right:none;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-V6kpzFq0uj3tyobvM-VF7ryKjCXg-flashscore-tennis-api-logo.png" width="20" height="20" style="vertical-align:middle">&nbsp;&nbsp;<a href="https://apify.com/zen-studio/flashscore-tennis-api" style="color:#1C1917;text-decoration:none;font-weight:700;font-size:13px">Flashscore Tennis</a></span><br>
<span style="color:#78716C;font-size:12px">Live scores and odds</span>
</td>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#E8F5E9;border-right:none;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-PReplR3mQf3tUpbKG-zUBywwwF1K-bet365-icon_lc6m4t.png" width="20" height="20" style="vertical-align:middle">&nbsp;&nbsp;<a href="https://apify.com/zen-studio/bet365-live-scores" style="color:#1C1917;text-decoration:none;font-weight:700;font-size:13px">Bet365 Scores</a></span><br>
<span style="color:#78716C;font-size:12px">13 sports, live</span>
</td>
<td style="padding:12px 16px;border:1px solid #E7E5E4;border-radius:0 0 4px 0;background:#E8F5E9;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-W8rOXiLSj8wrgF96k-PQehXxTEV5-draftkings-real-time-api-logo.png" width="20" height="20" style="vertical-align:middle">&nbsp;&nbsp;<a href="https://apify.com/zen-studio/draftkings-odds" style="color:#1C1917;text-decoration:none;font-weight:700;font-size:13px">DraftKings Odds</a></span><br>
<span style="color:#78716C;font-size:12px">Lines, props, SGP</span>
</td>
</tr>
</table>

### Key Features

<table>
<tr>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#F0FDF4;vertical-align:top;width:50%;border-radius:4px 0 0 0">
<span style="color:#1C1917;font-weight:700;font-size:14px">&#128203;&nbsp;&nbsp;112 fields per match</span><br>
<span style="color:#57534E;font-size:13px">Result, score, sets, surface, round, both players, stats and rates</span>
</td>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#F0FDF4;vertical-align:top;width:50%;border-left:none;border-radius:0 4px 0 0">
<span style="color:#1C1917;font-weight:700;font-size:14px">&#128100;&nbsp;&nbsp;ATP and WTA together</span><br>
<span style="color:#57534E;font-size:13px">One input, both tours, active and retired players alike</span>
</td>
</tr>
<tr>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#E8F5E9;vertical-align:top;width:50%;border-top:none">
<span style="color:#1C1917;font-weight:700;font-size:14px">&#128197;&nbsp;&nbsp;Three decades deep</span><br>
<span style="color:#57534E;font-size:13px">Serena Williams goes back to 1995, Federer to 1996</span>
</td>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#E8F5E9;vertical-align:top;width:50%;border-top:none;border-left:none">
<span style="color:#1C1917;font-weight:700;font-size:14px">&#127919;&nbsp;&nbsp;Head to head in one field</span><br>
<span style="color:#57534E;font-size:13px">Name an opponent and get only those meetings, with full stats</span>
</td>
</tr>
<tr>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#F0FDF4;vertical-align:top;width:50%;border-top:none;border-radius:0 0 0 4px">
<span style="color:#1C1917;font-weight:700;font-size:14px">&#128202;&nbsp;&nbsp;Rankings and Elo lists</span><br>
<span style="color:#57534E;font-size:13px">Around 2,000 ranked players per tour, plus the Elo leaderboard</span>
</td>
<td style="padding:12px 16px;border:1px solid #E7E5E4;background:#F0FDF4;vertical-align:top;width:50%;border-top:none;border-left:none;border-radius:0 0 4px 0">
<span style="color:#1C1917;font-weight:700;font-size:14px">&#9881;&nbsp;&nbsp;Filters that do the work</span><br>
<span style="color:#57534E;font-size:13px">Surface, level, round, opponent, date range, opponent ranking</span>
</td>
</tr>
</table>

### How to Scrape Tennis Abstract Player Data

#### Basic: one player's full career

```json
{
    "players": ["Novak Djokovic"]
}
```

Names work as you would write them. Short forms without spaces work too, and so does a pasted player page link.

#### Clay-court finals only

```json
{
    "players": ["Rafael Nadal"],
    "surfaces": ["clay"],
    "rounds": ["F"]
}
```

#### A head-to-head record

```json
{
    "players": ["Iga Swiatek"],
    "opponent": "Aryna Sabalenka"
}
```

#### Grand Slam results with point-by-point detail

```json
{
    "players": ["Carlos Alcaraz"],
    "levels": ["G"],
    "includePointByPoint": true
}
```

#### Today's rankings and Elo ratings, no player needed

```json
{
    "rankings": "both",
    "elo": "both"
}
```

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `players` | array | *one of these is required* | Player names, short forms, or player page links |
| `surfaces` | array | all | `hard`, `clay`, `grass`, `carpet` |
| `levels` | array | all | Tournament level: `G` Grand Slam, `M` Masters, `A` ATP Tour, `F` Tour Finals, `O` Olympics, `D` Davis Cup or Billie Jean King Cup, `C` Challenger, `S` Futures, `Q` Qualifying, `J` Juniors, `P` WTA Premier, `PM` WTA Premier Mandatory, `I` WTA International, `W` WTA Tour, `T1` to `T4` WTA Tiers |
| `rounds` | array | all | Round codes such as `F`, `SF`, `QF`, `R16` |
| `results` | array | both | `win` or `loss` |
| `opponent` | string | *none* | Keep only matches against this player |
| `maxOpponentRank` | integer | *none* | Keep only matches against opponents ranked this high or better |
| `fromDate` | string | *none* | Earliest match date, `YYYY-MM-DD` |
| `toDate` | string | *none* | Latest match date, `YYYY-MM-DD` |
| `includePointByPoint` | boolean | `false` | Add shot-by-shot detail for matches that have it |
| `rankings` | string | *none* | `atp`, `wta` or `both` |
| `elo` | string | *none* | `atp`, `wta` or `both` |
| `maxResults` | integer | *none* | Stop after this many records |

At least one of `players`, `rankings` or `elo` must be set. Filters are optional and combine freely.

### What Data Can You Extract from Tennis Abstract?

Every match record carries:

- **The match**: date, tournament, level and its name, surface, round and its name, best of, score, set-by-set games and tiebreak points, duration in minutes, winner, loser, retirement and walkover flags.
- **Both players**: name, ranking, seed, entry route, country, handedness, backhand, height, birthdate and age at the match.
- **Serve and return counts**: aces, double faults, serve points, first serves in, first and second serve points won, service games, break points saved and faced, mirrored for the opponent.
- **Derived rates**: ace rate, double fault rate, first serve in, first and second serve points won, serve and return points won, total points won, dominance ratio, hold, break, break point conversion.
- **The player's profile**: current rank, peak rank and the dates it was held, Elo rating and Elo rank, doubles rank, and identifiers for cross-referencing.

#### Output Example

```json
{
  "record_type": "match",
  "match_id": "2026-540-601",
  "date": "2026-06-29",
  "tournament": "Wimbledon",
  "level": "G",
  "level_name": "Grand Slam",
  "surface": "Grass",
  "round": "SF",
  "round_name": "Semifinal",
  "best_of": 5,
  "score": "6-4 6-4 6-4",
  "result": "loss",
  "winner": "Jannik Sinner",
  "loser": "Novak Djokovic",
  "duration_minutes": 140,
  "player_name": "Novak Djokovic",
  "player_slug": "NovakDjokovic",
  "player_tour": "atp",
  "player_rank": 8,
  "player_seed": 7,
  "opponent_name": "Jannik Sinner",
  "opponent_slug": "JannikSinner",
  "opponent_id": "206173",
  "opponent_rank": 1,
  "opponent_seed": 1,
  "opponent_country": "ITA",
  "opponent_hand": "R",
  "opponent_hand_name": "Right",
  "opponent_backhand": "2",
  "opponent_backhand_name": "Two-handed",
  "opponent_height_cm": 191,
  "opponent_birthdate": "2001-08-16",
  "opponent_age": 24.9,
  "sets": [
    { "player_games": 4, "opponent_games": 6, "tiebreak_loser_points": null, "is_tiebreak": false, "is_match_tiebreak": false, "is_complete": true },
    { "player_games": 4, "opponent_games": 6, "tiebreak_loser_points": null, "is_tiebreak": false, "is_match_tiebreak": false, "is_complete": true },
    { "player_games": 4, "opponent_games": 6, "tiebreak_loser_points": null, "is_tiebreak": false, "is_match_tiebreak": false, "is_complete": true }
  ],
  "sets_won": 0,
  "sets_lost": 3,
  "games_won": 12,
  "games_lost": 18,
  "tiebreaks_played": 0,
  "tiebreaks_won": 0,
  "is_retirement": false,
  "is_walkover": false,
  "is_default": false,
  "is_completed": true,
  "aces": 8,
  "double_faults": 3,
  "serve_points": 105,
  "first_serves_in": 67,
  "first_serve_points_won": 51,
  "second_serve_points_won": 13,
  "service_games": 15,
  "break_points_saved": 10,
  "break_points_faced": 13,
  "opponent_aces": 16,
  "opponent_double_faults": 0,
  "opponent_serve_points": 79,
  "opponent_first_serves_in": 51,
  "opponent_first_serve_points_won": 45,
  "opponent_second_serve_points_won": 17,
  "opponent_service_games": 15,
  "opponent_break_points_saved": 1,
  "opponent_break_points_faced": 1,
  "break_points_converted": 0,
  "service_games_held": 12,
  "ace_rate": 0.0762,
  "double_fault_rate": 0.0286,
  "first_serve_in_pct": 0.6381,
  "first_serve_points_won_pct": 0.7612,
  "second_serve_points_won_pct": 0.3421,
  "serve_points_won_pct": 0.6095,
  "return_points_won_pct": 0.2152,
  "total_points_won_pct": 0.4402,
  "dominance_ratio": 0.5511,
  "hold_pct": 0.8,
  "break_pct": 0.0,
  "break_points_conversion_pct": 0.0,
  "has_statistics": true,
  "has_point_by_point": true,
  "player_country": "SRB",
  "player_birthdate": "1987-05-22",
  "player_height_cm": 188,
  "player_hand": "R",
  "player_hand_name": "Right",
  "player_backhand": "2",
  "player_backhand_name": "Two-handed",
  "player_current_rank": 5,
  "player_peak_rank": 1,
  "player_peak_rank_first": "2011-07-04",
  "player_peak_rank_last": "2024-05-27",
  "player_elo_rating": 2061,
  "player_elo_rank": 4,
  "player_is_active": true,
  "points": [
    {
      "point_number": 1,
      "server": "Novak Djokovic",
      "sets_score": "0-0",
      "games_score": "0-0",
      "points_score": "0-0",
      "description": "1st serve down the T; backhand slice return crosscourt (very deep); forehand down the middle; backhand crosscourt; forehand down the line (net), unforced error. (7-shot rally)",
      "rally_length": 7,
      "outcome": "unforced error"
    }
  ],
  "shot_statistics": {
    "serve_basics": [
      { "category": "1st serve", "Pts": "67", "Won---%": "51 (76%)", "Aces---%": "8 (12%)" }
    ],
    "rally_outcomes": [
      { "category": "1-3 shots", "Pts": "104", "Wnrs----%": "22 (21%)", "UFE-----%": "14 (13%)" }
    ]
  },
  "source_url": "https://www.tennisabstract.com/cgi-bin/player-classic.cgi?p=NovakDjokovic"
}
```

`points` and `shot_statistics` appear when `includePointByPoint` is on and the match has that detail. The `shot_statistics` object holds 15 tables covering serve placement, return outcomes, key points, rally outcomes, shot types, shot direction and net play.

An Elo record looks like this:

```json
{
  "record_type": "elo",
  "tour": "atp",
  "elo_rank": 1,
  "player_name": "Jannik Sinner",
  "player_slug": "JannikSinner",
  "age": 24.8,
  "elo_rating": 2321.9,
  "hard_elo_rank": 1,
  "hard_elo_rating": 2259.3,
  "clay_elo_rank": 1,
  "clay_elo_rating": 2211.8,
  "grass_elo_rank": 1,
  "grass_elo_rating": 2125.5,
  "peak_elo_rating": 2339.8,
  "peak_elo_month": "2026-05",
  "tour_rank": 1,
  "log_diff": 0
}
```

### Advanced Usage

Ready-made configurations for tennis betting models, surface-specific form analysis, head-to-head previews, historical research and machine-learning datasets.

#### Surface form for a betting model

```json
{
    "players": ["Carlos Alcaraz", "Jannik Sinner", "Alexander Zverev"],
    "surfaces": ["clay"],
    "fromDate": "2023-01-01"
}
```

Every row carries the serve and return counts, so hold and break rates on the surface come straight out of the dataset.

#### Results against top-10 opposition

```json
{
    "players": ["Coco Gauff"],
    "maxOpponentRank": 10
}
```

#### A training set with the ratings attached

```json
{
    "players": ["Novak Djokovic", "Rafael Nadal", "Roger Federer"],
    "elo": "atp"
}
```

#### One rivalry, every meeting, shot by shot

```json
{
    "players": ["Novak Djokovic"],
    "opponent": "Rafael Nadal",
    "includePointByPoint": true
}
```

#### Grand Slam finals across a career

```json
{
    "players": ["Serena Williams"],
    "levels": ["G"],
    "rounds": ["F"]
}
```

### Pricing: Pay Per Event

**$1.99 per 1,000 matches** at the base rate, with volume discounts on higher Apify plans.

| Event | Per 1,000 |
|-------|-----------|
| Match | $1.99 |
| Player loaded | $4.99 |
| Ranking or Elo entry | $0.49 |
| Point-by-point match | $19.99 |

A player's complete career is billed per match, so a deep career costs a few dollars and a filtered slice costs cents. Point-by-point is charged only for matches that actually carry it, never for the ones that do not.

### FAQ

**What is Tennis Abstract?**
Tennis Abstract is a long-running tennis analytics site built around a match database that reaches back to the 1990s. It publishes career logs for ATP and WTA players with the serve and return counts behind each result, Elo ratings including surface-specific ones, and shot-by-shot charting contributed by volunteers. This Actor turns any player's page into structured rows.

**How far back does the data go?**
It depends on the player and the tier they played. Serena Williams reaches 1995 and Roger Federer 1996. Depth is deeper for main-tour players than for lower tiers, so the honest answer is that the Actor returns everything on record for the player you ask for.

**Does it cover WTA as well as ATP?**
Yes, both, in the same run and the same output shape. You do not need to say which tour a player is on.

**Can I get a head-to-head record?**
Yes. Set `opponent` to the other player and you get only those meetings, each with full statistics, which is a head-to-head with the numbers attached rather than just a win count.

**How complete are the match statistics?**
Around 90% of a main-tour career carries serve and return counts. Older matches and lower-tier events often do not, and those fields come back as null rather than zero so you can tell the difference between an unrecorded match and a genuine nil.

**What is dominance ratio?**
The share of return points won divided by the share of serve points lost. Above 1.0 means a player was doing more damage on return than they conceded on serve. It is calculated here with the same formula the source itself displays.

**Which matches have point-by-point detail?**
A large share of main-tour matches from recent decades, because the charting is volunteer work rather than an automated feed. Every record tells you up front with `has_point_by_point`, so you can filter before switching the option on.

**Do I need an account or cookies?**
No. Enter player names and run it.

**How do I export the data?**
JSON, CSV, Excel, XML or HTML from the run's Storage tab, or through the Apify API. JSON keeps the nested `sets`, `points` and `shot_statistics` fields intact; CSV flattens them.

**Can I get live scores and odds too?**
Not here, this Actor is historical. [Flashscore Tennis](https://apify.com/zen-studio/flashscore-tennis-api) covers live scores, fixtures, bookmaker odds and today's matches, and joins to this one on player name.

**Is it legal to scrape Tennis Abstract data?**
The Actor collects publicly available pages only. You are responsible for complying with the source's terms and with data protection law, including GDPR and CCPA. Player names and birthdates are personal data; treat them accordingly.

**Why did my run return no players?**
The name did not match. Use the player's name as it appears on their page, for example `Novak Djokovic`. The run log names any player it could not resolve.

### More Zen Studio scrapers for sports betting

**🏟️ Sportsbook odds**

- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-Pjlm871yhJCOjQh6I-xTwdMYSjNa-action-network-odds-icon.png" width="16" height="16" alt="Action Network scraper icon" style="vertical-align:middle;border-radius:3px"> **Action Network**
  - [Action Network Odds API](https://apify.com/zen-studio/action-network-odds)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-oLjv3CSV3BhHm5dGN-62o7r64lQq-fanduel-odds-api-logo.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **FanDuel**
  - [FanDuel Odds API](https://apify.com/zen-studio/fanduel-odds)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-W8rOXiLSj8wrgF96k-PQehXxTEV5-draftkings-real-time-api-logo.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **DraftKings**
  - [DraftKings Odds API](https://apify.com/zen-studio/draftkings-odds)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-TjShOnNguT17e9hfQ-ntCswWAqze-betmgm-real-time-api-logo-padded.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **BetMGM**
  - [BetMGM Odds API](https://apify.com/zen-studio/betmgm-odds)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-l6JP3yaLczAdUaiSf-yDHq17ycGp-bet365-icon_lc6m4t.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **Bet365**
  - [Bet365 Real-Time Odds API](https://apify.com/zen-studio/bet365-real-time-odds)
  - [Bet365 Live Scores API](https://apify.com/zen-studio/bet365-live-scores)
  - [Bet365 Sports Data Scraper](https://apify.com/zen-studio/bet365-sports-data)

**🎯 Daily fantasy & player props**

- <img src="https://api.apify.com/v2/key-value-stores/pJ7iaZsTFhR3k9tjV/records/player-props-aggregator-icon.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **Player Props Aggregator**
  - [Player Props Line Shopping](https://apify.com/zen-studio/player-props-aggregator)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-4AmgQeem8dEgMEiRF-VGffbe665M-prizepicks-scraper-logo.jpeg" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **PrizePicks**
  - [PrizePicks Player Props Scraper](https://apify.com/zen-studio/prizepicks-player-props)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-09TtSjF9Uzs5qfvLc-f9HhMKXsLt-underdog-fantasy-picks-api-logo.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **Underdog Fantasy**
  - [Underdog Fantasy Player Props API](https://apify.com/zen-studio/underdog-player-props)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-vZGwNIMCrwkjp76uR-6jWYFxsPSD-sleeper-fantasy-api-logo.jpg" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **Sleeper**
  - [Sleeper Player Props](https://apify.com/zen-studio/sleeper-player-props)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-otCGHYjTnE0YKgVNJ-iYqrcfxJiq-draftkings-pick6-api-logo.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **DraftKings Pick6**
  - [DraftKings Pick6 Player Props](https://apify.com/zen-studio/draftkings-pick6-player-props)
- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-l6JP3yaLczAdUaiSf-yDHq17ycGp-bet365-icon_lc6m4t.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **Bet365**
  - [Bet365 Player Props API](https://apify.com/zen-studio/bet365-player-props)

**🎾 Live scores & match data**

- <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/NWYsOG96fMDy8ycdf-actor-V6kpzFq0uj3tyobvM-VF7ryKjCXg-flashscore-tennis-api-logo.png" width="16" height="16" style="vertical-align:middle;border-radius:3px"> **Flashscore**
  - [Flashscore Tennis Scraper & API](https://apify.com/zen-studio/flashscore-tennis-api)

### Support

- **Bugs**: Issues tab
- **Features**: Issues tab

### Legal Compliance

Extracts publicly available data. Users must comply with the source's terms and data protection regulations (GDPR, CCPA).

***

*Complete ATP and WTA career match logs with serve and return statistics, Elo ratings by surface, and shot-by-shot point-by-point detail.*

# Actor input Schema

## `players` (type: `array`):

Player names, one per line. Full names work (<b>Novak Djokovic</b>), so do short forms without spaces (<b>NovakDjokovic</b>) and pasted player page links. ATP and WTA both, active and retired. Each player returns their complete career.

## `surfaces` (type: `array`):

Keep only matches on these surfaces. Leave empty for all.

## `levels` (type: `array`):

Keep only matches at these levels. Leave empty for all.

## `rounds` (type: `array`):

Keep only these rounds, for example <b>F</b> for finals. Leave empty for all.

## `results` (type: `array`):

Keep only wins, or only losses. Leave empty for both.

## `opponent` (type: `string`):

Keep only matches against this player, for example <b>Rafael Nadal</b>. Gives you a head-to-head record.

## `maxOpponentRank` (type: `integer`):

Keep only matches against opponents ranked this high or better. Enter <b>10</b> for results against the top 10.

## `fromDate` (type: `string`):

Keep only matches on or after this date, as <b>YYYY-MM-DD</b>.

## `toDate` (type: `string`):

Keep only matches on or before this date, as <b>YYYY-MM-DD</b>.

## `includePointByPoint` (type: `boolean`):

Add shot-by-shot records for every charted match: each point's serve, rally and outcome, plus serve placement, return outcomes, rally length, shot types, shot direction and net points. Available for a large share of main-tour matches from recent decades. <b>Adds a lot of data and time to a run.</b>

## `rankings` (type: `string`):

Add the full current ranking list, roughly 2,000 players per tour.

## `elo` (type: `string`):

Add the Elo leaderboard: overall rating and rank, separate ratings for hard, clay and grass, plus each player's peak and the month they reached it.

## `maxResults` (type: `integer`):

Stop after this many records. Leave empty for everything the filters match.

## Actor input object example

```json
{
  "players": [
    "Novak Djokovic",
    "Iga Swiatek"
  ],
  "includePointByPoint": false
}
```

# Actor output Schema

## `matches` (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 = {
    "players": [
        "Novak Djokovic",
        "Iga Swiatek"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zen-studio/tennis-abstract-scraper").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 = { "players": [
        "Novak Djokovic",
        "Iga Swiatek",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("zen-studio/tennis-abstract-scraper").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 '{
  "players": [
    "Novak Djokovic",
    "Iga Swiatek"
  ]
}' |
apify call zen-studio/tennis-abstract-scraper --silent --output-dataset

```

## MCP server setup

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

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/aSaCGC6CeIt8UFbft/builds/dIUdccQNnfsEb58Lw/openapi.json
