# TennisExplorer Scraper - Results, Odds, Fixtures & Rankings (`scrapesage/tennisexplorer-scraper`) Actor

Scrape TennisExplorer: ATP and WTA match results by date with set scores, tiebreaks, winners and bookmaker odds; upcoming matches with head-to-head counts and odds; ATP and WTA rankings with points and movement. Any date, any tour. No login, no browser. JSON, CSV, Excel.

- **URL**: https://apify.com/scrapesage/tennisexplorer-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (community)
- **Categories:** AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.83 / 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

## TennisExplorer Scraper - Results, Odds, Fixtures & Rankings

Scrape **tennis match results, upcoming fixtures and rankings from TennisExplorer.com** - the site tennis bettors and analysts use for day-by-day ATP and WTA data. Pick a date range and get every finished match with **set-by-set scores, tiebreak points, the winner and the bookmaker odds** the match closed at; pick upcoming days and get the schedule with **head-to-head counts and pre-match odds**; or pull the current **ATP or WTA ranking table** with points and weekly movement. No login, no API key, no browser - JSON, CSV or Excel.

> **Why this actor exists (demand):** the TennisExplorer niche on Apify draws **~180 monthly users**, almost all on one results-only actor with no reviews. This one covers results, fixtures **and** rankings, keeps the odds and tiebreaks the site shows, and adds implied probabilities - the inputs a betting model or a tennis-stats project actually needs.

### Modes

| Mode | What you get | Record |
|---|---|---|
| **results** | Finished matches for each day in the range: tournament (with country and tour), players (with seeds and profile URLs), sets won, per-set games with tiebreak points, winner, closing odds for both players, implied probabilities, match-detail URL | `match` (`status: finished`) |
| **upcoming** | Scheduled matches for each day: time, tournament, players, head-to-head counts, pre-match odds and implied probabilities, match-detail URL | `match` (`status: upcoming`) |
| **rankings** | The current ATP or WTA ranking table: rank, weekly movement, player, country, points, ranking date, profile URL | `ranking` |

Tour filter for results / upcoming: **ATP + WTA singles**, ATP singles only, or WTA singles only.

### Input

Results for a week of the US Open, both tours:

```json
{ "mode": "results", "tour": "all", "dateFrom": "2026-08-25", "dateTo": "2026-08-31", "maxResults": 2000 }
```

Tomorrow's WTA schedule with odds and H2H:

```json
{ "mode": "upcoming", "tour": "wta-single", "dateFrom": "2026-09-03" }
```

Top 200 ATP ranking:

```json
{ "mode": "rankings", "rankingTour": "atp", "maxResults": 200 }
```

- **Date from / Date to** - `YYYY-MM-DD`, inclusive, up to 60 days per run. Results default to yesterday, upcoming to today.
- **Max records** - caps matches or ranking rows across the run.

