Polymarket API Scraper - Odds, Order Book, Trades, Wallets avatar

Polymarket API Scraper - Odds, Order Book, Trades, Wallets

Pricing

from $0.50 / 1,000 result rows

Go to Apify Store
Polymarket API Scraper - Odds, Order Book, Trades, Wallets

Polymarket API Scraper - Odds, Order Book, Trades, Wallets

29,600 Polymarket markets in one sweep, where offset paging stops at offset 2,000. Up to 92 fields per market. Polymarket scraper for election odds and event odds: implied probability, volume, liquidity, top holders, trades and wallet positions, plus a Polymarket odds monitor.

Pricing

from $0.50 / 1,000 result rows

Rating

0.0

(0)

Developer

Snow Leo Data

Snow Leo Data

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

23 days ago

Last modified

Share

Polymarket Prediction Market Scraper — Odds, Order Book, Trades & Wallets

Polymarket is a prediction market where every outcome trades between $0 and $1 and settles at one of them, so an outcome's price is the market's probability for it. This Actor turns that into a dataset: one row per market, event, trade or wallet position, with the prices already parsed into numbers and the event, its tags and the order book joined in.

Everything below is measured, and every number is reproduced by tools/measure_source.py, which writes tools/measurements.json. The measurement date is 2026-09-12. The platform is live, so counts move day to day.

What does this Actor pull from Polymarket?

One run gives you any of four shapes:

  • markets — one row per tradable market: outcomes with prices as implied probabilities, best bid and ask, spread, volume over several windows, liquidity, the event and its tags, and optionally the full order book, price history, top holders and the recent tape. Up to 92 fields.
  • events — one row per event with its markets nested and the set priced as a whole: sum of outcome prices, overround, and the gap below $1 on a mutually exclusive set. 31 fields.
  • trades — the platform-wide trade tape: every print with price, size, dollar notional, outcome, side and the wallet behind it. Measured: 2,000 trades in 4 requests and 1.6 seconds.
  • wallets — open positions for the addresses you list, each with entry price, current price, current value, realized and unrealized P&L, plus the wallet's total portfolio value.

Why does ordinary pagination miss most of the catalogue?

Polymarket's catalogue API accepts offset, and that is the obvious way to page through it. It stops working part-way: measured on 2026-09-12, offset=2000 still returns data and offset=2001 returns HTTP 422 with the message "offset too large, use /events/keyset for deeper pagination". A scraper built on offset paging therefore sees roughly the first 2,100 records and silently sees nothing beyond them.

The keyset endpoints have no such ceiling — but only if you pass the cursor under the name the API expects, which is after_cursor. This is the part that costs people days: cursor, next_cursor and after are not rejected. The server quietly returns the first page again, every time, with a fresh-looking cursor. A sweep built that way looks like it is working, runs forever and collects the same 100 rows. Measured before the fix: 40 pages in a row, 100 unique records.

This Actor walks the keyset endpoints with the right cursor, so a sweep goes past the ceiling and each page really is new. A full sweep of open markets, measured the same day: 29,600 markets in 297 requests and 150.2 seconds (stopped at the time limit, not the end of the catalogue), and the same walk over events gives 20,500 events in 206 requests and 150.0 seconds (stopped at the time limit). The live test suite asserts both halves of this: that the cursor advances, and that the wrong cursor name silently does not.

Which filters does the API actually apply?

The same filter has different names on the two endpoints, and passing the wrong one is not an error either — it is ignored:

FilterOn marketsOn events
Minimum volumevolume_num_minvolume_min
Minimum liquidityliquidity_num_minliquidity_min

Measured: volume_min=5000000000 on events returns an empty list, as it should, while volume_num_min with the same threshold returns events with four thousand dollars of volume — the filter was never applied. This Actor sends the right name per endpoint and re-checks every threshold on the row itself, so the number you type is the number you get.

What is in a row that the raw API does not give you?

Polymarket returns the three most important lists as strings: outcomes is '["Yes", "No"]', outcomePrices is '["0.0395", "0.9605"]', and the CLOB token ids arrive the same way. Money fields are strings too. Handed to you unparsed, they mean JSON inside a CSV cell and a type error in your first filter.

This Actor parses all of it and computes what the API does not:

