# Tennis Player Match Stats Scraper - ATP & WTA Results (`scrapers_lat/tennis-player-match-stats-scraper`) Actor

Scrape ATP and WTA player match results with serve and return stats: aces, double faults, 1st serve %, break points, opponent, surface, round, score and career summary. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/scrapers\_lat/tennis-player-match-stats-scraper.md
- **Developed by:** [Scrapers Lat](https://apify.com/scrapers_lat) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.32 / 1,000 results

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/platform/actors/running/actors-in-store#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 Player Match Stats Scraper - ATP & WTA Results](https://scrapers.lat/banners/tennis-player-match-stats-scraper.png)](https://apify.com/scrapers_lat/tennis-player-match-stats-scraper)

## Tennis Player Match Stats Scraper - ATP & WTA Results

Scrape a complete, match-by-match career log for any ATP or WTA player, with full serve and return statistics for both the player and the opponent in every match. Built for tennis analytics, betting models, media and research.

Here is one real result row (Carlos Alcaraz vs Jannik Sinner, ATP Finals 2025):

```json
{
  "recordType": "match",
  "playerName": "Carlos Alcaraz",
  "playerId": "CarlosAlcaraz",
  "tour": "atp",
  "playerHand": "R",
  "playerCountry": "ESP",
  "playerHeightCm": 183,
  "playerDob": "2003-05-05",
  "tourneyName": "Tour Finals",
  "tourneyId": "2025-0605",
  "matchId": "2025-0605-385",
  "tourneyDate": "2025-11-09",
  "year": 2025,
  "tourneyLevel": "Tour Finals",
  "tourneyLevelCode": "F",
  "surface": "Hard",
  "round": "F",
  "bestOf": 3,
  "result": "L",
  "score": "7-6(4) 7-5",
  "sets": 2,
  "minutes": 135,
  "opponentName": "Jannik Sinner",
  "opponentId": "206173",
  "opponentRank": 2,
  "opponentSeed": 2,
  "opponentHand": "R",
  "opponentCountry": "ITA",
  "opponentHeightCm": 191,
  "opponentAgeAtTime": 24.2,
  "playerRankAtTime": 1,
  "playerSeed": 1,
  "playerAgeAtTime": 22.5,
  "aces": 5,
  "doubleFaults": 0,
  "servePoints": 72,
  "firstServeIn": 49,
  "firstServeWon": 36,
  "secondServeWon": 13,
  "serviceGames": 12,
  "bpSaved": 0,
  "bpFaced": 2,
  "firstServePct": 68.1,
  "firstServeWonPct": 73.5,
  "secondServeWonPct": 56.5,
  "servicePointsWonPct": 68.1,
  "bpSavedPct": 0,
  "acePct": 6.9,
  "dfPct": 0,
  "opponentAces": 8,
  "opponentDoubleFaults": 5,
  "opponentServePoints": 78,
  "opponentFirstServeIn": 43,
  "opponentFirstServeWon": 36,
  "opponentSecondServeWon": 19,
  "opponentBpSaved": 2,
  "opponentBpFaced": 3,
  "opponentFirstServePct": 55.1,
  "opponentFirstServeWonPct": 83.7,
  "opponentSecondServeWonPct": 54.3,
  "returnPointsWonPct": 29.5,
  "chartUrl": "https://www.tennisabstract.com/charting/20251116-M-Tour_Finals-F-Carlos_Alcaraz-Jannik_Sinner.html",
  "sourceUrl": "https://www.tennisabstract.com/cgi-bin/player-classic.cgi?p=CarlosAlcaraz",
  "source": "tennisabstract",
  "observedAt": "2026-08-16T22:11:34.407Z"
}
```

**📥 [Input](https://apify.com/scrapers_lat/tennis-player-match-stats-scraper/input-schema) · 📤 [Output](https://apify.com/scrapers_lat/tennis-player-match-stats-scraper/output-schema) · 💰 [Pricing](https://apify.com/scrapers_lat/tennis-player-match-stats-scraper/pricing) · ▶️ [Examples](https://apify.com/scrapers_lat/tennis-player-match-stats-scraper/examples)**

![Apify](https://img.shields.io/badge/Platform-Apify-1CE1CE?logo=apify\&logoColor=white)
![Tours](https://img.shields.io/badge/Tours-ATP%20%7C%20WTA-blue)
![Output](https://img.shields.io/badge/Output-JSON%20%7C%20CSV%20%7C%20Excel-orange)
![Billing](https://img.shields.io/badge/Billing-Pay%20per%20result-brightgreen)

### What you get

The most complete tennis player match-stats export available. For every player you request, the actor returns one row per singles match across their whole career, and each row carries far more than the score:

- **Match context**: tournament, tournament level (Grand Slam, Masters 1000, WTA 1000, Tour, Finals, Olympics), surface, round, date, best-of, score, sets and match duration in minutes.
- **Opponent detail**: name, ranking at match time, seed, entry, playing hand, country, height and age, plus opponent id for head-to-head joins.
- **Player serve and return stats**: aces, double faults, serve points, first serves in, first and second serve points won, service games, break points saved and faced, plus derived first serve %, first serve won %, second serve won %, service points won %, break points saved %, ace % and double fault %.
- **Opponent serve and return stats**: the same full stat block for the opponent, so you can model both sides of every match, including your player's return points won %.
- **Player bio**: hand, country, height and date of birth, plus ranking and age at the time of each match.
- **Optional career summary** (add-on): one aggregated record per player with wins and losses overall and by surface, titles, finals reached, record versus the top 10, career serve and return averages, current ranking and career-high ranking.
- **Optional AI scouting report** (add-on): playing style, strengths, weaknesses, surface preference and current form, generated from the aggregated numbers.

Filter by season, year range, surface, opponent (for an instant head-to-head log) or tour-level events only. Pass a single player or a list of players to batch many in one run. Empty or failed lookups are never charged.

### Who is it for

- **Sports bettors and traders** building serve, return and surface edges for ATP and WTA match markets.
- **Tennis analysts, coaches and scouts** studying an opponent's patterns, form and head-to-head record.
- **Media, bloggers and stats accounts** that need clean, exportable match data and career splits.
- **Data scientists and quants** training tennis prediction models on rich per-match serve and return features.
- **Fantasy tennis and product teams** that need a reliable player match-log feed.

### How to use it

1. Enter one or more **players** by full name or Tennis Abstract id, for example `Carlos Alcaraz`, `Novak Djokovic`, `Iga Swiatek`, `Aryna Sabalenka`.
2. Set **tour** to `atp` or `wta` to match the players.
3. Optionally filter by **season**, **year from/to**, **surface**, **opponent** (head-to-head) or **match type** (tour-level only).
4. Set **max matches** and, on a paid plan, toggle the **career summary** and **AI scouting report** add-ons.
5. Run and export the results to JSON, CSV or Excel.

### Input reference

| Field | Type | Description |
| --- | --- | --- |
| `players` | array | One or more players by full name or Tennis Abstract id. A single string is accepted too. |
| `tour` | select | `atp` or `wta`. Default `atp`. |
| `season` | integer | Optional. Only matches from this single year. |
| `yearFrom` | integer | Optional. Only matches in or after this year. |
| `yearTo` | integer | Optional. Only matches in or before this year. |
| `surface` | select | Optional. Hard, Clay, Grass or Carpet. |
| `opponent` | string | Optional. Only matches against this opponent (name substring) for a head-to-head log. |
| `matchType` | select | `all` or `tour-level` (excludes Challenger and ITF events). |
| `maxMatches` | integer | Max match rows across all players. Free plans are capped at 10. |
| `includeCareerSummary` | boolean | Paid add-on. Adds one aggregated career record per player. |
| `withAiReport` | boolean | Paid add-on. Adds an AI scouting report per player. |

### Output reference

Each match row includes `playerName`, `tour`, `tourneyName`, `tourneyDate`, `tourneyLevel`, `surface`, `round`, `score`, `sets`, `minutes`, `result`, the opponent block (`opponentName`, `opponentRank`, `opponentSeed`, `opponentCountry`, `opponentHand`, `opponentHeightCm`, `opponentId`), the player context (`playerRankAtTime`, `playerSeed`, `playerAgeAtTime`, `playerHand`, `playerCountry`, `playerHeightCm`, `playerDob`), and the full serve and return stat blocks for both players with derived percentages. Career-summary and AI-report records add aggregated and qualitative fields. See the Output schema for every field.

### Use cases

- Scrape **ATP match results** and **WTA match results** with serve stats for betting and trading models.
- Build a **tennis head-to-head** database (H2H) between any two players across surfaces.
- Analyze **serve statistics** like aces, first serve percentage, break points saved and service hold rates.
- Track **surface splits** (hard, clay, grass) and form for ATP and WTA players.
- Power **tennis analytics dashboards**, fantasy tennis tools and sports-data products.
- Feed **tennis prediction models** and machine learning pipelines with per-match features.
- Monitor a player's **ranking at match time**, seedings and results versus top-10 opponents.
- Export **career stats**, titles and win-loss splits for player profiles and media.

### Billing

This actor is pay per event, with no subscription and no charge for empty or failed runs.

| Event | Price (USD) | When it is charged |
| --- | --- | --- |
| `result` | 0.008 | Per match row returned. |
| `career_summary` | 0.008 | Once per player, only when the career summary add-on is enabled and produced. |
| `ai_scouting_report` | 0.012 | Once per player, only when the AI scouting report add-on returns usable output. |

Free Apify accounts are capped at 10 match rows per run and cannot use the paid add-ons. Anti-bot handling and proxying are managed internally, so no login or configuration is required.

### Data sources

Match logs, serve and return statistics and player bios are compiled from public Tennis Abstract player pages. The actor loads the full career match data for each player and enriches every row with derived serving and returning percentages that the raw pages do not expose.

### FAQ

**Which players are covered?** Any player with a Tennis Abstract page on the ATP or WTA tour, current or historical.

**Do I get the full career or just recent matches?** The full singles career log is returned by default. Use the season or year filters to narrow it.

**Can I get a head-to-head?** Yes. Set the `opponent` field to return only matches against that opponent.

**Is the opponent's data included?** Yes. Every row carries the opponent's full serve and return stats plus their ranking, seed, hand, country and height.

**How do I export?** Download the dataset as JSON, CSV or Excel, or pull it from the Apify API.

***

Built by scrapers.lat. Not affiliated with, endorsed by or connected to the ATP, WTA, or Tennis Abstract. All data is public information.

# Actor input Schema

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

One or more players to scrape in a single run. Use a full name or a Tennis Abstract player id, e.g. "Carlos Alcaraz", "Novak Djokovic", "Iga Swiatek", "Aryna Sabalenka". Set the Tour field to match (atp or wta).

## `tour` (type: `string`):

Which tour the players belong to.

## `season` (type: `integer`):

Optional. Return only matches from this single season, e.g. 2024. Leave empty for full career. Overridden by Year From / Year To if those are set.

## `yearFrom` (type: `integer`):

Optional. Only return matches in or after this year.

## `yearTo` (type: `integer`):

Optional. Only return matches in or before this year.

## `surface` (type: `string`):

Optional. Filter matches by court surface.

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

Optional. Return only matches against this opponent (name substring), e.g. "Sinner" for a head-to-head log.

## `matchType` (type: `string`):

Filter which competitions to include. Tour-level excludes Challenger and ITF / Satellite events.

## `maxMatches` (type: `integer`):

Maximum number of match rows to return across all players in this run. Free Apify plans are capped at 10.

## `includeCareerSummary` (type: `boolean`):

Off by default. Adds one extra summary record per player: win/loss overall and by surface, titles, finals, record vs top-10, career serve and return averages, current and career-high rank. Requires a paid Apify plan. Billed once per player.

## `withAiReport` (type: `boolean`):

Off by default. Generates an AI scouting report per player (playing style, strengths, weaknesses, surface preference, form) from the aggregated stats. Requires a paid Apify plan. Billed only when a report is produced.

## Actor input object example

```json
{
  "players": [
    "Carlos Alcaraz"
  ],
  "tour": "atp",
  "surface": "",
  "matchType": "all",
  "maxMatches": 100,
  "includeCareerSummary": false,
  "withAiReport": false
}
```

# Actor output Schema

## `results` (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": [
        "Carlos Alcaraz"
    ],
    "maxMatches": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers_lat/tennis-player-match-stats-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": ["Carlos Alcaraz"],
    "maxMatches": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapers_lat/tennis-player-match-stats-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": [
    "Carlos Alcaraz"
  ],
  "maxMatches": 100
}' |
apify call scrapers_lat/tennis-player-match-stats-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapers_lat/tennis-player-match-stats-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/f0VmxYZosDNSQjL1h/builds/wTj5wCHffPe7Mcu0X/openapi.json