Leave everything empty and the run returns a small free sample (yesterday's results, all tours, up to 100 matches).

### Example output (`match`)

```json
{
  "type": "match",
  "status": "finished",
  "date": "2026-08-31",
  "time": "23:45",
  "tournament": "US Open",
  "tournamentUrl": "https://www.tennisexplorer.com/us-open/2026/atp-men/",
  "tournamentCountry": "US",
  "tour": "ATP",
  "player1": "Khachanov K.",
  "player1Url": "https://www.tennisexplorer.com/player/khachanov/",
  "player1Seed": null,
  "player2": "Burruchaga R.",
  "player2Url": "https://www.tennisexplorer.com/player/burruchaga/",
  "setsPlayer1": 3,
  "setsPlayer2": 0,
  "score": "6-3 6-0 6-1",
  "sets": [{ "set": 1, "player1": 6, "player2": 3, "tiebreak": null }, { "set": 2, "player1": 6, "player2": 0, "tiebreak": null }, { "set": 3, "player1": 6, "player2": 1, "tiebreak": null }],
  "winner": "Khachanov K.",
  "oddsPlayer1": 1.25,
  "oddsPlayer2": 3.98,
  "impliedProbPlayer1": 80,
  "impliedProbPlayer2": 25.13,
  "matchId": "3307389",
  "matchUrl": "https://www.tennisexplorer.com/match-detail/?id=3307389",
  "scrapedAt": "2026-09-02T06:00:00.000Z"
}
```

`ranking` records: `rank`, `move`, `player`, `playerUrl`, `country`, `points`, `tour`, `rankingDate`.

### Match details (opt-in)

Turn on **Add match details** (results / upcoming) to open each match's detail page and enrich the record with:

- **Head-to-head** - the career H2H record (`h2hPlayer1Wins` / `h2hPlayer2Wins`) plus `h2hMeetings[]`: every prior meeting with year, tournament, surface, round, score and winner.
- **Player comparison** - `player1Detail` / `player2Detail`: singles ranking, birthdate, height, weight and playing hand.
- **All bookmaker odds** - `oddsBookmakers[]` (up to 30 books with each player's price), `bestOddsPlayer1/2` and `avgOddsPlayer1/2` across the market, `oddsBookmakerCount`, and `oddsMarketCounts` (how many Home-Away, Over-Under, Asian-Handicap and Correct-Score lines the match has). The listing-level `oddsPlayer1/2` remain the single closing price.

One extra request per match, so cap it with **Max match details** (default 200). *TennisExplorer does not publish per-point serve statistics (aces, first-serve %), so those are not available from any lane.*

### Use cases

- **Betting models** - closing odds and implied probabilities alongside the actual result, day by day, for both tours.
- **Tennis analytics** - set scores with tiebreak points for surface, form and momentum studies; ranking movement over time when scheduled weekly.
- **Fixture feeds** - tomorrow's schedule with H2H and odds for previews, newsletters and apps.
- **Player tracking** - filter the dataset by `player1` / `player2` or profile URL to follow specific players through a tournament.

### Notes and limits

- Doubles are not included (TennisExplorer lays doubles out differently); Challenger, ITF and qualifying singles that TennisExplorer lists on the day pages are included.
- Odds are the two decimal prices TennisExplorer shows per match (home / away); a missing odd is an honest `null`.
- Match statistics (aces, serve percentages) live on each match-detail page and are not part of this version.

### Use with AI assistants (MCP)

This actor is available through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp), so assistants like Claude can call it as a tool - "give me yesterday's WTA results with the odds" - and get structured data back.

### Agent-ready: autonomous payments (x402 & Skyfire)

This actor is **agent-ready** - AI agents can discover it, run it, and **pay for it autonomously**, with no Apify account and no human in the loop. It uses [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) pricing and [limited permissions](https://docs.apify.com/platform/actors/development/permissions), so it qualifies for Apify's agentic-payment standards:

- **[x402](https://docs.apify.com/platform/integrations/x402)** - an open, HTTP-native payment protocol. Agents pay per run in USDC on the Base network directly through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) - no account, no API key.
- **[Skyfire](https://docs.apify.com/platform/integrations/skyfire)** - agent-to-service payments for fully autonomous AI-agent workflows.

Building an AI agent, MCP tool, or autonomous data pipeline? This scraper is ready to plug in and pay as it goes.

### Pricing

Pay-per-event, tiered by volume: match records from **$0.0015** (down to **$0.00083** on the Gold tier and above) and ranking rows from **$0.001** (down to **$0.00055**). You pay only for records actually returned; days with no matches and blocked requests cost nothing.

Every run finishes with a clear status message; empty runs never crash and never bill.

***

*TennisExplorer is a trademark of its owner. This actor is an independent tool that reads publicly available pages and is not affiliated with or endorsed by TennisExplorer.*

# Actor input Schema

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

<b>results</b> - finished matches for each day in the date range with set scores, tiebreaks, winner and odds. <b>upcoming</b> - scheduled matches for each day with head-to-head counts and odds. <b>rankings</b> - the current ATP or WTA ranking table.

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

Which singles tour to include. Doubles are not covered (TennisExplorer lays them out differently).

## `dateFrom` (type: `string`):

First day to scrape (results / upcoming). Defaults to yesterday for results and today for upcoming.

## `dateTo` (type: `string`):

Last day to scrape, inclusive (max 60 days per run). Defaults to the same day as <b>Date from</b>.

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

Which ranking to scrape in <b>rankings</b> mode.

## `includeMatchDetails` (type: `boolean`):

For results / upcoming, open each match's detail page and add: head-to-head record and prior meetings, a player comparison (ranking, birthdate, height, weight, hand), and odds from every bookmaker (best / average home-away prices plus the count of Over-Under, Asian-Handicap and Correct-Score markets). One extra request per match, so it is slower - cap it with the next field.

## `maxMatchDetails` (type: `integer`):

When 'Add match details' is on, stop enriching after this many matches (the rest still ship with their listing-level fields).

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

Maximum number of match records (results / upcoming) or ranking rows to return. Ranking pages hold 100 players each.

## `proxyConfiguration` (type: `object`):

TennisExplorer serves full pages to Apify datacenter proxies, so the default is enough.

## Actor input object example

```json
{
  "mode": "results",
  "tour": "all",
  "rankingTour": "atp",
  "includeMatchDetails": false,
  "maxMatchDetails": 200,
  "maxResults": 500,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped TennisExplorer records as JSON items in the default dataset.

# 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 = {
    "mode": "results",
    "tour": "all",
    "rankingTour": "atp",
    "maxMatchDetails": 200,
    "maxResults": 500,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesage/tennisexplorer-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 = {
    "mode": "results",
    "tour": "all",
    "rankingTour": "atp",
    "maxMatchDetails": 200,
    "maxResults": 500,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/tennisexplorer-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 '{
  "mode": "results",
  "tour": "all",
  "rankingTour": "atp",
  "maxMatchDetails": 200,
  "maxResults": 500,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call scrapesage/tennisexplorer-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapesage/tennisexplorer-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/568ytOwPGdEVaIexM/builds/5kmni7yyxYQhPYSaD/openapi.json
