Underdog Fantasy Scraper — Player Props, Lines & Multipliers avatar

Underdog Fantasy Scraper — Player Props, Lines & Multipliers

Pricing

from $0.15 / 1,000 results

Go to Apify Store
Underdog Fantasy Scraper — Player Props, Lines & Multipliers

Underdog Fantasy Scraper — Player Props, Lines & Multipliers

Underdog Fantasy scraper: export the live Pick'em board — every player prop, one row per line with Higher/Lower payout multipliers, American and decimal prices, implied probability, player, team, matchup and start time; alternate ladders optional. NFL, CFB, NBA, NHL, soccer, tennis, esports.

Pricing

from $0.15 / 1,000 results

Rating

0.0

(0)

Developer

Logiover

Logiover

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

16 hours ago

Last modified

Categories

Share

Underdog Fantasy Scraper — Player Props, Lines, Alternate Lines & Payout Multipliers

Export the live Underdog Fantasy Pick'em board — every player prop with the payout multipliers, American and decimal prices and implied probabilities of its Higher and Lower side, player, team, matchup, start time and league, and on request the full ladder of alternate lines — as clean JSON, CSV or Excel. One row per line, both sides in the row. No login, no API key, no browser.

Independent tool. Not affiliated with, endorsed by, or sponsored by Underdog, Underdog Sports or any league, team or player named in the data. "Underdog" and "Underdog Fantasy" are trademarks of their owners and are used here only to describe the public website this Actor reads. This Actor only reads the lines Underdog serves to every anonymous visitor of its web app: it does not log in, does not use an account, does not place or automate entries, and does not offer betting advice.

Underdog Fantasy Scraper is an Underdog Fantasy API alternative and Underdog Pick'em scraper that turns the public board behind underdogfantasy.com and app.underdogsports.com into a flat table you can sort, filter, join and chart. Every row is one line — "Points 24.5" — with the payout multipliers, American, decimal and fractional odds and implied probabilities of both its Higher (over) and Lower (under) side, the player (name, team, position, jersey number, country, headshot), the matchup (home and away team, venue, season type, broadcast), the start time in ISO 8601 UTC, the league (NFL, college football, NBA, NHL, WNBA, soccer, tennis, MMA, golf, NASCAR, Counter-Strike, League of Legends, Dota 2, Valorant …) and the stat (points, rebounds, passing yards, shots on goal, kills on maps 1+2, round strokes …). By default you get the main line of every prop; switch includeAlternates on and it also reads the alternate-line ladder of every prop that has one — the 19.5, 23.5, 29.5, 34.5 and 39.5 next to a 24.5 — each with its own multipliers and prices.

Use it as an Underdog player props API, an Underdog odds scraper, a pick'em line-shopping feed next to PrizePicks or a sportsbook, a props database for models and backtests, a line-movement and closing-line-value tracker when you schedule it, or a Discord / Telegram alert source. Export CSV, Excel, JSON or XML; call it from the Apify API, Make, Zapier, n8n, Google Sheets or an AI agent. Field names follow our PrizePicks and Sleeper Scrapers (playerName, playerTeam, playerPosition, league, statType, lineScore, startTime, projectionId, matchup, overMultiplier / underMultiplier), so the datasets join on player, stat and line. Prefer one row per side? Set rowShape to side.

Table of contents

At a glance

SourceThe JSON Underdog's own web app loads: the Pick'em board (/v1/over_under_lines) and the alternate-line ladder of each prop (/v3/over_unders/<id>/alternate_projections). No browser, no login.
RowOne line with both sides in it (over* = Higher, under* = Lower) — 73 columns, flat, typed, every field nullable. rowShape: "side" gives one row per side instead.
Board on 2026-10-299,744 main lines on 15 leagues (13,749 sides); 3,794 props carry an alternate-line ladder.
Default run (main lines)9,740 rows in 10 seconds; $2.44 at the free tier, $1.46 on Gold and above.
With alternate linesOpt-in (includeAlternates: true). Biggest verified run: 24,995 unique line rows (9,744 main + 15,251 alternate lines, 35,473 sides), 0 duplicates, 6.6 minutes, 2026-10-29.
Prefill run300 rows in 9 seconds, first rows after 8 seconds.
Odds formatsAmerican, decimal, fractional, implied and no-vig probability and payout multiplier — both sides, every row.
PricePay per result — from $0.25 per 1,000 rows, down to $0.15 per 1,000 on higher Store tiers. No start fee, no monthly rent.

What you get

