# PGA TOUR Scraper - Results, Scorecards, Odds & Stats (`artsiom_k/pgatour-scraper`) Actor

PGA TOUR, Champions, Korn Ferry and Americas tournament results back to the 1950s, hole-by-hole scorecards, FanDuel odds history including in-play, tee times, Strokes Gained and 500+ player stats, and player bios, from pgatour.com's own data.

- **URL**: https://apify.com/artsiom_k/pgatour-scraper.md
- **Developed by:** [Artsiom Kunitsyn](https://apify.com/artsiom_k) (community)
- **Categories:** Other, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## PGA TOUR Scraper - Results, Scorecards, Odds & Stats

Golf data straight from [pgatour.com](https://www.pgatour.com)'s own data feed, for the **PGA TOUR**, **PGA TOUR
Champions**, **Korn Ferry Tour** and **PGA TOUR Americas**:

- **Tournament results**: finish position, round-by-round scores, total, to-par, FedExCup (or Schwab Cup / Korn Ferry)
  points and official money for every player. Seasons since 2012 are complete; for older seasons each event
  that is still played goes back to its first edition (the Masters to 1953).
- **Scorecards**: hole-by-hole scores with par and yardage, front and back nine, birdies, bogeys and more, per round.
- **Odds history**: FanDuel **odds to win** for every player **before each round and at the finish**, or **every hour
  through the event** including in-play movement, from the 2024 season. With no tournament given, you get the odds for
  the event in progress or the next one.
- **Tee times** and groupings, with the local time at the course.
- **Player stats**: Strokes Gained and 500+ other stats (driving, approach, putting, scoring, streaks, money,
  rankings) for any season.
- **Player directory** with bios: age, birth date and place, college, turned pro, height, weight, residence.

Other golf scrapers give you today's leaderboard. This one also gives you the history behind it, including odds
history that is hard to find anywhere else.

### What you get

#### `entityType: "results"` (default, one row per player per tournament)

| Field | Example |
|---|---|
| `season`, `tournament_name`, `tournament_id`, `start_date`, `course`, `city`, `country`, `purse_usd` | `2025`, `Masters Tournament`, `R2025014`, `2025-04-10`, `Augusta National Golf Club`, `Augusta`, `United States of America`, `21000000` |
| `player_name`, `player_id`, `player_country`, `amateur` | `Rory McIlroy`, `28237`, `Northern Ireland`, `false` |
| `position`, `position_number`, `tied`, `made_cut` | `1`, `1`, `false`, `true` |
| `total_strokes`, `to_par`, `r1`-`r4`, `rounds` | `277`, `-11`, `72`, `66`, `66`, `73` |
| `points`, `points_label`, `earnings_usd` | `750`, `FedExCup Pts`, `4200000` |
| `team_id`, `partner_name` (team events such as the Zurich Classic) | `00130`, `Andrew Novak` |

#### `entityType: "scorecards"` (one row per player per round)

`round`, `round_score`, `round_to_par`, `par`, `front_nine`, `back_nine`, `eagles_or_better`, `birdies`, `pars`,
`bogeys`, `double_bogeys_or_worse`, the player's final `position`, and `holes`: a list of
`{"hole": 1, "par": 4, "yardage": 445, "score": 4, "to_par": 0}` for all 18 holes.

#### `entityType: "odds"` (one row per player per snapshot)

| Field | Example |
|---|---|
| `snapshot`, `snapshot_time` | `before_round_1`, `2025-04-10T11:35:00Z` |
| `player_name`, `odds_american`, `odds_decimal`, `implied_probability` | `Scottie Scheffler`, `+400`, `5.0`, `20.0` |
| `odds_movement`, `final_position`, `sportsbook`, `market` | `DOWN`, `4`, `fanduel`, `to_win` |

Snapshots are taken five minutes before each round's first tee time (`before_round_1` ... `before_round_4`) and
after the final round (`final`). Choose **hourly** snapshots to follow the odds through the event: at the 2025
Masters McIlroy went from +650 before round 1 to -650 on Sunday evening.

#### `entityType: "teeTimes"`, `"stats"`, `"players"`

- **Tee times**: `round`, `tee_time` (UTC), `tee_time_local`, `start_tee`, `group_number`, `playing_partners`.
- **Stats**: `stat_name`, `stat_category`, `rank`, `value`, `value_text`, `values` (every column, e.g. average, total,
  measured rounds), `stat_through`.
- **Players**: `player_name`, `player_country`, `age`, `born`, `birthplace`, `residence`, `college`, `turned_pro`,
  `height`, `weight_lb`, `profile_url`.

### How to use it

- **This season's results** (the default): just run it, and clear **Max results** for the whole season.
- **Every Masters since 1953**: tournaments `Masters`, `seasonFrom: 1953`, clear **Max results**.
- **Odds for this week's event**: `entityType: "odds"`.
- **A full season of odds before every round**: `entityType: "odds"`, `seasonFrom: 2025`, `seasonTo: 2025`.
- **In-play odds every 30 minutes at one major**: `entityType: "odds"`, tournaments `U.S. Open`, `seasonFrom: 2025`,
  `oddsSnapshots: hourly`, `oddsIntervalHours: 0.5`.
- **Hole-by-hole for a tournament**: `entityType: "scorecards"`, tournaments `R2025014`.
- **Strokes Gained and putting stats, last three seasons**: `entityType: "stats"`, statCategories `Strokes Gained`,
  `Putting`, `seasonFrom: 2023`.
- **Korn Ferry Tour results**: tours `Korn Ferry Tour`.

### Input

| Field | What it does |
|---|---|
| `entityType` | `results`, `scorecards`, `odds`, `teeTimes`, `stats` or `players`. |
| `tours` | PGA TOUR (default), PGA TOUR Champions, Korn Ferry Tour, PGA TOUR Americas. |
| `seasonFrom`, `seasonTo` | Season range. Empty = the current season. |
| `tournaments` | Names or parts of names (`Masters`, `Open`), tournament ids (`R2025014`) or event numbers (`014`). |
| `oddsSnapshots`, `oddsIntervalHours` | Odds: before each round + final, or every N hours (in-play). |
| `statCategories`, `statIds` | Stats: categories (default Strokes Gained) or exact stat ids. |
| `playerDetails`, `activeOnly` | Players: full bios; skip inactive players. |
| `maxItems` | Row cap, 50 by default. Clear it for everything. |
| `concurrency` | Requests in parallel (default 8). |
| `impersonate`, `proxyConfiguration` | Browser fingerprint and proxy. Neither needed. |

### Good to know

- **How far back.** Schedules, and so complete seasons, start in 2012 on the PGA TOUR (2013 on PGA TOUR Champions
  and the Korn Ferry Tour, 2024 on PGA TOUR Americas). Before that, results come from each current event's own
  history, so events no longer played aren't included. Scorecards and tee times exist from about 2013-2015, and not
  for every event (a few majors are missing in early years).
- **Odds are FanDuel's "to win" market**, the only odds pgatour.com keeps a history of, from the 2024 season on.
  Other tours rarely have odds. Team events (Zurich Classic) price teams, named after both partners.
- **Points before 2007** are empty: the FedExCup started that season.
- No proxy and no login needed. A full season of results takes well under a minute.

### FAQ

**What's in `position`?** The finish as pgatour.com shows it: `1`, `T5`, `CUT`, `WD`, `DQ`, `MDF`. `position_number`
gives the number for sorting, `tied` flags shared places.

**Why do some players in an odds snapshot have no final position?** They withdrew or weren't in the final results
(for example in unofficial events).

**Which stat ids exist?** Every stat page on pgatour.com has its id in the URL (`/stats/detail/02675` is SG: Total).
Or pick whole categories.

### Related sports data scrapers

- [Action Network Scraper](https://apify.com/artsiom_k/actionnetwork-scraper) — US sportsbook odds, public betting splits, line movement, props, injuries and futures.
- [Smarkets Betting Exchange Scraper](https://apify.com/artsiom_k/smarkets-scraper) — back and lay odds, matched volume and traded-price history from a betting exchange, golf outrights included.
- [Sports Odds History Scraper](https://apify.com/artsiom_k/sports-odds-history-scraper) — opening and closing lines per sportsbook since 2021 and ATS results since 2006.
- [Kalshi & Polymarket Scraper](https://apify.com/artsiom_k/prediction-markets-scraper) — prediction market odds, settled results and price history for sports, politics, economics and crypto.
- [SofaScore Scraper](https://apify.com/artsiom_k/sofascore-scraper) — results, team statistics, lineups with player ratings, incidents and odds for football, basketball, hockey, tennis and 17 more sports.
- [Flashscore Scraper](https://apify.com/artsiom_k/flashscore-scraper) — results, statistics, lineups, incidents and opening/closing odds from ~20 bookmakers for 17 sports.

# Actor input Schema

## `entityType` (type: `string`):

"results": one row per player per tournament. "scorecards": one row per player per round with every hole. "odds": FanDuel to-win odds per player before each round and at the finish (or hourly), 2024 season on; with no tournament or season, the current event's odds. "teeTimes": one row per player per round. "stats": one row per player per stat. "players": the tour's player directory.

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

Which tours. Odds exist almost only for the PGA TOUR.

## `seasonFrom` (type: `integer`):

First season (year). Leave both seasons empty for the current season. Results reach back to each event's first edition (the Masters to 1953); full schedules start in 2012, scorecards and tee times around 2013-2015, odds in 2024.

## `seasonTo` (type: `integer`):

Last season (year). Defaults to the current one when only From season is set.

## `tournaments` (type: `array`):

Limit to these tournaments: a name or part of one (Masters, U.S. Open, Players), a pgatour.com tournament id (R2025014) or an event number (014). Leave empty for all.

## `oddsSnapshots` (type: `string`):

odds only, finished or running events: "rounds" takes the odds just before each round's first tee time and after the final round. "hourly" takes them every oddsIntervalHours from 24 hours before round 1 to the end (in-play movement).

## `oddsIntervalHours` (type: `number`):

odds with hourly snapshots only.

## `statCategories` (type: `array`):

stats only: categories to pull. Empty (and no stat ids) = Strokes Gained.

## `statIds` (type: `array`):

stats only: exact pgatour.com stat ids instead of categories, e.g. 02675 (SG: Total), 101 (driving distance), 120 (scoring average). The id is the number in a stat page's URL.

## `playerDetails` (type: `boolean`):

players only: add birth date, birthplace, residence, height and weight (one extra request per 50 players).

## `activeOnly` (type: `boolean`):

players only: skip players the directory marks inactive.

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

Stop after this many rows. Defaults to 50 for a quick preview; clear it (null) for everything that matches.

## `concurrency` (type: `integer`):

Requests in parallel (scorecards and stats).

## `impersonate` (type: `string`):

curl_cffi browser fingerprint. Defaults to "chrome"; change only if requests start failing.

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

Not needed: pgatour.com's API answered every request from Apify without a proxy in testing.

## Actor input object example

```json
{
  "entityType": "results",
  "tours": [
    "R"
  ],
  "oddsSnapshots": "rounds",
  "oddsIntervalHours": 1,
  "playerDetails": true,
  "activeOnly": true,
  "maxItems": 50,
  "concurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("artsiom_k/pgatour-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("artsiom_k/pgatour-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 '{}' |
apify call artsiom_k/pgatour-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,artsiom_k/pgatour-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/6DV2VsCWpApZH7BMy/builds/aSfrmiwbUACp6pWqQ/openapi.json