FieldWhat it is
outcomesOne object per outcome: name, price, implied probability, CLOB token id.
impliedProbabilityPrice of the first outcome — the answer to the question in the title.
topOutcome, topOutcomePriceThe leading outcome on a multi-outcome market.
outcomePriceSum, overround, arbitrageGapWhat the whole set costs against the $1 that one winning outcome pays.
payoutRatioTopReturn per dollar if the leading outcome resolves true.
midPrice, spreadPctMid of bid and ask, and spread as a share of it.
bidDepthUsd, askDepthUsd, bookImbalanceDollars resting on each side of the book and which side is heavier.
volume24hShare, volumeToLiquidityHow much of lifetime volume traded today, and today's volume against resting liquidity.
hoursToEnd, daysToEnd, endsWithin24hTime left, precomputed.
windowHigh, windowLow, windowChangePrice range over the history window you chose.
lastTradeAt, minutesSinceLastTrade, recentVwap, buyShareWhat the recent tape says about who is buying.
topHolders, topHolderShareOfListedLargest holders per outcome and how concentrated they are.

Empty numbers are null, never "" — an empty string in a float column breaks Excel, BigQuery and pandas.

How does the event-level pricing work?

On a mutually exclusive event — Polymarket calls it negative risk — exactly one outcome can win, so the prices across its markets should add up to about $1. When they add up to less, the whole set can be bought for less than the guaranteed payout. outcomePriceSum, overround and arbitrageGap report that, and arbitrageGap is filled only for events the platform actually marks as mutually exclusive. On a set where the outcomes are not exclusive the sum means nothing, and printing it as an edge would be worse than printing nothing.

How does monitor mode avoid paying for the same market twice?

Turn on Monitor mode and the Actor remembers what it delivered in a named key-value store, which survives between runs — the default store does not, it is wiped at the start of every run.

On the next run each market is classified NEW, UPDATED or UNCHANGED, and unchanged markets are never written to the dataset, so they are never billed. Every row also carries probabilityChange, the move since the last delivery.

Min probability move is what makes this worth having on a busy platform: prices twitch constantly, so a plain content hash would call nearly every market updated on every run. Set it to 0.05 and a market comes back only after its price has moved five points. Tested in both directions: a 2-point move produces zero rows, a 20-point move produces the full set again.

State key keeps several schedules apart; two schedules with different keys never see each other's memory.

What can you filter before being billed?

Every filter runs before rows are written, so a filtered-out market never reaches your bill:

  • Keyword — substring over question, slug, description and event title.
  • Tag — the platform's own tags: politics, crypto, sports, economy, elections and the rest. Applied by the API itself.
  • Market or event URLs — paste links straight from the browser. A link with two path segments is a market; a link with one is an event, and its markets are expanded for you.
  • Min lifetime volume, min 24h volume, min liquidity — in dollars, sent to the API where it supports them and re-checked on every row.
  • Min / max price of the first outcome — 0.9 and up for near-certainties, 0.1 and below for longshots.
  • Ending within hours — markets resolving soon.
  • Include closed markets — off by default; turn it on for resolved history.
  • Sort by — 24h volume, lifetime volume, liquidity, end date, start date or competitiveness, ascending or descending. With a limit set, sorting decides which markets you get, so it is a filter in practice.

What does the output look like?

A market row, abridged:

{
"marketId": "2252244",
"conditionId": "0xa3b36b2d6104d34af4e6c6215fc818e43352e78a748fbfb0b85e3a35f71dec9a",
"slug": "will-there-be-no-change-in-fed-interest-rates-after-the-september-2026-meeting-615",
"question": "Will there be no change in Fed interest rates after the September 2026 meeting?",
"groupItemTitle": "No change",
"url": "https://polymarket.com/event/fed-decision-in-september-762/will-there-be-no-change-in-fed-interest-rates-after-the-september-2026-meeting-615",
"eventId": "481717",
"eventTitle": "Fed Decision in September?",
"tags": ["Fed Rates", "Economy", "Politics"],
"outcomes": [
{"outcome": "Yes", "price": 0.945, "impliedProbability": 0.945, "tokenId": "9123..."},
{"outcome": "No", "price": 0.055, "impliedProbability": 0.055, "tokenId": "4471..."}
],
"impliedProbability": 0.945,
"topOutcome": "Yes",
"outcomePriceSum": 1.0,
"overround": 0.0,
"bestBid": 0.944,
"bestAsk": 0.947,
"midPrice": 0.9455,
"spread": 0.003,
"volume24hr": 1607864.0,
"liquidity": 221725.52,
"volumeToLiquidity": 7.25,
"endDate": "2026-09-16T12:00:00Z",
"hoursToEnd": 118.6,
"endsWithin24h": false,
"bidDepthUsd": 118958.21,
"askDepthUsd": 91240.77,
"bookImbalance": 0.13,
"source": "polymarket.com",
"scrapedAt": "2026-09-12T01:18:53Z"
}

A market row carries 70 fields without enrichment and 92 fields with the order book, price history, holders and tape switched on. Compact output reduces it to the 17 fields a decision is made on.

