# Polymarket markets and price history (`omraydev/polymarket-markets-history`) Actor

Export Polymarket market metadata, confirmed winners and both token price histories with resumable pagination. Filter by category, date range, tags and resolved-only.

- **URL**: https://apify.com/omraydev/polymarket-markets-history.md
- **Developed by:** [Om Ray](https://apify.com/omraydev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 market histories

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Polymarket market history and prices

If you're studying a prediction market, the winner alone doesn't tell you much, and you'll want to see how the price moved before it resolved. This actor exports market details together with confirmed winners and historical prices for both outcome tokens, so you can compare how prices changed with what eventually happened. You can filter the markets before exporting and resume a larger collection from a saved cursor instead of starting again.

A closed market doesn't always have a confirmed result. The actor checks CLOB winner flags and falls back to Gamma only when Gamma reports a resolved market with exact 0 and 1 outcome prices. It won't treat a 99-cent quote as proof of a winner, and it leaves sparse or empty price histories visible rather than filling the gaps. Past performance is not a prediction or a recommendation to trade.

### Run the actor

Set the filters in the actor's input to choose the markets you want. The example below requests three confirmed resolutions whose scheduled end dates fall on October 25 or 26, 2026. These dates filter scheduled market endings, not the actual resolution time or the price-history window.

```json
{
  "startDate": "2026-10-25T00:00:00Z",
  "endDate": "2026-10-26T23:59:59Z",
  "resolvedOnly": true,
  "fidelityMinutes": 60,
  "maxMarkets": 3,
  "maxPages": 10
}
```

For a local run, install the repository dependencies with `npm ci` at the root, then run the commands below. You don't need an Apify login or a Polymarket API key. Dataset rows go into `storage/datasets/default/`, and the coverage totals and next cursor appear in `storage/key_value_stores/default/OUTPUT.json`.

```sh
cd actors/polymarket-markets-history
npx apify run --input-file examples/input.json
```

### Choose markets and a history window

The `category` filter matches an explicit category or a tag ID, label or slug, without regard to case. If you supply `tags`, every tag must match information in Gamma's market or embedded event records. Missing tags don't match, and the actor doesn't guess a category from the question's wording. Set `resolvedOnly` to exclude markets without a confirmed winner.

The `startDate` and `endDate` filters apply to the market's scheduled `endDate`. A date without a time means midnight UTC, so include an end-of-day timestamp when you want the full final day. These filters don't trim the token price histories returned for each matching market.

Use `fidelityMinutes` to request price samples at intervals between 1 and 1,440 minutes. The API may return gaps, so the requested spacing doesn't guarantee a point at every interval. Omit `historyStart` and `historyEnd` to request the full history CLOB currently exposes, or set both for a window of up to 366 days. Explicit windows are fetched in seven-day sections.

### Read the export

Each row contains the market question and description together with its IDs, dates, tags, volume and liquidity. The `resolution` field records the winner evidence, and `tokens` contains each outcome's `tokenId` and price history with Unix-second timestamps. IDs remain strings so large token IDs aren't rounded. Each token's `coverage` includes source URLs, point counts, request errors and the actual first and last timestamps returned.

A recorded request for market `601818` on October 27, 2026 returned a confirmed `No` winner and 188 hourly points for each token. You can inspect the full records in the repository's sample outputs. Other markets can have much less history, so treat that as one example.

### Resume a larger export

`maxMarkets` limits exported rows, while `maxPages` limits Gamma requests, including pages with no matching markets. Both default to 100, and collection uses `/markets/keyset` instead of Gamma's offset pagination. The actor scans closed markets first and then open markets, so a small export may contain only closed markets. With `resolvedOnly` enabled, it scans only the closed phase and checks each market's winner evidence.

Copy `OUTPUT.resumeCursor` into the next run's `resumeCursor` input to continue. Keep the category, tags, date filters, history window, resolution filter and fidelity unchanged because a cursor with different filters is rejected. You can change `maxMarkets`, `maxPages` or `pageSize` between runs. The saved cursor includes the phase and keyset position, `nextPhase` tells you which phase will continue, and `exhausted` is true only when every requested phase has ended.

The actor shrinks each page to fit the rows or billing budget you have left, so a run that stops normally at its limit doesn't skip the rest of a source page. `CHECKPOINT` saves the last completed page, but an interruption or billing stop inside a page can cause that page to replay on resume. Rows already exported can then be charged again, and deduplicating by `marketId` removes duplicate data without refunding those charges. Source records can also change between runs because the API isn't a frozen snapshot.

### Limits and charges

Public price history has retention limits and gaps, and an empty history doesn't prove that a market never traded. A failed history request stays in `coverage.errors` while other tokens and markets can still be exported. Resolution lookup errors remain visible in each row; with `resolvedOnly`, markets without sufficient winner evidence are skipped and counted in `unresolvedSkipped`. The 10,000-offset cap on the wallet trade feed doesn't apply here, because this actor reads market price samples rather than wallet trades.

Each `market-history` event pays for one exported market row and its token histories, including any empty or partial histories reported in that row. The actor stops when its event budget is spent, and paid runs reject a missing event price or a positive automatic dataset-item price that would charge twice. Running it locally costs nothing on Apify. The repository's `PUBLISH.md` records the pricing and Console setup.

The HTTP client makes sequential requests with a browser User-Agent, stores no cookies and retries transient failures up to three times. A narrow filter can still take a while, because the actor has to check every nonmatching market along the way, so use date filters and resume cursors for larger exports. Run `npm test` from the repository root to check winner evidence, history windows, filter behavior and billing stops, including pagination across repeated runs.

# Actor input Schema

## `category` (type: `string`):

Exact category or tag ID, label or slug, case-insensitive. For example politics. No inferred categories.

## `tags` (type: `array`):

All supplied tag IDs, labels or slugs must match. Case-insensitive; up to 20.

## `startDate` (type: `string`):

Include markets whose scheduled endDate is on or after this ISO timestamp. A date alone means midnight UTC. This is not the resolution date.

## `endDate` (type: `string`):

Inclusive upper bound on scheduled endDate. Use 23:59:59Z to include a whole last day.

## `historyStart` (type: `string`):

Optional ISO timestamp. Set historyEnd too. The window may be at most 366 days. Omit both to request all samples currently exposed by CLOB.

## `historyEnd` (type: `string`):

Optional inclusive ISO timestamp; used with historyStart.

## `resolvedOnly` (type: `boolean`):

Require a closed CLOB market with one winner, or Gamma resolved status and exact terminal 0/1 prices. Closed alone is insufficient.

## `fidelityMinutes` (type: `integer`):

Sampling fidelity requested from CLOB, 1 to 1440 minutes. API gaps and empty history are reported.

## `maxMarkets` (type: `integer`):

Stop after this many matching markets. OUTPUT.resumeCursor continues at the next source page.

## `maxPages` (type: `integer`):

Bound source scanning when filters are selective. Page-limit results are incomplete and include a resume cursor.

## `pageSize` (type: `integer`):

Maximum Gamma markets per keyset request. Pages shrink to the remaining export budget, so stopping cannot skip part of a page.

## `resumeCursor` (type: `string`):

Copy OUTPUT.resumeCursor or CHECKPOINT.resumeCursor from an earlier run. Keep filters and fidelity unchanged. maxMarkets and maxPages may change.

## Actor input object example

```json
{
  "tags": [],
  "resolvedOnly": false,
  "fidelityMinutes": 60,
  "maxMarkets": 100,
  "maxPages": 100,
  "pageSize": 100
}
```

# Actor output Schema

## `markets` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `checkpoint` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("omraydev/polymarket-markets-history").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("omraydev/polymarket-markets-history").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call omraydev/polymarket-markets-history --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,omraydev/polymarket-markets-history"
        }
    }
}
```

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/4QUHPBlqqBgzVyjnG/builds/ybof0oSGm9GXIWlUy/openapi.json
