# Polymarket Markets Scraper (`nice_dev/polymarket-markets-scraper`) Actor

Scrape Polymarket prediction markets: odds, prices, volume, liquidity, order book, price history and trades. Search by keyword, category or market URL. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/nice\_dev/polymarket-markets-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** Automation, News, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.09 / 1,000 markets

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

### 🔎 What is Polymarket Markets Scraper?

**Polymarket Markets Scraper** extracts **prediction markets from [Polymarket](https://polymarket.com)**: **question, outcome prices (the implied probability), best bid and ask, spread, 24h / 7d / 30d / all-time volume, liquidity, open interest, price moves, opening and closing dates** — plus the **live order book**, the **price history**, the **latest trades** and the **biggest holders** when you ask for them.

Type a **keyword** (`bitcoin`), pick a **category**, paste a market URL — or ask for nothing at all and walk the **whole catalogue, over 40,000 open markets**. Click **Start** and download the markets in JSON, CSV or Excel. No login, nothing to set up, and it is **fast: a market costs no request of its own (100 per API page), and the order books of 100 markets cost a single extra request — 500 markets, with their order book, in seconds**.

### 📋 What data can you extract from Polymarket?

One item per market, 74 fields:

| Category | What you get |
| --- | --- |
| 🎯 **Market** | the question, the resolution rules in full, the page link, the site's id — `Will United Russia (ER) gain the most seats…?` |
| 📈 **Odds and prices** | every outcome with its price (the implied probability), yes / no shortcuts, best bid and ask, spread, last trade — `Yes 0.815 / No 0.185` |
| 💵 **Money** | 24h, 7-day, 30-day, 1-year and all-time volume, liquidity, open interest — `$1,601,129 traded in 24h` |
| 📊 **Price moves** | the move over 1 hour, 24 hours, a week and a month, in probability points — `+8 points in 24h` |
| 🕒 **Dates and state** | opening, closing, creation and update dates, open / closed / archived / accepting orders — `ends 2026-09-30` |
| 🏁 **Resolution** | resolved or not, **the outcome that paid out**, the source of truth, how it was settled and by which contract, bonds, rewards — `winner: Yes` |
| 💸 **Fees** | maker and taker base fees, **the fee category and its schedule** (taker rate, maker rebate) — `politics_fees, 4 %` |
| 🔗 **On-chain ids** | condition id, question id, one token per outcome, the negative-risk flag and group ids |
| 🗂️ **Event and categories** | the parent event (title, volume, open interest, comments) and the tags — `Politics` |
| 📖 **Order book** (on by default) | bids and asks with price and size for both outcomes, ten levels a side |
| 💬 **Comments** (option) | the comments of the market's event: text, author, date, reactions, replies with their thread, GIFs |
| 📉 **Price history, trades, holders** (options) | the price series, the latest trades with wallet, pseudonym and user name, the biggest positions per outcome (up to 500) with the verified badge |
| 🧾 **Run** | the search the market was found by, the timestamp |

Every field, with an example, is listed under **Output** below (All 74 fields).

### ✅ Why use Polymarket Markets Scraper?

- 🚀 **Fast**: 100 markets per API request, and the order books of 100 markets in one more — 500 markets with their order book in seconds.
- 🗺️ **The whole catalogue, not the first page**: over 40,000 open markets, walked to the end — leave the keyword empty and set `maxItems: 0`.
- 🏁 **Resolved markets with their winner**: `status: "resolved"` gives the settled markets, the outcome that paid out and when they closed — a ready-made backtesting dataset.
- 📖 **Order book in the same run**: bids and asks with price and size for **both outcomes**, on by default ($0.10 per 1,000 markets; untick it for the markets alone).
- 🐋 **Whale trades**: `includeRecentTrades` with `minTradeSizeUsd` returns the trades above your threshold, wallet and pseudonym included.
- 🔔 **Monitoring built in**: tick **Only new markets**, schedule the Actor, and each run returns (and charges) only the markets it has never delivered.
- 🎯 **Filters for next to nothing**: volume, liquidity, open interest, fee category, spread, 24h price move, "ending within the next hour", opening and closing dates — a filtered-out market is never charged, and a filter Polymarket cannot apply itself costs $0.20 per 1,000 results pages read.
- 🔌 API, scheduling, monitoring, integrations (Make, Zapier, n8n, Google Sheets…) and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to scrape Polymarket

1. Create a free Apify account.
2. Open **Polymarket Markets Scraper** and type a **Search keyword** (e.g. `bitcoin`), or pick a **Category** (`politics`, `crypto`, `sports`).
3. Or paste Polymarket URLs into **Start URLs**: an event page, a single market page, or a category page.
4. Set **Max markets** (100 by default, 0 = no limit) — and **Max markets per search** when you run several searches — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to scrape Polymarket?

This Actor uses **pay per event** pricing, at its launch price: **$0.09 per 1,000 markets** (all 74 fields but the options), **$0.10 per 1,000 markets per option** you tick — order book, price history, trades, holders, comments: $0.0001 per market each — and **$0.001 per run start** (10 cents per 100 runs). Every Apify plan pays the same: $0.09 (Bronze), $0.09 (Silver) and $0.09 (Gold) per 1,000 markets. Platform usage (compute, proxy) is included in the price.

| What you ask for | Price per 1,000 markets | Example |
| --- | --- | --- |
| Markets only (every option off) | $0.09 | the whole catalogue of ≈ 200,000 open markets ≈ $18.00 |
| Markets + order book (the default input) | $0.19 | the whole catalogue with its order books ≈ $38.00; a daily monitor of 200 new markets ≈ $0.04 |
| Markets + the 5 options, each on its first page | $0.59 | 1,000 markets with book, price history, trades, holders and comments ≈ $0.59 |

An option is charged only to the markets that get it: a closed market has no order book, and an option whose page fails, or that Polymarket answers without data, is not charged for that market.

Two options can go past their first page, and each page after it is **$0.03 per 1,000 extra option pages** ($0.00003 a page, the same on every plan): a price history over a **range of dates** (one page per 15 days, counted from the day the market was created) and **more than 100 comment threads** (one page per 100 threads). Trades (up to 1,000), holders (up to 500 per outcome) and a price history interval are always one page. The most a market can cost:

| Input | Options | Extra option pages, at most | Most a market costs |
| --- | --- | --- | --- |
| Markets only (every option off) | 0 | 0 | $0.00009 |
| Defaults (the order book) | 1 | 0 | $0.00019 |
| Every option on its first page | 5 | 0 | $0.00059 |
| Order book + `priceHistoryStartDate: "180 days"` | 2 | 11 | $0.00062 |
| Order book + `maxCommentsPerEvent: 1000` | 2 | 9 | $0.00056 |
| Every option at its maximum (750 days of history, 1,000 comment threads) | 5 | 58 | $0.00233 |

Filtered pages cost **$0.20 per 1,000 results pages** ($0.0002 a page, the same on every plan). Polymarket applies the volume, liquidity, date and status filters itself on the catalogue: they cost nothing more. The other filters — 24h volume, open interest, spread, fee category, 24h price move, excluded words, `status: "resolved"` — and every filter of a keyword search (the status of its markets included) are checked here, on pages of 100 markets of which only a few may pass: each results page read for them is one filtered page, whether its markets pass or not. Example: the whole open catalogue (≈ 200,000 markets) filtered by open interest reads ≈ 2,000 pages ≈ $0.40. A list of exact identifiers and `onlyNew` alone never charge a page.

The log says, before the run starts, the options charged, the most extra pages a market of your input can take and which filters charge their pages, and at the end how many of each were charged. A page that fails is never charged, and a maximum cost per run counts each market at its dearest and pays each filtered page before it is read, so the run never goes past it.

### ⚙️ Input

```json
{
    "query": "bitcoin",
    "maxItems": 200,
    "includeOrderBook": true
}
```

Several searches, a cap per search, only the markets that move, only the ones not delivered before:

```json
{
    "searchQueries": ["bitcoin", "election"],
    "categories": ["crypto", "politics"],
    "maxItemsPerQuery": 50,
    "minVolume24h": 10000,
    "minPriceChangePct": 5,
    "onlyNew": true,
    "stateKey": "crypto-daily"
}
```

Resolved markets with their winner, for a backtest:

```json
{
    "status": "resolved",
    "sortBy": "endDate",
    "maxItems": 5000,
    "includePriceHistory": true,
    "priceHistoryInterval": "max",
    "priceHistoryFidelity": 1440
}
```

Or with your own URLs:

```json
{
    "startUrls": [
        { "url": "https://polymarket.com/event/which-party-will-gain-most-seats-in-russian-parliamentary-election" },
        { "url": "https://polymarket.com/markets/crypto" }
    ],
    "maxItems": 500
}
```

| Field                                                | Notes                                                                                                                                  |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `query`, `searchQueries`                              | Free-text search; `searchQueries` adds more keywords (one search each). Ignored when `startUrls` is set.                                  |
| `categories`, `tagIds`                                | Category slugs as in the site URL (`politics`, `crypto`, `sports`) and numeric tag ids; a category typed as the site shows it (`Pop Culture`) is looked up as its slug (`pop-culture`). Every keyword × every category (max 500 searches per run). |
| `marketSlugs`, `eventSlugs`, `conditionIds`, `marketIds`, `outcomeTokenIds` | Exact identifiers, fetched directly — no search, no pagination. An outcome token (`clobTokenIds`) finds its market whichever outcome it stands for. |
| `startUrls`                                           | Event, market, category or search pages of the site; the status, sort, filters and monitoring apply to them too.                        |
| `status`                                              | Open, closed, resolved (settled, with the winning outcome) or all.                                                                       |
| `sortBy`, `sortDescending`                            | 24h volume, total volume, liquidity, start date, end date, creation date, spread or competitiveness (catalogue and category searches; a keyword search comes in the site's relevance order). With a date bound or the monitoring mode, the default sort becomes the newest markets first. |
| `maxItems`, `maxItemsPerQuery`                        | Stop after this many markets for the run (0 = unlimited), and a cap for EACH search.                                                      |
| `includeEvent`, `includeTags`                         | The parent event and the categories: both on by default, and they cost no extra request.                                                  |
| `includeOrderBook`, `orderBookDepth`                  | Live bids and asks per outcome, on by default, cut to ten levels per side (zero = the whole book). $0.0001 per market.                                         |
| `includePriceHistory`, `priceHistoryInterval`, `priceHistoryFidelity` | The price series per outcome, over the last hour, 6 hours, day, week, month or since the market opened, one point per hour by default (Polymarket's floor: 5 minutes for a week, 10 minutes for a month, 720 minutes for the whole life of a market). $0.0001 per market (the option). |
| `priceHistoryStartDate`, `priceHistoryEndDate`         | Or ANY range of dates instead (`2026-08-01` to `2026-08-31`, or `30 days` back to now), at any resolution — even one point a minute — up to 750 days and 10,080 points per outcome. One request per 15 days of range per market, from the day the market was created; each after the first is an extra option page ($0.00003). |
| `includeRecentTrades`, `recentTradesLimit`, `minTradeSizeUsd` | The latest trades of each market (side, size, price, time, wallet, trader name and picture), up to 1,000 trades per market, worth at least the USD amount you set for a whale run. $0.0001 per market (the option). |
| `includeTopHolders`, `maxHoldersPerOutcome`           | The biggest position holders, 20 per outcome by default, up to 500 (wallet, pseudonym, user name, verified badge, picture, size) — in one request per market whatever the number. $0.0001 per market (the option). |
| `includeComments`, `maxCommentsPerEvent`              | The comments of the market's event (text, author, date, reactions, replies), 100 threads by default, up to 1,000 — one request per 100 threads per market, each after the first an extra option page ($0.00003); the markets of one event carry the same comments. Switches `includeEvent` on. $0.0001 per market (the option). |
| `minVolume24h`, `minVolume`, `minLiquidity`, `minOpenInterest` | Money floors in USD (open interest = the value of every open position of the market's event); zero means no floor. |
| `minSpread`, `maxSpread`                              | Bid-ask spread bounds in probability points: 0.05 is 5 cents.                                                                             |
| `minPriceChangePct`                                   | Only markets that moved by at least this many percentage points over 24 hours, up or down.                                                |
| `endingWithinMinutes`                                 | Only markets closing within the next N minutes.                                                                                          |
| `postedAfter`, `postedBefore`                         | Opening date range: `2026-09-01`, or a period before now (`7 days`, `2 weeks`, `1 month`, `24 hours`).                                     |
| `endingAfter`, `endingBefore`                         | Closing date range: `2026-12-31`, or a period AHEAD of now (`30 days` in `endingBefore` = closing in the next 30 days).                  |
| `excludeKeywords`                                     | Drop the markets whose question contains one of these words (case and accents ignored).                                                   |
| `feeTypes`                                            | Only the markets of these fee categories (`politics_fees`, `sports_fees_v3`, `crypto_fees_v2`, `zero_fees`…); `none` = the markets without one. |
| `onlyNew`, `stateKey`, `resetState`                   | Monitoring: only the markets never delivered under this memory key; `resetState` forgets the memory.                                       |
| Advanced                                              | `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

A real item, shortened (the description, the event description and the book of the second outcome are cut here):

```json
{
    "id": "1130012",
    "url": "https://polymarket.com/event/which-party-will-gain-most-seats-in-russian-parliamentary-election/will-united-russia-er-gain-the-most-seats-in-the-next-russian-parliamentary-election",
    "slug": "will-united-russia-er-gain-the-most-seats-in-the-next-russian-parliamentary-election",
    "question": "Will United Russia (ER) gain the most seats in the next Russian parliamentary election?",
    "description": "Parliamentary elections are to be scheduled to be held in Russia in September 2026…",
    "conditionId": "0x502a94e5c525766d5ee7f16c6568131ba1b2cbadb69c703af05a6ef00336ed64",
    "questionId": "0xc194d621e2ef9468b86ed0db1328fd8d56ae8fba1e21b94c5c515e96ecbfc400",
    "clobTokenIds": ["20915769520649892253891152116814645067070024223185517956799957803974344024878", "115351075585746600277716377744935410125916932950844626289798775482755919708780"],
    "outcomes": ["Yes", "No"],
    "outcomePrices": [0.815, 0.185],
    "yesPrice": 0.815,
    "noPrice": 0.185,
    "bestBid": 0.81,
    "bestAsk": 0.82,
    "spread": 0.01,
    "volume": 16144126.59,
    "volume24hr": 1601129.41,
    "liquidity": 478206.56,
    "openInterest": 5728158.26,
    "priceChange24h": 0.08,
    "startDate": "2026-01-07T21:34:52.537Z",
    "endDate": "2026-09-30T00:00:00.000Z",
    "closedTime": null,
    "active": true,
    "closed": false,
    "archived": false,
    "acceptingOrders": true,
    "resolved": false,
    "winningOutcome": null,
    "competitive": 0.9097,
    "groupItemTitle": "United Russia (ER)",
    "event": { "id": "149589", "slug": "which-party-will-gain-most-seats-in-russian-parliamentary-election", "title": "Which party will gain most seats in Russian Parliamentary Election?", "openInterest": 5728158.26, "commentCount": 12 },
    "tags": [{ "id": "2", "label": "Politics", "slug": "politics" }],
    "orderBook": { "Yes": { "bids": [{ "price": 0.81, "size": 41447.61 }], "asks": [{ "price": 0.82, "size": 12000 }] } },
    "priceHistory": null,
    "recentTrades": null,
    "topHolders": null,
    "comments": null,
    "searchUrl": "https://gamma-api.polymarket.com/markets/keyset?include_tag=true&limit=100&closed=false&order=volume24hr&ascending=false",
    "scrapedAt": "2026-09-20T05:12:00.000Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel.

#### All 74 fields

| Field                                                            | Example                                                                                  |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `id`, `slug`, `url`, `question`, `description`                    | `1130012`, `will-united-russia-er-gain…`, the market page, the question, the resolution rules |
| `outcomes`, `outcomePrices`, `yesPrice`, `noPrice`                | `["Yes","No"]`, `[0.815, 0.185]`, `0.815`, `0.185`                                        |
| `bestBid`, `bestAsk`, `spread`, `lastTradePrice`, `competitive`   | `0.81`, `0.82`, `0.01`, `0.82`, `0.91`                                                    |
| `volume`, `volume24hr`, `volume1wk`, `volume1mo`, `volume1yr`     | all-time and rolling volumes in USD                                                       |
| `liquidity`, `openInterest`                                       | `478206.56`, `5728158.27`                                                                 |
| `priceChange1h`, `priceChange24h`, `priceChange1wk`, `priceChange1mo` | the move in probability points (`0.08` = 8 points)                                    |
| `startDate`, `endDate`, `createdAt`, `updatedAt`, `closedTime`    | ISO 8601 UTC (`startDate` is what the date filters read)                                  |
| `active`, `closed`, `archived`, `acceptingOrders`, `acceptingOrdersTimestamp`, `enableOrderBook` | the state of the market, and when its order book opened |
| `resolved`, `winningOutcome`, `resolutionSource`, `umaResolutionStatus`, `automaticallyResolved`, `resolvedBy` | `true`, `Yes`, the source of truth, how it was settled, the resolver contract |
| `umaBond`, `umaReward`, `makerBaseFee`, `takerBaseFee`, `feeType`, `feeSchedule` | `500`, `5`, fees, the fee category (`politics_fees`) and its rate / maker rebate |
| `rewardsMinSize`, `rewardsMaxSpread`, `orderMinSize`, `orderPriceMinTickSize` | liquidity rewards and order limits                                            |
| `conditionId`, `questionId`, `clobTokenIds`, `negRisk`, `negRiskMarketId`, `negRiskRequestId` | the on-chain ids (one token per outcome), the negative-risk group |
| `groupItemTitle`, `line`, `featured`, `restricted`, `funded`      | `United Russia (ER)`, the handicap line of a sports market, flags                         |
| `imageUrl`, `iconUrl`                                             | the market picture                                                                        |
| `event`, `tags`                                                   | the parent event (title, slug, url, volume, open interest, comments) and the categories   |
| `orderBook`, `priceHistory`, `recentTrades`, `topHolders`, `comments` | filled by the options below, `null` otherwise                                         |
| `searchUrl`, `scrapedAt`                                          | the query it was found by, ISO timestamp                                                  |

`outcomes`, `outcomePrices` and `clobTokenIds` are **real arrays** (Polymarket sends them as text), and `winningOutcome` **names the outcome that paid out** on a resolved market.

### 💡 Tips

#### How to get more results

Leave **Search keyword** empty and set `maxItems` to `0`: the Actor then walks the whole catalogue, over 40,000 open markets, page after page. `status: "all"` adds the closed ones — that is where the history lives.

#### How to reduce costs

The levers are `maxItems`, `maxItemsPerQuery`, the filters (a filtered-out market is free; a filter Polymarket cannot apply itself costs $0.0002 per results page read, so combine it with one it can — `minVolume`, `minLiquidity`, the dates), `onlyNew` for recurring runs (you never pay twice for the same market) and the options: each one ticked adds $0.10 per 1,000 markets — untick `includeOrderBook` for the markets alone at $0.09 per 1,000. Only a price history range and more than 100 comment threads add extra option pages: a shorter range, or fewer threads, costs less — a coarser resolution does not (a page covers 15 days whatever the number of points).

#### Several searches in one run

Fill `searchQueries` and / or `categories`: the Actor runs one search per keyword × category (3 keywords × 4 categories = 12 searches, up to 500 per run). The single `query` field still works and is added to the list. A market found by several searches is saved — and charged — once. Set `maxItemsPerQuery` to give every search its own cap: without it the first searches can use up the whole `maxItems` budget.

#### Monitoring: only the new markets

Tick **Only new markets** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the markets already delivered: they are not saved, not charged, and their order book is not even fetched. The memory lives in a named key-value store of your account (`polymarket-markets-scraper-seen`, up to 150,000 markets per key) and is only updated with markets that really reached the dataset, so a failed run never hides anything. Give each schedule its own `stateKey`, and tick `resetState` once to start over. Searches are then sorted by newest, and a search stops once it meets 500 markets in a row you already have.

#### Filter by date

`postedAfter` and `postedBefore` read the date a market OPENED; `endingAfter`, `endingBefore` and `endingWithinMinutes` read the date it closes. All take a date (`2026-09-01`, the whole day is included, UTC) or a period (`7 days`, `2 weeks`, `1 month`; via the API also `24 hours` or a full ISO date-time): before now for the opening dates, ahead of now for the closing dates (`1 month` on 31 January = 28 February). `endingBefore` alone also keeps the open markets already past their end date but not settled yet; `endingWithinMinutes` starts from now. A market without the date a filter reads is dropped as soon as that bound is set. Filtered-out markets are never charged and do not count in `maxItems`.

#### Track the whales

`includeRecentTrades` with `minTradeSizeUsd: 10000` returns, for each market, only the trades worth at least $10,000 — with the wallet, the trader's pseudonym, the side, the size, the price and the transaction hash. Add `includeTopHolders` for the biggest open positions of each outcome.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per Polymarket market. Actor id: `nice_dev/polymarket-markets-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/polymarket-markets-scraper`.

Smallest input, for a cheap first call:

```json
{
    "query": "bitcoin",
    "maxItems": 10
}
```

Key output fields: `url`, `question`, `outcomes`, `outcomePrices`, `volume24hr`, `liquidity`, `endDate` and `orderBook` (with `includeOrderBook`).

Cost: $0.09 per 1,000 markets, plus $0.10 per 1,000 markets for each option ticked (the order book is on by default: $0.19 per 1,000), plus $0.001 per run start; every Apify plan pays the same. Filtered pages and extra option pages cost extra, see the pricing section above. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape Polymarket?

The Actor only reads what Polymarket shows publicly to any anonymous visitor. It logs in to nothing, places no order and holds no funds. Results can contain personal data — a trade or a holding carries the trader's wallet address and pseudonym, which are public on the blockchain, and the user name and picture of the trader's Polymarket profile (a holder who keeps the name private gets `null`; the trade feed has no such setting and gives the name as Polymarket's API does); the comments (`includeComments`) carry their authors the way the holders are — and personal data is protected by GDPR: those fields are off by default (`includeRecentTrades`, `includeTopHolders`, `includeComments`), and you should not store them without a legitimate reason. You are responsible for using the data in compliance with Polymarket's Terms of Use and applicable law; prediction markets are restricted in several countries, and reading prices is not trading. This Actor is not affiliated with Polymarket.

#### Why can a market cost more than $0.00009?

Each option you tick adds $0.0001 to the markets that get it (the order book is on by default: $0.00019 a market). An option can also go past its first page: a price history over a range of dates longer than 15 days, or more than 100 comment threads. Each page after the first is one more request to Polymarket, and is charged $0.00003 (`extra-option-page`) — so 750 days of history, 50 pages, add $0.0015 to the market. A page that fails, or that Polymarket answers without data, is never charged. A run that is stopped and resumed reads again the pages it lost, and charges them once.

#### Does it need a login or a proxy?

No login, no account, no API key. The proxy is included in the price: leave the default setting (the residential proxy is not available). A request the site turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 60 seconds).

#### Is the data safe to open in Excel or to show on a web page?

Every URL field (`url`, `imageUrl`, `iconUrl`, `event.url`, `profileImageUrl` of a trade, a holder or a comment, `url` of a comment's picture) holds an http(s) URL or `null`. A comment's `body` is plain text: any HTML tag is removed. Questions and descriptions are written by the market creators and copied as they are: a text can begin with `-`, `+`, `=` or `@`, which Excel and Google Sheets may read as a formula in a CSV file — import those columns as text. Prices and volumes are numbers, never text. On a web page, escape every field like any text written by a stranger.

#### Known limitations

- `tags` only names the categories of the market; the full category tree of the site is not exposed.
- `priceChange1h` is not sent for every market: it is `null` there.
- The price history has a floor set by Polymarket: 5 minutes between two points for a week, 10 minutes for a month, 720 minutes (two points a day) since the market opened — finer, Polymarket only serves the last 31 days; a finer `priceHistoryFidelity` is refused before the run starts. For a fine series further back, use `priceHistoryStartDate` / `priceHistoryEndDate`.
- `onlyNew` remembers market ids, not their content: a market whose price changed is not returned again, nor a market delivered open that has since closed or resolved — give a `status: "resolved"` schedule its own `stateKey`.
- The order book is the live one at the moment of the run: two runs a minute apart give two different books.
- Two runs sharing the same `stateKey` at the same time may both return the same new market.

**A run the platform stops without warning** (out of memory, run timeout)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the markets already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved once a minute: resurrect the stopped run and the markets it had saved meanwhile join the memory; leave it stopped for good, and the next run may return up to a minute of them once more.

#### Something doesn't work?

The last line of the log counts the markets saved and filtered out, and the requests that failed after every retry. Those requests are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause. A run that saved some markets fails too when at least as many requests failed for good as were read, or when at least as many option pages (order book, price history, trades, holders, comments) failed for good as were answered: a green run of bare markets would hide an outage. One failed request among many is only a warning.

If Polymarket changes its pages, you are told instead of paying for blank rows. A results page that counts markets but gives none the Actor can read is an error (listed in `FAILED_REQUESTS`), never a quiet "No markets found". If the first 20 markets read all lack their question, slug, outcomes, prices, ids or dates, the run saves nothing more, stops and fails, and its last message names the missing field: at most those first markets are charged.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Actor input Schema

## `startUrls` (type: `array`):

Polymarket URLs to start from: event pages (`https://polymarket.com/event/<event-slug>`), single market pages (`https://polymarket.com/event/<event-slug>/<market-slug>`) or category pages (`https://polymarket.com/markets/<tag>`). When this list is not empty, the search fields below (keyword, categories, identifiers) are ignored; the market status, the sort, the filters, the caps and the monitoring still apply to every page. Max 1 000 URLs.

## `query` (type: `string`):

Free-text search, as typed on the site (e.g. `bitcoin`, `election`). Polymarket searches events, so every market of every matching event is returned. Empty = no keyword filter, the whole catalogue is walked (use the filters and caps below). With a keyword every filter, the status of the markets too, is checked on our side: each results page is charged as a filtered page ($0.0002).

## `searchQueries` (type: `array`):

Several keywords in one run: one search per keyword. Added to **Search keyword**; a market found by several searches is saved once.

## `categories` (type: `array`):

Polymarket category slugs, as in the site URL `polymarket.com/markets/<slug>` (e.g. `politics`, `crypto`, `sports`). A category typed as the site shows it (`Pop Culture`, `US Politics`) is looked up as the slug of its page (`pop-culture`, `us-politics`); case does not matter. Each category is one search, combined with the keywords above (max 500 searches per run). A slug the site does not know stops the run before anything is charged.

## `tagIds` (type: `array`):

Polymarket numeric tag ids (e.g. `21` for crypto), for the tags that have no slug. Same effect as **Categories**.

## `marketSlugs` (type: `array`):

Exact market slugs (the last part of a market URL, e.g. `will-bitcoin-hit-200k-in-2026`). Each one is fetched directly — no search, no pagination.

## `eventSlugs` (type: `array`):

Exact event slugs (e.g. `next-prime-minister-of-ethiopia`). Every market of the event is returned.

## `conditionIds` (type: `array`):

On-chain condition ids (`0x…`), as used by the CLOB and by the trade API. Each one is fetched directly.

## `marketIds` (type: `array`):

Numeric Polymarket market ids (e.g. `559651`). Each one is fetched directly.

## `outcomeTokenIds` (type: `array`):

CLOB token ids of an outcome (the `clobTokenIds` of a market, long decimal numbers): the market of each token is fetched directly — either outcome's token finds it.

## `status` (type: `string`):

Which markets to return. `open` = still accepting orders. `closed` = finished, whatever the outcome. `resolved` = finished AND settled, with the winning outcome. `all` = everything, open and finished. Applies to exact identifiers and pasted market URLs too: a market that has finished is only returned with `closed`, `resolved` or `all`. `resolved` is checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `sortBy` (type: `string`):

Order the site returns the markets in — it decides which markets come first when **Max markets** stops the run. Applies to the catalogue and category searches; a keyword search comes in the site's own relevance order.

## `sortDescending` (type: `boolean`):

Highest value first (biggest volume, latest date). Untick for the other way round.

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

Maximum number of markets to save for the whole run (after deduplication and filters). 0 = no limit — the whole catalogue is over 40 000 open markets.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (keyword, category or start URL), so that the first search cannot use up the whole **Max markets** budget. 0 = no per-search cap.

## `includeEvent` (type: `boolean`):

Add the parent event (title, description, slug, URL, total volume, open interest, comment count).

## `includeTags` (type: `boolean`):

Add the market's categories/tags (label and slug).

## `includeOrderBook` (type: `boolean`):

Add the live CLOB order book (bids and asks with price and size) for every outcome. The books of 100 markets come in one extra request. Option charged $0.0001 per market that gets a book ($0.10 per 1,000; a closed market has none) — untick it for the markets alone, $0.09 per 1,000.

## `orderBookDepth` (type: `integer`):

How many price levels to keep on each side of the book. 0 = the whole book.

## `includePriceHistory` (type: `boolean`):

Add the price time series for every outcome: at the default resolution (one point an hour) 25 points over the last day (the default range), 744 over a month; up to about 4,500 at ten minutes over a month. One extra request per market, and a much heavier item — off by default. Option charged $0.0001 per market ($0.10 per 1,000).

## `priceHistoryInterval` (type: `string`):

How far back the price history goes.

## `priceHistoryFidelity` (type: `integer`):

Minutes between two points of the price history (60 = one point per hour). Lower = more points, heavier items. Polymarket's own floor: at least 5 for a week, at least 10 for a month, at least 720 for the whole life of a market (finer, Polymarket only gives the last 31 days: use the range of dates below) — a finer value is refused before the run starts.

## `priceHistoryStartDate` (type: `string`):

A range of dates for the price history instead of the range above: from this date, `2026-08-01`, or a period before now such as `30 days`, `6 months` (API: full ISO date-times work too). Any resolution, one extra request per 15 days of range per market, up to 750 days. The first 15 days are in the price of the option; each 15 days after them is an extra option page, $0.00003 (750 days: up to $0.0015 more per market).

## `priceHistoryEndDate` (type: `string`):

End of that range (the whole day is included): `2026-08-31`, or a period before now such as `7 days`. Empty = until now.

## `includeRecentTrades` (type: `boolean`):

Add the latest trades of the market (side, size, price, time, wallet, trader pseudonym). One extra request per market — off by default. Option charged $0.0001 per market ($0.10 per 1,000).

## `recentTradesLimit` (type: `integer`):

How many trades to keep per market, newest first: up to 1,000, in one extra request whatever the number.

## `minTradeSizeUsd` (type: `integer`):

Keep only the trades worth at least this much in USD (Polymarket's own filter, so the big trades are not lost behind the small ones). 0 = every trade.

## `includeTopHolders` (type: `boolean`):

Add the biggest position holders of the market (wallet, pseudonym, user name, verified badge, picture, size), per outcome. One extra request per market. Option charged $0.0001 per market ($0.10 per 1,000). These are public on-chain identities — off by default.

## `maxHoldersPerOutcome` (type: `integer`):

How many holders to keep per outcome, biggest first: up to 500, in one extra request whatever the number.

## `includeComments` (type: `boolean`):

Add the comments of the market's event (text, author, date, reactions, replies with their thread, pictures). The markets of one event each carry the same comments. Switches 'Include parent event' on. One extra request per 100 threads per market: option charged $0.0001 per market ($0.10 per 1,000) with the first 100 threads, each 100 after them an extra option page, $0.00003. Authors are public identities — off by default.

## `maxCommentsPerEvent` (type: `integer`):

How many comment threads to keep per event, newest first, their replies along: up to 1,000 (one extra request per 100 threads). Each 100 after the first is an extra option page, $0.00003 — 1,000 threads: up to $0.0003 more per market.

## `minVolume24h` (type: `integer`):

Only markets traded at least this much (USD) over the last 24 hours. 0 = no minimum. Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `minVolume` (type: `integer`):

Only markets whose all-time volume (USD) reaches this. 0 = no minimum.

## `minLiquidity` (type: `integer`):

Only markets with at least this much liquidity (USD) in the order book. 0 = no minimum.

## `minOpenInterest` (type: `integer`):

Only markets whose event holds at least this much open interest (USD: the value of every open position). 0 = no minimum. Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `minSpread` (type: `number`):

Only markets whose bid-ask spread is at least this, in probability points. 0 = no minimum. Useful to look for the markets where the price is still being argued over. Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `maxSpread` (type: `number`):

Only markets whose bid-ask spread is at most this, in probability points (0.05 = 5 cents). 0 = no maximum. Useful to drop the markets nobody is really quoting. Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `minPriceChangePct` (type: `number`):

Only markets whose price moved by at least this many percentage points over 24 hours, up or down (5 = 5 points). 0 = no minimum. Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `endingWithinMinutes` (type: `integer`):

Only markets that close within this many minutes from now (60 = the next hour). 0 = no limit. Markets without an end date are dropped.

## `postedAfter` (type: `string`):

Only markets that opened on or after this date: `2026-09-01`, or a period before now such as `7 days`, `2 weeks`, `1 month` (API: `24 hours` and full ISO date-times work too). Reads the market's start date; markets without one are dropped.

## `postedBefore` (type: `string`):

Only markets that opened on or before this date (the whole day is included), or older than a period such as `30 days`. Reads the market's start date.

## `endingAfter` (type: `string`):

Only markets whose end date is on or after this date, or after a period from now such as `7 days`. Markets without an end date are dropped.

## `endingBefore` (type: `string`):

Only markets whose end date is on or before this date, or before a period from now such as `30 days`. Open markets already past their end date (not settled yet) are kept too; the `endingWithinMinutes` window starts from now.

## `excludeKeywords` (type: `array`):

Drop the markets whose question contains one of these words (case and accents ignored). Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `feeTypes` (type: `array`):

Only the markets of these Polymarket fee categories, e.g. `politics_fees`, `sports_fees_v3`, `crypto_fees_v2`, `zero_fees`; `none` = the markets without a fee category. Empty = every market. Checked on our side: each results page read for it is charged as a filtered page ($0.0002).

## `onlyNew` (type: `boolean`):

Skip the markets that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and their order book is not even fetched. First run = everything is new. A market delivered open is not returned again once it resolves: give a `resolved` schedule its own Memory key.

## `stateKey` (type: `string`):

Name of the memory used by **Only new markets**. Give each schedule / task its own key (e.g. `crypto-hourly`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every market again. Untick it afterwards.

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

Apify Proxy or your own proxies. Keep the default: it is included in the price. The residential Apify proxy is not available in this Actor.

## `maxConcurrency` (type: `integer`):

Maximum number of requests processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Global request rate. Polymarket allows far more (300 market requests and 1,500 order book requests per 10 s per IP), so lower this only if the log shows HTTP 429. A results page gives 100 markets, and the order books of those 100 markets take one more request: 600 a minute is thousands of markets a minute. Every request to the site counts, the next pages of an option read on the way included: a budget, not an even pace (spread them with the minimum delay below).

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests, in milliseconds. Unlike the per-minute rate, this spreads the requests evenly instead of letting them go out in a burst. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed. Behind a proxy, a request the site turns away is also retried on a new proxy session up to 10 times without using up these retries.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "startUrls": [],
  "query": "bitcoin",
  "searchQueries": [],
  "categories": [],
  "tagIds": [],
  "marketSlugs": [],
  "eventSlugs": [],
  "conditionIds": [],
  "marketIds": [],
  "outcomeTokenIds": [],
  "status": "open",
  "sortBy": "volume24hr",
  "sortDescending": true,
  "maxItems": 100,
  "maxItemsPerQuery": 0,
  "includeEvent": true,
  "includeTags": true,
  "includeOrderBook": true,
  "orderBookDepth": 10,
  "includePriceHistory": false,
  "priceHistoryInterval": "1d",
  "priceHistoryFidelity": 60,
  "includeRecentTrades": false,
  "recentTradesLimit": 100,
  "minTradeSizeUsd": 0,
  "includeTopHolders": false,
  "maxHoldersPerOutcome": 20,
  "includeComments": false,
  "maxCommentsPerEvent": 100,
  "minVolume24h": 0,
  "minVolume": 0,
  "minLiquidity": 0,
  "minOpenInterest": 0,
  "minSpread": 0,
  "maxSpread": 0,
  "minPriceChangePct": 0,
  "endingWithinMinutes": 0,
  "excludeKeywords": [],
  "feeTypes": [],
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8,
  "maxRequestsPerMinute": 600,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": 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 = {
    "query": "bitcoin",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/polymarket-markets-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 = {
    "query": "bitcoin",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/polymarket-markets-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 '{
  "query": "bitcoin",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/polymarket-markets-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/polymarket-markets-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/IjN3BKHM5aXqnmXr8/builds/AsHITfsAOdl7LC8xg/openapi.json