How much does it cost to run?

Pricing is pay per event: $0.001 when a run starts and $0.0005 per row written to the dataset, which is $0.50 per 1,000 rows. Platform usage is included in that price — compute is not billed to you separately.

Rows in a runWhat you pay
100$0.051
1,000$0.501
10,000$5.001

Filters and monitor mode both cut rows before they are written, so both cut the bill directly.

How do you use this for a scheduled job?

A working setup for hourly monitoring of one topic:

  1. Set Tag to the topic you follow, e.g. politics.
  2. Set Min 24h volume to a level that removes dead markets, e.g. 1000.
  3. Turn on Monitor mode, set Min probability move to 0.05, give the schedule its own State key.
  4. Optionally set a Webhook URL — Slack and Discord incoming webhooks are formatted for them automatically, any other URL receives plain JSON with the run summary and up to 20 rows.

The first run builds the baseline and delivers everything that matches. Later runs deliver only markets that moved past your threshold.

What can this Actor not do?

Named honestly, because the comparison matters more than the sales pitch:

  • No Telegram or WhatsApp delivery. Those need bot tokens and phone-number ids; only webhook-style delivery (generic, Slack, Discord) is implemented.
  • No MCP or Notion connector. Results come out through the dataset, the Apify API and webhooks.
  • No raw API blob per row. Every field is parsed and typed instead; the conditionId and marketId in each row are enough to fetch the untouched record yourself.
  • No trading, no account data. This Actor reads only public endpoints — no key, no proxy, no browser — so it cannot place orders or read a private account. Wallet mode reads what the chain publishes about any address.
  • Order book, history, holders and tape cost extra API requests per returned market — the order book costs one per outcome, so two on a binary market. They are off by default for that reason.
  • No profit-and-loss time series for a wallet. Wallet mode returns the positions a wallet holds now, with realized and unrealized P&L on each, not a P&L curve over a chosen window.
  • Price history covers the first outcome. On a binary market the second outcome is its complement; on a multi-outcome market you get the history of the first listed outcome only.

How is this checked?

Four suites, all runnable from the project:

  • python3 tests/test_logic.py — parsing, arithmetic, filters, memory and shaping on recorded API responses, no network.
  • python3 tests/test_live.py — the live API: the cursor advances, the wrong cursor name silently does not, the offset ceiling is where we say it is, server filters really filter.
  • python3 tests/test_lifecycle.py — a run broken in the middle, resumed, repeated; memory between runs; the spending limit; webhook delivery.
  • python3 tools/verify_readme.py — every number in this file against the code and against tools/measurements.json.

The ordering rule that matters for your data: rows are written to the dataset first and only then marked as delivered in memory. The reverse order loses rows silently when a run is interrupted, and the lifecycle suite fails on purpose if anyone swaps it back.

FAQ

Do you need a Polymarket account or API key?

No. The Actor reads Polymarket's public APIs — the Gamma catalogue, the CLOB order book and the public data API. No key, no login, no proxy, no browser.

How current is the data?

Each row is a snapshot taken during the run, and scrapedAt records the moment. For tighter tracking, filter to one tag or a handful of markets and run more often; for a whole-catalogue picture, run without filters and accept that the sweep takes minutes rather than seconds.

Can you get closed and resolved markets?

Yes. Turn on Include closed markets. Closed rows keep their last prices and their end date, which is what backtesting needs. For price paths, turn on Include price history and pick a window up to max.

How do you find a market or event?

Paste its polymarket.com URL into Market or event URLs. An event link expands into its markets; a market link returns just that market. No ids to look up.

What does arbitrageGap mean, exactly?

On a mutually exclusive event, the winning outcome pays $1. If the prices of all outcomes add up to less than $1, the difference is what a buyer of the whole set would keep. That difference is arbitrageGap. It ignores fees, slippage and the size actually available at those prices, so treat it as a screen, not a trade.

What happens when a run hits your spending limit?

The platform stops charging at the limit but does not stop the run. This Actor reads the remaining budget at the start and stops writing rows once it is used up, so you never get a half-billed run, and the run report says chargeLimitReached.

Can the output be used by an AI agent?

Yes. Compact output returns 17 core fields instead of 92, Description max length trims the long resolution text, and Drop empty fields removes nulls and empty arrays. Together they cut the payload enough to fit many markets into a context window.

Is scraping Polymarket allowed?

The Actor reads only public API endpoints, the same ones the website uses, and does not log in or bypass anything. Wallet addresses, positions and trades are public blockchain data, and the display names attached to them are published by the platform. You are responsible for complying with Polymarket's terms and with the rules that apply to you. This Actor is not affiliated with or endorsed by Polymarket.