Every row carries the context of its line, so one row is a complete selection. The columns come in eight groups; the full data dictionary with measured fill rates is further down.

  • Identity — rowId (underdog:line:<projectionId>), recordType, platform, lineKey (the market: <league>:<gameId>:<playerId>:<statKey>), projectionId (the line), overUnderId (Underdog's prop id), appearanceId, playerId, gameId, matchType.
  • Player — playerName, playerTeam, playerTeamName, playerPosition, playerPositionName, jerseyNumber, playerCountry, playerImageUrl, isHome.
  • Event — league, sportName, competition, gameTitle, matchup (AWAY @ HOME), opponent, homeTeam / awayTeam and their full names, homePlayerName / awayPlayerName, startTime, gameStatus, seasonType, venueName, venueType, broadcasts.
  • Market and line — statType, statKey, propTitle, lineScore (the number to beat), mainLineScore, isAlternate, hasAlternates, lineProvider, sidesOffered.
  • Both sides — for over (Higher) and under (Lower): …LineId, …Multiplier, …PayoutTier, …OddsAmerican, …OddsDecimal, …OddsFractional, …ImpliedProbability, …NoVigProbability, the separate …Fantasy… price set and …Status, plus marketOverround.
  • Meta — updatedAt (when Underdog last changed the line) and scrapedAt.
  • Side shape only — with rowShape: "side" each side is its own row and carries side, lineId, oppositeLineId, multiplier, payoutTier, oddsAmerican, impliedProbability … (listed last in the data dictionary).

A real line from a run on 2026-10-29 is shown unmasked in Real output sample below.

Who uses it — 14 workflows

1. Pick'em players and line shoppers

Sort tonight's board by statType and lineScore, compare Underdog's number with the same player elsewhere, and use overPayoutTier / underPayoutTier to find boosted sides. With includeAlternates on, the ladder shows what the 19.5 and the 29.5 pay before you commit to the 24.5.

2. Sports bettors comparing sportsbook props with pick'em lines

Join the export with the props you already collect on playerName + statType + lineScore and compare the implied and no-vig probabilities, computed the same way on every row.

3. DFS content creators and newsletters

A daily "best boosted picks" post is a filter: payoutTiers: ["boosted"], minPayoutMultiplier: 1.15, startsWithinHours: 24. Schedule it, push the dataset to a sheet; team names and headshot URLs are in the row.

4. Sports analytics teams and modellers

Schedule the Actor, keep every run, and key rows by rowId (a line) and lineKey (a prop): line movement, multiplier drift and the moment a side turns suspended become time series.

5. Odds comparison sites and aggregators

One row per line with both sides' American, decimal and fractional odds maps straight onto an odds-table schema; league + startTime + matchup place the event on your fixture list.

6. Discord, Telegram and Slack alert bots

Run every few minutes with a narrow filter, diff against the previous run by rowId, and post when lineScore or a multiplier changes. A webhook on run success triggers the bot.

7. Sports-data journalists

When a star is ruled out the boards react within minutes: pull a player's rows before and after and quote the movement with updatedAt.

8. Fantasy-sports and prediction start-ups

Seed a product with real market lines: projection baselines, difficulty ratings or a "what the market expects" widget. The main lineScore is Underdog's market estimate; with alternates on, the ladder maps the distribution around it.

9. Quantitative researchers

With includeAlternates on, the ladder is a discrete price curve: multiplier and price at 19.5, 23.5, 24.5, 29.5, 34.5, 39.5 for one stat. Fit a curve per prop or look for ladders whose neighbouring thresholds are mispriced.

10. Esports analysts

Counter-Strike, League of Legends, Dota 2 and Valorant props (kills on maps 1+2, assists, deaths) share the board and the columns; a team's whole slate is one teams filter.

11. Tennis, MMA, golf and NASCAR analysts

Individual-sport props (games played, aces, significant strikes, round strokes) come with the event in gameTitle, the tournament in competition, and opponent / homePlayerName / awayPlayerName for one-on-one events.

12. Academic and market-efficiency researchers

A scheduled collection of a small market over a season is a dataset few papers have; flat, typed rows with a stable rowId suit studies of line efficiency and favourite–longshot bias.

13. Risk, pricing and competitive-intelligence teams

See how a competitor prices the pairs you offer: group by league and statType, read the margin from marketOverround, measure how often lines move.

14. AI agents, RAG and LLM pipelines

A small JSON input, a flat output and a SUMMARY record make a clean agent tool: "which boosted sides start in the next three hours?" is one call with payoutTiers and startsWithinHours.

Cookbook — 15 ready-to-run inputs

Every input below is valid as written. Leave a field out to leave that filter off. Rows are returned soonest match first, so a small maxItems always gives you "what is coming up next".

1. A quick look (what the Console pre-fills)

{ "maxItems": 300 }

The soonest 300 rows of the whole board, all leagues: one request for the board, finished in seconds — the input the Store's daily health check uses.

2. The whole live board — main lines (the default)

{}

Every league that has lines right now, the main line of every prop: 9,740 rows in about 10 seconds on 2026-10-29. Raise "Maximum cost per run" if you want to be sure of the ceiling.

3. Alternate lines too — the deep ladders

{ "includeAlternates": true }

One more request per prop: 24,995 rows on 2026-10-29 (15,251 of them alternates), about 6.6 minutes. Narrow it with filters to make it quick and cheap.

4. One league: NFL player props

{ "leagues": ["NFL"] }

League codes are not case-sensitive; a few names work as aliases (soccer → FIFA, golf → PGA, valorant → VAL). With one to eight leagues the Actor downloads just those leagues.

5. Tonight's NBA board: points, rebounds, assists

{ "leagues": ["NBA"], "statTypes": ["Points", "Rebounds", "Assists"], "startsWithinHours": 24 }

statTypes matches the stat name, key or prop title.

6. One player, everything Underdog offers

{ "playerNames": ["Jokic"] }

Case-insensitive, accents ignored, partial names allowed — Jokic finds Jokić. Use several names for a watch-list.

7. One team's whole slate

{ "leagues": ["NFL"], "teams": ["KC", "Chiefs"] }

teams matches the player's team and either side of the matchup, by abbreviation or by name.

8. Boosted sides only

{ "payoutTiers": ["boosted"], "minPayoutMultiplier": 1.2, "startsWithinHours": 48, "includeAlternates": true }

Lines where a side pays more than a standard pick, starting within two days; the row shows both sides. Alternate lines are where the large multipliers live, so this one switches them on.

9. Lower (under) sides that are discounted

{ "side": "lower", "payoutTiers": ["discounted"] }

Lines whose Lower side pays less than a standard pick (multiplier below 1.0).

10. Soccer: shots on target

{ "leagues": ["FIFA"], "statTypes": ["Shots On Target"] }

Soccer is the FIFA league code on Underdog; home and away are resolved for soccer matchups.

11. Esports

{ "leagues": ["CS", "LOL", "DOTA", "VAL"] }

Counter-Strike, League of Legends, Dota 2 and Valorant. playerTeam holds the team name.

12. Individual sports: tennis, MMA, golf

{ "leagues": ["TENNIS", "MMA", "PGA"] }

No team here: competition holds the tournament, homePlayerName / awayPlayerName the two sides of one-on-one events.

13. A single day

{ "startDateFrom": "2026-10-31", "startDateTo": "2026-10-31" }

Both are inclusive UTC days (YYYY-MM-DD); a match at 01:00 UTC on the 1st is the evening of the 31st in the US.

14. Scheduled line-movement tracking

{ "leagues": ["NBA"], "statTypes": ["Points"], "maxItems": 5000 }

Schedule it every 15 minutes (Console → Schedules), keep every run's dataset and compare runs by rowId: the same line has the same rowId each run, so lineScore, overMultiplier and overOddsAmerican line up row by row; rows in one run only are new or removed lines.

15. One row per side

{ "rowShape": "side", "leagues": ["NBA"], "maxItems": 2000 }

Higher and Lower as two rows (side, lineId, oppositeLineId, multiplier, oddsAmerican, impliedProbability …) — twice the rows for the same lines, for tools that expect one selection per row.

Tutorial: your first run in the Apify Console

  1. Open the Actor and press Try for free or Start. The input form is pre-filled with maxItems = 300 and every filter empty.
  2. Leave the leagues empty to read every league that has lines right now, or pick leagues from the suggestions (you can also type any league code Underdog uses).
  3. Optionally narrow the board: player names, teams, stat types, side, payout tiers, a multiplier range or a start window. Row shape chooses one row per line (default) or per side.
  4. Switch Include alternate lines on if you want the whole ladder (more rows, minutes instead of seconds); it is off by default.
  5. Press Start; the pre-filled input ends in seconds.
  6. Open the Output tab. Views: Board, Prices, Players, Matches and Ladders (the lines of one prop next to each other). Export as CSV, Excel, JSON or JSONL.
  7. Storage → Key-value store → SUMMARY has the outcome, the leagues on the board, the number of alternate-line requests and the routes used.

Tutorial: run it from the API

1. Get your token

Console → Settings → API & Integrations → copy the personal API token. Put it in an environment variable instead of in code.

2. Run and get the data in one call (small runs)

curl -X POST "https://api.apify.com/v2/acts/logiover~underdog-fantasy-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"leagues":["NBA"],"statTypes":["Points"],"maxItems":200}'

The response is the dataset items as JSON. Add &format=csv or &format=xlsx for a file. Synchronous calls end after five minutes: use the next pattern for big boards.

3. Start a run and fetch the data later (big runs)

# start
curl -X POST "https://api.apify.com/v2/acts/logiover~underdog-fantasy-scraper/runs?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" -d '{"maxItems":100000}'
# poll: GET https://api.apify.com/v2/actor-runs/RUN_ID?token=$APIFY_TOKEN (status SUCCEEDED)
# data: GET https://api.apify.com/v2/datasets/DATASET_ID/items?format=csv&token=$APIFY_TOKEN

4. Node.js (apify-client)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('logiover/underdog-fantasy-scraper').call({
leagues: ['NFL'], payoutTiers: ['boosted'], startsWithinHours: 72, maxItems: 2000,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const r of items.slice(0, 5)) console.log(r.playerName, r.statType, r.lineScore, `over x${r.overMultiplier}`, `under x${r.underMultiplier}`);

5. Python (apify-client)

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("logiover/underdog-fantasy-scraper").call(run_input={"leagues": ["NBA"], "statTypes": ["Points"], "startsWithinHours": 24})
rows = client.dataset(run["defaultDatasetId"]).list_items().items
for r in sorted((r for r in rows if r["overMultiplier"]), key=lambda r: -r["overMultiplier"])[:10]:
print(r["playerName"], r["statType"], r["lineScore"], r["overMultiplier"], r["underMultiplier"])

6. Read the run summary

summary = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("SUMMARY")["value"]
print(summary["outcome"], summary["rowsSaved"], summary["board"]["leagues"].keys())

outcome is COMPLETED, PARTIAL, EMPTY_RESULT, BLOCKED, FETCH_FAILED or INVALID_INPUT (see Troubleshooting).

Input reference

Everything is optional. Filters combine with AND.

FieldTypeDefaultWhat it does
leagueslist of textall live leaguesUnderdog league codes: NFL, CFB, NBA, NHL, MLB, WNBA, CBB, FIFA (soccer), TENNIS, MMA, PGA, MOTORSPORTS, CS, LOL, DOTA, VAL, CFL, KBO …; not case-sensitive. A league with no lines returns nothing.
playerNameslist of textnoneKeep only these players. Partial, case-insensitive, accent-insensitive.
teamslist of textnoneKeep only props of these teams or matches of these teams (abbreviation or name).
statTypeslist of textnoneKeep only these stats (name, stat key or prop title; case-insensitive substring).
rowShapeline / sidelineOne row per line with both sides (default) or one row per side.
sideboth / higher / lowerbothKeep lines whose Higher or Lower side passes the payout filters (and, in the side shape, only that side's rows).
payoutTierslist of boosted / standard / discountednoneKeep lines where a side is in these tiers.
minPayoutMultipliernumbernoneKeep lines where a side pays at least this multiplier.
maxPayoutMultipliernumbernoneKeep lines where a side pays at most this multiplier.
includeAlternatestrue / falsefalseAlso read the alternate-line ladder of every prop that has one: one more request per prop, about 2.5 times the rows. Off = main lines only (one request, seconds).
startsWithinHourswhole numbernoneKeep only matches starting within this many hours from now.
startDateFromtext YYYY-MM-DDnoneKeep only matches starting on or after this UTC day.
startDateTotext YYYY-MM-DDnoneKeep only matches starting on or before this UTC day.
maxItemswhole number100,000Upper bound on rows saved (each row is one billed result — a line, or a side in the side shape). The Console pre-fills 300.
proxyConfigurationproxy editorno proxyOptional. Without it the Actor connects directly and falls back to the Apify datacenter proxy and, for small documents, a capped residential exit.

Filters that depend on the prop (league, player, team, stat, time window) are applied before any alternate-line request is made, so a narrow input also makes few requests. Filters that depend on the side (side, payoutTiers, multiplier range) keep a line when at least one of its sides passes all of them; in the side shape they decide which side rows are saved.

Output data dictionary

73 columns in the default shape, every one nullable. The Filled column is measured on the 24,995-row verified run of 2026-10-29 (the whole board with includeAlternates: true); a column that is empty for some rows is empty because the source has no value for them, never because the Actor dropped it. The columns of the Side shape group exist only with rowShape: "side".

Identity

ColumnTypeFilledMeaningExample
rowIdtext100 %Unique key: underdog:line:<projectionId> (a side row: underdog:<its option id>).underdog:line:0f900…
recordTypetext100 %line (default) or side.line
platformtext100 %Always underdog; a discriminator for merging with the other pick'em Actors.underdog
lineKeytext100 %Stable key of the market (one prop): <league>:<gameId>:<playerId>:<statKey>; shared by the main line and its alternates.TENNIS:329778:0ee77…
projectionIdtext100 %Underdog's id of the line (one threshold of a prop); same name as in the PrizePicks Actor.0f900c6e-2edc-4c06-…
overUnderIdtext100 %Underdog's own prop id (player + stat + match).15b9456b-f660-48c3-…
appearanceIdtext100 %Underdog's id of the player's appearance in the match.672c2c7e-7a53-40e4-…
playerIdtext100 %Underdog's player id.0ee77440-ce67-48a6-…
gameIdtext100 %Underdog's match id (team game or individual event).329778
matchTypetext100 %Game (team match) or SoloGame (golf, tennis, MMA, NASCAR).SoloGame

Player

ColumnTypeFilledMeaningExample
playerNametext100 %Player name as Underdog shows it.Kaitlin Quevedo
playerTeamtext97.7 %Team abbreviation (CLE); team name for esports; null for individual sports and unresolved matchups.BIG
playerTeamNametext97.7 %Full team name when Underdog gives one, else the nickname.BIG
playerPositiontext100 %Position code (SG, QB, FW, G, Gamer, TP).TP
playerPositionNametext100 %Position written out (Shooting Guard, Tight End).Tennis Player
jerseyNumbertext94.7 %Jersey number when Underdog lists one.15
playerCountrytext5.7 %ISO country code when Underdog lists one (golf, tennis, soccer, MMA).ESP
playerImageUrltext100 %Headshot URL on Underdog's asset host.https://assets.unde…
isHometrue / false99.7 %true when the player's side is the home side (tennis / MMA: the slot Underdog calls home).false

Event

ColumnTypeFilledMeaningExample
leaguetext100 %League code as Underdog uses it (NFL, CFB, NHL, FIFA = soccer, TENNIS, MMA, CS, LOL …); use it in leagues.TENNIS
sportNametext100 %Sport / game name from the match record (Soccer, CS2, Dota 2).Tennis
competitiontext6.1 %Tournament or competition when there is one (EPL, ATP Vienna).WTA Guangzhou
gameTitletext100 %Match title as Underdog prints it (CLE @ BOS, MCI vs BHA).Bondar vs Quevedo
matchuptext100 %AWAY @ HOME (the PrizePicks Actor's opponent shape); A vs. B for one-on-one events.A. Bondar vs. K. Qu…
opponenttext99.5 %The player's opponent: a team (name for esports) or, in tennis and MMA, the other competitor (as in the Sleeper Actor).Anna Bondar
homeTeamtext97.7 %Home team. AWAY @ HOME titles are exact; vs titles are resolved for soccer and esports only.BIG
awayTeamtext97.7 %Away team, same rules as homeTeam.Eternal Fire
homeTeamNametext97.7 %Home team's full name when the match record has one.BIG
awayTeamNametext97.7 %Away team's full name when the match record has one.Eternal Fire
homePlayerNametext1.9 %Home-side competitor in one-on-one events.Anna Bondar
awayPlayerNametext1.8 %Away-side competitor in one-on-one events.Kaitlin Quevedo
startTimetext100 %Scheduled start, ISO 8601 UTC.2026-10-29T10:10:00…
gameStatustext100 %scheduled, or scoring in the last minutes before the start. Started matches are not on the board.scheduled
seasonTypetext97.7 %regular or post, for league matches.regular
venueNametext82.5 %Venue, when the match record lists one.Center Court
venueTypetext76.9 %outdoor, indoor … when listed (mostly NFL / college football).outdoor
weatherConditiontext0 % (conditional)Forecast condition. Conditional: empty on every match when measured, so the key is written only when it has a value.Sunny
weatherTemperaturenumber0 % (conditional)Forecast temperature. Conditional, same rule as weatherCondition.61
broadcastslist94.1 %TV / streaming channels Underdog lists for the match.["Peacock", "USA"]

Market

ColumnTypeFilledMeaningExample
statTypetext100 %The stat as Underdog displays it (Points, Pass Yards, Kills on Maps 1+2).1st Set Aces
statKeytext100 %Underdog's machine key of the stat (points, rush_rec_tds); tells apart stats that share a display name.period_1_aces
propTitletext100 %Prop title as printed on the card.Kaitlin Quevedo 1st…

Line

ColumnTypeFilledMeaningExample
lineScorenumber100 %The threshold of this line — the number to beat; same name as in the PrizePicks Actor.1.5
mainLineScorenumber100 %The prop's main line; equals lineScore on main-line rows.1.5
isAlternatetrue / false100 %false = main-board line, true = alternate line from the prop's ladder.false
hasAlternatestrue / false100 %true when Underdog offers a ladder of alternate lines for the prop.false
nonDiscountedLineScorenumber0 % (conditional)Original line when Underdog discounted the line. Conditional: empty everywhere when measured, so written only when it has a value.25.5
lineProvidertext34.8 %Who set the main line: swish (model feed) or manual; not given for alternates.swish
sidesOfferednumber100 %Sides Underdog offers on this line: 2, or 1 (many lines are Higher-only).2

Sides

ColumnTypeFilledMeaningExample
overLineId / underLineIdtext99.8 % / 42.1 %Option id of each side (the Sleeper Actor's column name).067fc5be-45e2-4c7e-… / 9bb164e2-0c61-4ff4-…
overMultiplier / underMultipliernumber99.8 % / 42.1 %Pick'em payout multiplier (1.0 standard, above pays more, below less).1.28 / 0.76
overPayoutTier / underPayoutTiertext99.8 % / 42.1 %boosted (multiplier above 1.0), standard (1.0) or discounted (below).boosted / discounted
overOddsAmerican / underOddsAmericannumber99.8 % / 42.1 %American price Underdog serves (the leg price; equals the sportsbook-set price on ladder documents).162 / -200
overOddsDecimal / underOddsDecimalnumber99.8 % / 42.1 %Decimal price.2.62 / 1.5
overOddsFractional / underOddsFractionaltext99.8 % / 42.1 %Reduced fraction (computed from the American price).81/50 / 1/2
overImpliedProbability / underImpliedProbabilitynumber99.8 % / 42.1 %1 / decimal price, 4 decimals (computed; includes the margin).0.3817 / 0.6667
overNoVigProbability / underNoVigProbabilitynumber41.9 % / 41.9 %Share of the two implied probabilities, so the pair sums to 1 (two-sided lines).0.3641 / 0.6359
overFantasyOddsAmerican / underFantasyOddsAmericannumber94.2 % / 36.5 %American price of Underdog's separate fantasy price set.135 / -228
overFantasyOddsDecimal / underFantasyOddsDecimalnumber94.2 % / 36.5 %Decimal price of the fantasy set.2.35 / 1.44
overFantasyProbability / underFantasyProbabilitynumber94.2 % / 36.5 %Probability Underdog attaches to the fantasy set, as a fraction (served as whole percent).0.39 / 0.66
overStatus / underStatustext99.8 % / 42.1 %active or suspended.active / active
marketOverroundnumber41.9 %Implied over + implied under − 1: the margin of a two-sided line (computed).0.0484

Meta

ColumnTypeFilledMeaningExample
updatedAttext100 %When Underdog last changed the line (later of its two sides), ISO 8601 UTC.2026-10-28T15:47:45…
scrapedAttext100 %When the board was read, ISO 8601 UTC; same for every row of a run.2026-10-29T10:02:46…

Side shape (only with rowShape: "side": each side is its own row, which carries all the line columns above plus these, with the meaning of the matching over… / under… columns for the row's own side)

side, sideLabel, lineId, oppositeLineId, multiplier, oppositeMultiplier, payoutTier, oddsAmerican, oddsDecimal, oddsFractional, impliedProbability, noVigProbability, fantasyOddsAmerican, fantasyOddsDecimal, fantasyProbability, status, pickLabel, choiceShort. lineId is the option id of THIS side and oppositeLineId that of the other side (the Sleeper Actor's convention); side is over or under; pickLabel is the full pick text (Higher 24.5 Points) and choiceShort its short form (25+).

Real output sample

Two rows from the verified run of 2026-10-29 (alternate lines on), unmasked, empty columns left out: a main line and an alternate line of the same prop.

A main line (both sides in the row)

{
"rowId": "underdog:line:286e9f16-17a2-4479-b1cb-38eabc835a2a",
"recordType": "line",
"platform": "underdog",
"lineKey": "NBA:212020:046c78d0-6297-436a-92ab-e50ef6fb2aeb:three_points_made",
"projectionId": "286e9f16-17a2-4479-b1cb-38eabc835a2a",
"overUnderId": "87e2370e-ed7a-4867-8202-bcf7397b4333",
"appearanceId": "f3fecb84-1da2-42d0-840c-9fe75feaaec8",
"playerId": "046c78d0-6297-436a-92ab-e50ef6fb2aeb",
"gameId": "212020",
"matchType": "Game",
"playerName": "Aaron Wiggins",
"playerTeam": "ATL",
"playerTeamName": "Atlanta Hawks",
"playerPosition": "SG",
"playerPositionName": "Shooting Guard",
"jerseyNumber": "2",
"playerImageUrl": "https://assets.underdogfantasy.com/player-images/nba/20261008_21-d3b28775-473d-471a-8452-e913f4347f0f.png",
"isHome": true,
"league": "NBA",
"sportName": "NBA",
"gameTitle": "CLE @ ATL",
"matchup": "CLE @ ATL",
"opponent": "CLE",
"homeTeam": "ATL",
"awayTeam": "CLE",
"homeTeamName": "Atlanta Hawks",
"awayTeamName": "Cleveland Cavaliers",
"startTime": "2026-10-30T00:00:00.000Z",
"gameStatus": "scheduled",
"seasonType": "regular",
"broadcasts": ["NBA TV", "DAZN-CLE", "Prime-ATL"],
"statType": "3-Pointers Made",
"statKey": "three_points_made",
"propTitle": "Aaron Wiggins 3-Pointers Made O/U",
"lineScore": 1.5,
"mainLineScore": 1.5,
"isAlternate": false,
"hasAlternates": true,
"lineProvider": "swish",
"sidesOffered": 2,
"overLineId": "a0f85185-0de2-465a-a895-064b0d5c48b1",
"overMultiplier": 0.79,
"overPayoutTier": "discounted",
"overOddsAmerican": -179,
"overOddsDecimal": 1.56,
"overOddsFractional": "100/179",
"overImpliedProbability": 0.641,
"overFantasyOddsAmerican": -200,
"overFantasyOddsDecimal": 1.5,
"overFantasyProbability": 0.63,
"overStatus": "active",
"overNoVigProbability": 0.6109,
"underLineId": "a7d3e8b1-09f3-420b-8192-ece437bac78f",
"underMultiplier": 1.19,
"underPayoutTier": "boosted",
"underOddsAmerican": 145,
"underOddsDecimal": 2.45,
"underOddsFractional": "29/20",
"underImpliedProbability": 0.4082,
"underFantasyOddsAmerican": 120,
"underFantasyOddsDecimal": 2.2,
"underFantasyProbability": 0.42,
"underStatus": "active",
"underNoVigProbability": 0.3891,
"marketOverround": 0.0492,
"updatedAt": "2026-10-29T08:32:25.078Z",
"scrapedAt": "2026-10-29T10:02:46.600Z"
}

An alternate line of the same prop (columns identical to the row above are left out)

{
"rowId": "underdog:line:bd0c4862-c5a9-420f-84de-445b87a0588a",
"projectionId": "bd0c4862-c5a9-420f-84de-445b87a0588a",
"playerName": "Aaron Wiggins",
"statType": "3-Pointers Made",
"lineScore": 2.5,
"isAlternate": true,
"overLineId": "a03716b5-4adb-499e-997d-b796686f58f1",
"overMultiplier": 1.3,
"overPayoutTier": "boosted",
"overOddsAmerican": 165,
"overOddsDecimal": 2.65,
"overOddsFractional": "33/20",
"overImpliedProbability": 0.3774,
"overFantasyOddsAmerican": 138,
"overFantasyOddsDecimal": 2.38,
"overFantasyProbability": 0.38,
"overNoVigProbability": 0.3615,
"underLineId": "24079a1e-59b3-443b-8d30-4f3943a00e78",
"underMultiplier": 0.76,
"underPayoutTier": "discounted",
"underOddsAmerican": -200,
"underOddsDecimal": 1.5,
"underOddsFractional": "1/2",
"underImpliedProbability": 0.6667,
"underFantasyOddsAmerican": -228,
"underFantasyOddsDecimal": 1.44,
"underFantasyProbability": 0.66,
"underNoVigProbability": 0.6385,
"marketOverround": 0.0441,
"updatedAt": "2026-10-29T08:29:19.805Z"
}

CSV / Excel columns, in order: rowId, recordType, platform, lineKey, projectionId, overUnderId, appearanceId, playerId, gameId, matchType, playerName, playerTeam, playerTeamName, playerPosition, playerPositionName, jerseyNumber, playerCountry, playerImageUrl, isHome, league, sportName, competition, gameTitle, matchup, opponent, homeTeam, awayTeam, homeTeamName, awayTeamName, homePlayerName, awayPlayerName, startTime, gameStatus, seasonType, venueName, venueType, broadcasts, statType, statKey, propTitle, lineScore, mainLineScore, isAlternate, hasAlternates, lineProvider, sidesOffered, overLineId, overMultiplier, overPayoutTier, overOddsAmerican, overOddsDecimal, overOddsFractional, overImpliedProbability, overFantasyOddsAmerican, overFantasyOddsDecimal, overFantasyProbability, overStatus, overNoVigProbability, underLineId, underMultiplier, underPayoutTier, underOddsAmerican, underOddsDecimal, underOddsFractional, underImpliedProbability, underFantasyOddsAmerican, underFantasyOddsDecimal, underFantasyProbability, underStatus, underNoVigProbability, marketOverround, updatedAt, scrapedAt

How to read a row

One row is one line with both sides. "Points 24.5" has a Higher side (over… columns) and usually a Lower side (under… columns), each with its own multiplier and prices. projectionId identifies the line, lineKey the prop — every line of a prop, main or alternate, shares it. When Underdog offers one side only, sidesOffered is 1 and the other side's columns are empty: 59 % of the main lines on 2026-10-29 were one-sided, almost all Higher-only. With rowShape: "side" the same line becomes two rows.

The payout multiplier is the pick'em number. Each pick scales the entry's payout by its own multiplier: 1.00 is standard, above 1.00 the side is boosted (pays more), below 1.00 discounted (pays less). In the verified run the multipliers ran from 0.51 to 19.91, median 1.28: 59 % of sides boosted, 14 % standard, 27 % discounted.

Two price sets, both served by Underdog. overOddsAmerican, overOddsDecimal (and the computed fractional, implied and no-vig probabilities; same for under…) are the price Underdog attaches to the side as a leg; on the alternate-line documents it is identical to the sportsbook price set served next to it — a sportsbook-style quote, not a payout you can collect on its own. The …Fantasy… columns are Underdog's separate fantasy set for the same side. They differ because they carry different margins; the Actor never blends them.

The margin is in the row. …ImpliedProbability is 1 / decimal odds to four decimals; …NoVigProbability is each side's share of the two (the pair sums to 1) and marketOverround is implied over + implied under − 1, the margin built into the line.

Alternate lines (opt-in). isAlternate = false rows come from the main board, true rows from the prop's ladder (only with includeAlternates: true). mainLineScore repeats the main line on every row of a prop, so lineScore - mainLineScore is the distance from it; the further away, the more extreme the multiplier (largest in the verified run: 19.91).

Times. startTime is the scheduled start in ISO 8601 UTC, updatedAt when Underdog last changed the line, scrapedAt when the Actor read the board (the same for every row of a run). The board only carries matches that have not started: in the verified run no row had a start time earlier than the moment it was read.

Scale and speed (measured)

All figures are from runs on the Apify platform on 2026-10-29, 1,024 MB memory (the default), default settings, direct connection first.

RunRowsTimeNotes
Console pre-fill (maxItems 300, main lines)3009 sfirst rows after 8 s
1,000 rows with alternates on1,00025 ssoonest matches first
Default run: main lines, whole board9,74010 sone request for the board, no ladders (13,742 rows in the side shape)
Whole board with every alternate line (includeAlternates: true)24,995394 s (6.6 min)9,744 props, 3,794 ladder requests, 202 MB peak memory, 0 duplicate rowId; 35,473 sides

How the board is read

The main board is one document of about 25 MB that Underdog serves in roughly a second; the Actor downloads it once and flattens it in memory. A default run stops there: that is why it takes seconds. Alternate lines are not in that document: for every prop flagged hasAlternates (3,794 props on 2026-10-29) Underdog's web app makes one more request for the ladder, and so does the Actor when includeAlternates is on. Those requests are small (a few kilobytes) but numerous, so they are paced: the direct connection is used at a modest rate and, if Underdog's edge refuses it for a while, Apify datacenter sessions (one IP each) carry the load. In the verified run the direct connection answered 3,794 ladder requests, the datacenter sessions 0, and 0 were refused. That is why the whole board with alternates takes 6.6 minutes — but rows are saved from the first seconds on, soonest match first, and maxItems stops the reading as soon as enough rows are in.

What you pay

Pay per result, no start fee, no subscription: $0.25 per 1,000 rows on the free Store tier, falling to $0.15 per 1,000 on the highest tiers (Bronze $0.217, Silver $0.183, Gold and above $0.15). A row is one line (both sides in it); in the side shape a row is one side.

RunRowsFree tierGold tier and above
1,000 rows1,000$0.25$0.15
Default run: whole main-line board (2026-10-29)9,744$2.44$1.46
With includeAlternates: true: whole board (2026-10-29)24,995$6.25$3.75
100,000 rows100,000$25.00$15.00

Alternates are opt-in because they multiply the rows and the run time (the default run is 39 % of the rows). Filters cut the bill directly — a filtered-out row is never saved or billed.

Maximum cost per run

Every run has a Maximum cost per run (Console → run options, or maxTotalChargeUsd in the API). The Actor reads the budget at the start, never saves more rows than it pays for, and ends the run as SUCCEEDED with a status message, for example "Saved 230 rows — this run's maximum cost ($0.05) covers 230 results at the current price. Raise "Maximum cost per run" to get more." Verified after pricing: a run capped at $0.05 saved 230 rows and was charged for exactly 230 (the number depends on the price of your tier). Set a small maximum while testing.

Integrations

  • Apify API and clients — apify-client for Node.js and Python (examples above), plain HTTP for everything else; the dataset as JSON, JSONL, CSV, XLSX, XML or HTML.
  • Schedules and webhooks — Console → Schedules (any cron; every 15 minutes for line movement, once a day for a "boosted picks" sheet); a webhook fires on success, failure or timeout with the run and dataset ids.
  • Make, Zapier, n8n — the Apify app / node: "Run Actor", then "Get dataset items"; map playerName, statType, lineScore, overMultiplier, underMultiplier into the next step.
  • Google Sheets, Airtable, Notion, Slack, Discord, Telegram — through the Apify Google Sheets integration, Make / Zapier / n8n, or a small webhook handler.
  • Warehouses and lakes — JSONL or CSV to S3 / GCS / Azure, or straight into BigQuery, Snowflake or Postgres. rowId is a stable primary key per line; scrapedAt is the snapshot key.
  • MCP, AI agents, Pandas / R / DuckDB — the Apify MCP server exposes the Actor as a tool; typed columns (lineScore, overMultiplier are numbers, startTime is ISO 8601) need no cleaning.

Performance tips

  • Start from the question. League, player, team, stat and time filters are applied before any alternate-line request: "NBA points in the next 24 hours" needs a few dozen small requests, "everything" thousands.
  • Alternates are opt-in. The default is one request for the whole board — 9,740 rows in about 10 seconds on 2026-10-29. Switch includeAlternates on when you need the ladders, and narrow it with filters.
  • Use maxItems as a safety rail. Rows come out soonest match first; pair it with Maximum cost per run while testing.
  • Schedule instead of polling by hand, with a narrow filter, and compare runs by rowId.
  • Do not start many full-board runs at the same moment. Underdog's edge refuses bursts from one address; the Actor paces itself, but ten parallel full runs are ten times the pressure.

Troubleshooting: every status message explained

The run's status message and the SUMMARY record in the key-value store always say what happened. COMPLETED, PARTIAL and EMPTY_RESULT end as Succeeded; BLOCKED, FETCH_FAILED and INVALID_INPUT end as Failed with the reason.

Status message (start)MeaningWhat to do
COMPLETED: saved N rows from L league(s) (with alternates on: … (K alternate-line rows))Everything requested was read. May end with the "maxItems" limit … was reached or this run's maximum cost … covers ….Nothing; raise maxItems or the maximum cost for more.
PARTIAL: … the alternate lines of N prop(s) could not be read (alternates on)Underdog's edge refused or timed out some ladder requests even after retries on other exits. Those props keep their main line only; every other row is complete.Run again later, or with fewer leagues. The SUMMARY lists the exits and refusals.
PARTIAL: … could not read <LEAGUE>One requested league could not be downloaded; the others are complete.Run again, or add a proxy.
PARTIAL: … the run time limit was reachedThe timeout came before every prop was read; the rows saved are complete.Raise the timeout or narrow the filters.
EMPTY_RESULT: Underdog's board is empty …Underdog answered but no lines are posted (off-season, no games).Try again later or choose other leagues. Off-season leagues (MLB, UFL, NPB on 2026-10-29) are empty by nature.
EMPTY_RESULT: N main lines are on the board but none match these filters. Leagues posting lines now: …Your filters exclude everything; the message lists the leagues with lines.Loosen a filter; check the spelling.
The run's maximum cost … does not cover a single resultThe "Maximum cost per run" is below the price of one row.Raise it.
Saved N rows — this run's maximum cost … covers N resultsThe cost ceiling was reached; the rows saved are complete and billed.Raise "Maximum cost per run" to continue.
FETCH_FAILED: Underdog answered HTTP 426 (upgrade required) …Underdog retired or changed the endpoint this Actor reads.Open an issue; we update the Actor.
BLOCKED: no board could be read … / FETCH_FAILED: no board could be read …Every route (direct, datacenter, capped residential) was refused or timed out — an access failure, not an empty board.Retry in a few minutes; add proxyConfiguration.
FETCH_FAILED: the board was read but no row could be completed …The time limit ended before the first rows.Raise the timeout or leave alternates off.
INVALID_INPUT: …A contradictory multiplier range, a date that is not YYYY-MM-DD, or a reversed date window.Fix the input named in the message.

SUMMARY notes: Resumed after a platform restart (rows already saved are not written or charged again); … read league by league through the capped residential rescue route (the board was unreachable directly).

Honest limits

  • Pre-game lines only. The public board lists matches that have not started. In the data of 2026-10-29 no row had a start time earlier than the moment it was read; 177 team games and individual events were on the board, all scheduled except one Counter-Strike match four minutes from its start (status scoring). A line leaves the board when its match begins. There is no in-play data and no results or grading.
  • A snapshot, not a tick history. You get the board at the moment of the run. History is what you build by scheduling runs and keeping the datasets.
  • Pick'em prices are not sportsbook bets. …OddsAmerican / …OddsDecimal are quotes Underdog attaches to a leg, not a price you can bet at; an entry pays by Underdog's rules and the multipliers. Treat them as a market signal.
  • The board and the ladders are read seconds apart; each row carries its own updatedAt.
  • Alternate lines (opt-in) cost requests. Ladders are read one prop at a time; a refused request is retried on another exit, and a prop whose ladder still cannot be read keeps its main line (the run ends PARTIAL).
  • Home / away for vs titles. An AWAY @ HOME title is exact. For a vs title the Actor resolves soccer (home team first — checked against stadiums and squads) and esports (away team first — checked against the squads of League of Legends and Counter-Strike matches); for any other sport with a vs title it leaves homeTeam, awayTeam and playerTeam empty rather than guess.
  • Weather and sport-specific context. On 2026-10-29 no match carried a forecast and MLB was out of season, so forecast columns are written only when they carry a value and MLB-specific context (probable pitchers) is not mapped; venue and broadcast are mapped where present (83 % and 94 % of rows).
  • Not on the public board: pick popularity, player statistics and game logs, injury reports, live scores, the state-gated sportsbook and prediction-market products, contest or entry data.
  • Leagues come and go. Off-season leagues return nothing; new leagues appear without a code change.
  • The source can change. Underdog retires old API versions (the earlier ones answer HTTP 426). If the endpoint changes the Actor says so in plain words instead of returning an empty file.

How it compares

OptionEffortAlternate linesUpkeepCost
Copying lines from the app by handHours per slateOnly the ones you openNoneYour time
Your own script against the web app's JSONDays; six document parts to joinNeeds the separate ladder endpointYou fix it when Underdog changes versionsServers + proxies
A general sports-odds APILowUsually sportsbook main lines, rarely pick'em multipliersVendorMonthly subscription
This ActorMinutesWhole ladder of every prop, opt-inWe keep it currentPay per row, no monthly fee

The trade-off: this Actor reads one platform's public board; it is not a multi-book odds feed.

FAQ

What is Underdog Fantasy Scraper?

An Apify Actor that reads the public Pick'em board of Underdog Fantasy (underdogfantasy.com / app.underdogsports.com) and returns one row per line with both sides in it — payout multipliers, American / decimal / fractional odds, implied and no-vig probabilities, player, team, matchup, start time, league and stat — with the alternate lines of each prop on request (or one row per side with rowShape: "side").

Is there an official Underdog Fantasy API?

Underdog does not publish an API for its Pick'em board. Its web app loads the board from JSON endpoints that any visitor's browser can call, with no login, cookie or key; this Actor reads those endpoints. They are undocumented and not guaranteed, so the Actor says so plainly when one changes.

How do I export Underdog props to Excel or CSV?

Run the Actor, open the Output tab and press Export → Excel or CSV, or call …/datasets/DATASET_ID/items?format=xlsx (or csv) with your token.

What is the difference between the line shape and the side shape?

The default is one row per line with both sides in it (overMultiplier / underMultiplier, …): about half the rows and price of the side shape. rowShape: "side" writes Higher and Lower as two rows (side, lineId, oppositeLineId, multiplier, oddsAmerican …) for tools that expect one selection per row.

What is a payout multiplier on Underdog?

The factor by which a pick scales the entry's payout: 1.00 standard, above 1.00 pays more, below pays less. Each side of a line has its own: overMultiplier and underMultiplier.

What do boosted, standard and discounted mean?

A derived label per side (overPayoutTier, underPayoutTier): boosted above 1.0, standard at 1.0, discounted below 1.0 — it lines up with PrizePicks' demon / standard / goblin picks.

What are alternate lines and how do I get them?

Other thresholds of the same prop — a 24.5-point prop may also offer 19.5, 29.5, 34.5 — each with its own multipliers and prices. They are off by default (they multiply the rows and the run time); includeAlternates: true adds them as rows of their own, and isAlternate tells the two apart. An alternate can sit at the same number as the main line with different prices (58 NFL props on 2026-10-29).

Why does hasAlternates say true but I only see the main line?

includeAlternates is off (the default), a side / tier filter removed the alternates, or the ladder request for that prop failed (the run then ends PARTIAL and says how many).

How many props and rows are there?

9,744 main lines on 2026-10-29 (the default run), plus 15,251 alternate lines with includeAlternates: true: 24,995 line rows in the verified run (35,473 sides, which is what rowShape: "side" would give). The numbers move with the schedule.

Which leagues and sports are supported?

Whatever Underdog lists that day. On 2026-10-29: NFL (2,929 lines), CFB (3,149 lines), NHL (1,328 lines), FIFA (996 lines), NBA (315 lines), TENNIS (223 lines), CS (207 lines), MMA (193 lines), LOL (120 lines), WNBA (76 lines), MOTORSPORTS (59 lines), DOTA (58 lines), CFL (40 lines), VAL (30 lines), PGA (21 lines). Use the league code in leagues.

Why is MLB (or another league) empty?

Underdog posts no lines for it — off-season or no games. MLB, UFL, NPB and Formula 1 season props were empty on 2026-10-29.

Does it include live, in-play lines?

No. In the verified run no row had a start time earlier than the moment it was read; a match leaves the board when it begins.

How often do lines change, and how often should I run it?

updatedAt shows lines changing minute by minute on a busy day: every 5–15 minutes with a narrow filter for line movement, once in the morning for a newsletter.

How do I track line movement?

Schedule the Actor, keep every run's dataset and compare two runs by rowId: lineScore, overMultiplier and overOddsAmerican of the same row give the movement; rows in one run only are new or removed.

Is rowId stable between runs?

While the line exists, yes. On 2026-10-29, 98 % of the main-line ids of a board read 83 minutes earlier were still on the board.

Why are some lines one-sided?

Underdog offers one side on many lines — mostly Higher-only props such as "anytime touchdown". On 2026-10-29 59 % of main-line rows came from such lines; sidesOffered is 1 and the other side's columns are empty.

What is the difference between overOddsAmerican and overFantasyOddsAmerican?

Underdog serves two price sets per side. …OddsAmerican / …OddsDecimal are the leg price (identical to the sportsbook set on alternate-line documents); …FantasyOdds… is a separate set with its own margin. Both are output as served, never blended.

Are these real sportsbook odds?

They are Underdog's quotes for a pick'em leg in odds formats — good for comparison and modelling, not a bettable price (see Honest limits).

How do I compare Underdog with PrizePicks or a sportsbook?

Join on playerName + statType + lineScore (sportsbooks also startTime). The names match our PrizePicks and Sleeper Scrapers (playerName, playerTeam, playerPosition, league, statType, lineScore, startTime, projectionId, overMultiplier / underMultiplier); the PrizePicks Actor's opponent string is matchup here, and opponent is the opposing team as in the Sleeper Actor.

How fast is it and how much does it cost?

Default (main lines): 9,740 rows in about 10 s; pre-fill: 300 rows in 9 s; the whole board with alternates on: 24,995 rows in 6.6 min. From $0.25 per 1,000 rows (free tier) down to $0.15: a main-line board is about $2.44, the whole board about $6.25 at the free tier.

How do I cap what I spend?

Set Maximum cost per run, use maxItems, or filter — a filtered-out row is never billed. The Actor stops exactly at the budget and says so in the status message.

Why did I get fewer rows than maxItems?

The board (after your filters) had fewer rows; the SUMMARY lists the leagues and counts on the board.

Why is playerTeam empty on some rows?

Individual sports (tennis, MMA, golf, NASCAR) have no team. For a team game with a vs title in a sport other than soccer or esports the Actor does not guess which side is home.

How are home and away decided?

AWAY @ HOME titles are exact. For vs titles, soccer lists the home team first and esports the away team first (checked against stadiums and squads); other sports are left empty.

Does it work from outside the US? Do I need a proxy?

Yes, and no. The Actor runs on Apify's infrastructure and reads Underdog's JSON from there. It connects directly, moves to the Apify datacenter proxy when Underdog's edge refuses the direct connection, and keeps a capped residential exit for small documents as a last resort; you can set your own proxy.

Can I get player stats, injuries, pick popularity, results or live scores?

No — they are not on the public board. The row has the player's position, jersey number, country and image.

Does it include Underdog's sportsbook or prediction markets?

No. Those are separate, state-gated products; this Actor reads the Pick'em board and its alternate lines.

Can I use the data in a commercial product?

That is governed by Underdog's terms, copyright and database law and your gambling and data-protection rules: read Is it legal to scrape Underdog? and take advice.

What happens when Underdog changes its API?

The Actor stops with a plain message (an upgrade-required answer) or returns PARTIAL with the reason instead of an empty file, and we update it.

Two stats share a display name — how do I tell them apart?

Use statKey. On 2026-10-29 only soccer "Assists" had two keys (assists and period_1_2_assists); period stats such as "1Q Rec Yards" have their own names.

Glossary

  • Pick'em — a contest format where you pick Higher or Lower on player stats and combine picks into an entry.
  • Higher / Lower — Underdog's wording for over / under.
  • Line (lineScore) — the threshold of a prop, e.g. 24.5 points.
  • Prop — one player, one stat, one match (overUnderId).
  • Main line / alternate line / ladder — the line on the main board, another threshold of the same prop, and all lines of one prop ordered by lineScore.
  • Payout multiplier — the factor a pick applies to the entry's payout; 1.00 is standard. Above 1.00 is boosted, below is discounted.
  • American, decimal, fractional odds — three ways to write one price (+104, 2.04, 26/25).
  • Implied probability — the chance a price represents, 1 / decimal odds; it includes the margin.
  • Margin (vig, juice) — how far the implied probabilities of all sides add up past 1.
  • Line shopping / CLV — comparing a prop across platforms; comparing the line you took with the closing line (needs repeated snapshots).
  • Solo game — Underdog's name for an individual event (a golf round, a tennis match, a fight, a race).

The Actor reads data that Underdog serves to every anonymous visitor of its web app — it does not log in, bypass a paywall or use anyone's account, and it collects no personal data of Underdog's customers. The rows describe public matches, public athletes and the prices Underdog displays. That is not the same as permission: Underdog's website terms may restrict automated access or reuse, copyright and database rights may apply to the compiled board, and the rules for gambling-related data differ by country and state. You are responsible for how you use the output — check the terms and the law where you operate, take advice before building a commercial product on it, and do not use the data to harm the platform or to evade a restriction on you personally. Athlete names are personal data in a narrow sense; they are public figures and the data is sports statistics, but run your own data-protection assessment if you combine it with other personal data.

Responsible use

This is a data tool for analytics, research and tooling. It does not place bets, enter contests or automate an account, and promises no profit; past lines and multipliers do not predict results. Betting and fantasy pick'em involve real financial risk and can be addictive — take part only where it is legal for you, only with money you can afford to lose, and use the limit and self-exclusion tools of any platform you play on. If gambling is a problem for you or someone you know, contact your national problem-gambling helpline.

Changelog

  • 1.0 — 2026-10-29 — first release: the whole Pick'em board (main lines by default, alternate-line ladders on request) as one row per line with both sides, or one row per side; filters for league, player, team, stat, side, tier, multiplier, start window and alternates; American / decimal / fractional odds, probabilities and multipliers on every row; paced reading with a capped residential rescue; pay per result with a maximum-cost guard; verified on a 24,995-row run, no duplicates.

Support

Questions, a missing field, a wrong value, a league that is empty when you expect lines? Open an issue on the Actor page with the run link — we reply within 24 hours. If Underdog changes its web app and a run starts failing, send us the status message; source changes are the first thing we fix.