Apify Store
AS
Apify Store
/zhorex/sports-odds-aggregator

Sports Betting Odds Scraper — Tennis, Soccer + 5K Props

Scrape live and pre-match betting odds from Pinnacle and Bovada — sharp baseline plus the largest US offshore book, keyless, no login. Moneyline, spreads, totals, 5K+ specials and props markets, de-vi

liveasyncunknown~30s typical
sportsautomationdeveloper toolsoddsaggregator
$0.013
per result + $0.005 call
plus $0.001 platform fee per run
Actor charges $0.01 per result; Cracked adds 25% plus a $0.005 call fee
Bring your own Apify Store key: provider portion drops to $0.
$Set up https://cracked-ai-pearl.vercel.app/SKILL.md, then use Cracked to run apify /zhorex/sports-odds-aggregator for me.

Input

FieldTypeDescription
booksarrayWhich sportsbooks to pull odds from. Pinnacle is the canonical sharp-line book and works on datacenter or residential proxy without auth. Bet365 support is temporarily UNDER REPAIR (their public mobile-web endpoints recently changed — a defensive patch is in active development; selecting Bet365 right now returns 0 events while the new path is published). US books (DraftKings / FanDuel / BetMGM) are intentionally out of scope: they require US residential proxy. <b>Kambi</b> covers the Unibet/Paf/Betsson family from one public feed — add it alongside Pinnacle to get cross-book best-price comparison and to keep the feed alive if any single book closes its doors. Bovada is the largest US offshore book: keyless JSON verified from datacenter IPs, pre-match and live moneyline/spread/total across 6+ sports — the offshore market view next to Pinnacle's sharp baseline. default ["pinnacle"]
sportsarrayWhich sports to query. These are Pinnacle's own top-level categories, not league names — the leagues inside each one rotate with the calendar, so pick the category and read the `league` field on the rows. Measured 2026-08-21 (fixtures / specials, and what was actually inside): soccer 1,716 / 19,901 (by far the deepest shelf, worldwide); american_football_intl 78 / 311 (NCAA + NFL); tennis 48 / 2 (ATP, WTA, Challenger, ITF — runs year-round); mma 45 / 139 (UFC, PFL); basketball 31 / 93; baseball 29 / 827 (MLB, NPB Japan); esports 28 / 32 (LCK, NACL); rugby_league 7; ice_hockey 6; rugby_union 5; cricket 3. NOTE the US seasons: NBA and NHL fixtures only appear from roughly October, so in summer those two categories return the southern-hemisphere and European leagues instead. Soccer and tennis are the highest-liquidity, sharpest-priced markets year-round. Empty selections waste a run budget — if a sport comes back with nothing, the run status now says so explicitly. default ["soccer","tennis"]
leagueFilterarrayOptional league codes / display-name fragments to whitelist (e.g. 'EPL', 'UEFA', 'ATP', 'NBA'). Empty = all leagues for the chosen sports. Case-insensitive substring match against the book's league label. default []
marketTypesarrayWhich betting markets to extract per event. 'h2h' (moneyline) is the canonical sharp market. 'spreads' (handicap) and 'totals' (over/under) drive most EV-modelling pipelines. 'specials' enables Pinnacle's futures / yes-no / first-team-to-score / exact-totals / team-props markets (premium $0.05 tier — there are 5,000+ specials per major sport, so use maxEventsPerSport to control volume). 'player_props' is the Bet365-only player-prop tier (premium $0.05 — currently returns empty while Bet365 mode is under repair). default ["h2h","spreads","totals"]
modestring (pre_match_only | live_only | pre_match_and_live)'pre_match_only' (default) returns scheduled fixtures and is the cheapest, most-common workflow (5-15 min cadence). 'live_only' returns in-play markets — premium pricing tier; use with scheduled runs at ≤5 min cadence. 'pre_match_and_live' covers both, useful for arb finders that want to compare scheduled vs in-play lines. default "pre_match_only"
priceFormatstring (decimal | american | fractional)Output price format. 'decimal' (1.91) is the sharp / EU standard and is most convenient for implied-probability math; the actor ALWAYS computes the other two as well so all three fields are always populated. default "decimal"
maxEventsPerSportintegerSafety cap on number of events extracted per (book, sport) pair. Multiply by ~5-10 market-outcomes per event to estimate snapshot volume per run. default 50
includeAlternateLinesbooleanPinnacle only. Off by default. When on, the whole alternate ladder is returned — every extra handicap and total, not just the primary line (e.g. spread -1.5 / -1.0 / -0.5 alongside the main one). It costs no extra request, but it multiplies BILLED rows, and HOW MUCH depends on how many events you take. Measured 2026-08-07: across a full pre-match sweep it is about ×1.7 (×1.66 soccer, ×2.59 tennis, ×3.24 basketball, ×1.58 baseball, ×1.00 ice hockey), but with maxEventsPerSport=10 the same run went 42 → 354 rows, i.e. ×8.4 — the fewer events you take, the larger the share that is ladder. Check your first run's row count before scaling up. Rows carry `isAlternate` so you can filter, and `marketKey` so two rungs at the same line stay distinguishable. default false
includeBestPriceFlagbooleanWhen ≥2 books are selected, mark exactly one outcome per (event, market, outcome) as the best price across the chosen books. This is the foundation for any 2-way arbitrage workflow. default true
deduplicationWindowSecondsintegerIf a price hasn't changed within this many seconds, suppress the duplicate snapshot — keeps PPE cost down on cron runs where most lines are stable. Set to 0 to disable and emit every snapshot. default 30
cookieStringsobjectOptional. Object keyed by book name ({ 'bet365': '...', 'pinnacle': '...' }) with raw cookie headers from your browser DevTools to raise per-IP rate limits on heavy runs. NOT required for typical workloads — both books work anonymously.
proxyConfigurationobjectLeave this as it comes. The default (Apify Proxy, automatic selection) uses datacenter IPs, which is the right cost/quality point for both books — residential burns roughly 20x the proxy cost with no quality lift. Do NOT set apifyProxyGroups to "DATACENTER": that is not a real Apify group name and the run will refuse to start. If the run log shows repeated "unhealthy (code=403)" lines and a sport comes back empty, the exit range is being blocked by the book — switch apifyProxyGroups to ["RESIDENTIAL"] for that run. default {"useApifyProxy":true}
includeFairOddsbooleanCompute the vig-free fair probability + fair decimal odds (no-vig / CLV benchmark) for every market line and add them to each row (noVigFairPrice, noVigProb, overround) — the standard baseline for spotting +EV prices at softer books and for model calibration. Opt-in premium: from 8 Aug 2026 this charges the fair-odds-enrichment event ($0.05) per enriched snapshot, on top of the base snapshot price. Leave off for raw odds only. default false
includeLineMovementbooleanAdds movement fields to every snapshot by comparing the price to the last one this account's runs saw for the same market-outcome: previousPrice, priceChange, priceChangePct, impliedProbChange, moveDirection (shortened / drifted / unchanged), secondsSincePreviousPrice, plus firstSeenPrice and moveSinceFirstSeen for movement since the first observation. Free — it reuses the state the dedup window already keeps, so there is no extra request and no extra charge. Fields appear from your SECOND run of a market onward (the first run has nothing to compare to). default true

Call it

curl
curl https://cracked-ai-pearl.vercel.app/v1/run \
  -H "Authorization: Bearer ck_live_..." -H "content-type: application/json" \
  -d '{"provider":"apify","endpoint":"/zhorex/sports-odds-aggregator","input":{"books":["pinnacle"],"sports":["soccer","tennis"],"marketTypes":["h2h","spreads"],"mode":"pre_match_only"},"wait":false}'
poll
curl "https://cracked-ai-pearl.vercel.app/v1/runs/<runId>?wait=30" -H "Authorization: Bearer ck_live_..."
cli
npx cracked-ai run -p apify -e /zhorex/sports-odds-aggregator -i '{"books":["pinnacle"],"sports":["soccer","tennis"],"marketTypes":["h2h","spreads"],"mode":"pre_match_only"}' -w 120
mcp
run_tool({ provider: "apify", endpoint: "/zhorex/sports-odds-aggregator", input: {"books":["pinnacle"],"sports":["soccer","tennis"],"marketTypes":["h2h","spreads"],"mode":"pre_match_only"}, wait: false })

Try it

Runs against your signed-in workspace balance. Sign in if you have not.