# Tennis Match Data — Live, Fixtures, Results & Model-Ready Stats (`signallayer/tennis-match-data`) Actor

Tennis data for ATP, WTA, Challenger & ITF: live scores, fixtures, results, rankings and model-ready pre-match feature rows (form, H2H, surface splits).

- **URL**: https://apify.com/signallayer/tennis-match-data.md
- **Developed by:** [Max](https://apify.com/signallayer) (community)
- **Categories:** Sports, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 model-ready rows

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Match Data — Live Scores, Fixtures, Results & Model-Ready Stats

Tennis data API for **ATP, WTA, Challenger and ITF**: live scores, fixtures, results, rankings — and the only tennis scraper on Apify that outputs **model-ready pre-match feature rows**: current form, head-to-head, surface record, fatigue indicators and market form, merged and computed for you. Built for betting models, fantasy tools, live scoreboards and tennis analytics.

### Why this Actor?

Raw tennis scrapers give you match listings. **Prediction models need features.** Before you can model a match you normally have to collect each player's recent results, surface splits, head-to-head and schedule density yourself. This Actor does that work in one call:

```json
{ "mode": "model-ready", "day": 0, "tours": ["ATP"] }
```

→ one row per upcoming singles match, with both players' form already computed:

| Feature | Example (real output) |
|---|---|
| Rank / career high | 226 / 214 |
| Last 10 matches | 7–3 |
| Surface record, last 12 months | 30–9 on hard |
| Days since last match | 14 |
| Matches / sets in last 14 days | 1 / 2 |
| Comeback after 30+ day break | false |
| Retired in last match | false |
| Avg. closing odds, last 5 | 1.50 |
| Head-to-head (overall / this surface) | 2–0 / 1–0 |

Every row carries a `dataQuality` block (`complete` flag + notes), so your pipeline knows exactly what it got.

### Modes

| Mode | What you get | Typical use |
|---|---|---|
| `model-ready` | One feature row per upcoming singles match | Prediction models, betting analytics |
| `fixtures` | Upcoming matches: players, tournament, surface, start time | Schedules, draft lobbies |
| `results` | Finished matches: set scores, duration, retirements/walkovers | Results digests, training datasets |
| `live` | Matches in play: current sets/games, status | Live scoreboards |
| `rankings` | Current ATP or WTA ranking list (rank, player, country, points) | Enrichment, seeding |
| `all` | Every match of the day, any status | Bulk ingestion |

All modes cover **singles and doubles** (doubles opt-in via `includeDoubles`) across **ATP, WTA, Challenger, ITF, UTR and exhibitions**, filterable with `tours`.

### Input

```json
{
  "mode": "model-ready",
  "day": 0,
  "tours": ["ATP", "WTA"],
  "includeDoubles": false,
  "maxItems": 100
}
```

- **mode** — see table above.
- **day** — day offset: `0` today, `-1` yesterday, `1` tomorrow. Results reach ~7 days back; fixtures ~1 day ahead.
- **tours** — filter: `ATP`, `WTA`, `CHALLENGER`, `ITF`, `UTR`, `EXHIBITION`. Empty = all.
- **includeDoubles** — include doubles/mixed (default `false`).
- **rankingTour** — `atp` or `wta` (mode `rankings` only).
- **maxItems** — hard cap on output rows (cost control).

### Example output (`fixtures`)

```json
{
  "matchId": "fivcpwcn",
  "source": "flashscore",
  "tournament": {
    "tour": "ATP", "discipline": "SINGLES", "name": "Winston-Salem",
    "location": "USA", "surface": "hard", "tourGroup": "ATP"
  },
  "home": { "name": "Altmaier D.", "slug": "altmaier-daniel", "country": "Germany" },
  "away": { "name": "Comesana F.", "slug": "comesana-francisco", "country": "Argentina" },
  "status": "scheduled",
  "startTime": "2026-08-25T00:10:00.000Z",
  "setsWon": { "home": null, "away": null },
  "setScores": []
}
```

Export as **JSON, CSV, Excel or XML**, or read it straight from the API. Nested keys flatten to columns (`playerA.rank`, `h2h.overallA`, …) in tabular exports.

### Use it from code or AI agents

Run via the [Apify API](https://docs.apify.com/api/v2) from any language, schedule it daily in two clicks, or connect it to your AI agent — this Actor works as an **MCP tool**, so agents can query tennis data and pay per result automatically.

```bash
curl "https://api.apify.com/v2/acts/<ACTOR_ID>/run-sync-get-dataset-items?token=<TOKEN>" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"mode":"model-ready","tours":["ATP"]}'
```

### Honest notes on the data

- Day pages are **rolling windows**: `day: -1` can include matches that started up to two days earlier (late finishes, suspended matches). Filter on `startTime` if you need strict dates.
- The fixtures window is short (~1 day ahead). For longer horizons, run daily on a schedule.
- `model-ready` resolves players across two sources by name; rare unresolvable players are reported in `dataQuality.notes` instead of being silently dropped. Rows where **neither** player resolves are skipped and never charged.
- Rankings and player histories come from public tennis statistics pages; live scores and fixtures from a public scores feed. Sources can change without notice — a daily automated health check watches for this, and fixes ship fast (check the Issues tab response time).

### Pricing

Pay per event: you are charged per delivered row (see the Pricing tab). `model-ready` rows cost more than raw rows because each one bundles 4–6 upstream lookups plus feature computation — typically still **>10× cheaper** than tennis data API subscriptions ($29–99/month) for moderate volumes, with no monthly commitment.

### FAQ

**Which tournaments are covered?** Everything on the public scores feed: ATP, WTA, Challenger, ITF (men/women), UTR and exhibitions — singles and doubles.

**Can I get historical data?** `results` reaches ~7 days back per run. For deep history, run daily on a schedule and accumulate — or open an issue and tell us what you need.

**How fresh is `live`?** Each run is a snapshot. Poll every 30–60 s for near-real-time boards.

**Point-by-point data?** Not yet — it is on the roadmap. Tell us in the Issues tab if you need it; user requests set the priority.

**Something broke?** Open an issue — the daily health check usually catches source changes before users do, and fixes are typically same-day.

# Actor input Schema

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

What data to fetch. `model-ready` = one feature row per upcoming singles match (form, H2H, surface record, fatigue — ready for prediction models). `fixtures` = upcoming matches, `results` = finished matches, `live` = matches in play right now, `rankings` = current ATP/WTA rankings, `all` = every match of the day regardless of status.

## `day` (type: `integer`):

Day relative to today: 0 = today, -1 = yesterday, 1 = tomorrow. Fixtures are available ~1 day ahead, results ~7 days back.

## `tours` (type: `array`):

Filter by tour. Empty = all tours.

## `includeDoubles` (type: `boolean`):

Include doubles and mixed doubles matches.

## `rankingTour` (type: `string`):

Which ranking list to fetch when mode is `rankings`.

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

Hard cap on the number of dataset rows (cost control).

## Actor input object example

```json
{
  "mode": "fixtures",
  "day": 0,
  "tours": [],
  "includeDoubles": false,
  "rankingTour": "atp",
  "maxItems": 500
}
```

# Actor output Schema

## `dataset` (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("signallayer/tennis-match-data").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("signallayer/tennis-match-data").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 signallayer/tennis-match-data --silent --output-dataset

```

## MCP server setup

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

```

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/8nAX8S7NDd2dr7Ytd/builds/n0gvSpvstaJjds9Dz/openapi.json
