If you want Polymarket price history in a notebook or CSV, you do not need a paid data vendor to get started. Polymarket documents a public /prices-history endpoint on the CLOB API — no API key, no signup. This article shows how to download Polymarket historical prices with Python using that official path first, then when a hosted archive is worth considering.
That order matters. Many researchers only need implied-probability time series for charts or signal work. Others eventually need unified Polymarket price data alongside metrics or historical L2 depth. We will cover both — without skipping the free option.
What Polymarket price history actually is
Each Polymarket outcome trades as a token on the CLOB. Historical prices are stored per token ID (the asset id in Polymarket's docs), not per market slug. A binary market has two series — typically YES and NO — and each point is a timestamp t plus an implied probability p between 0 and 1.
This is Polymarket price data suited to time-series analysis: repricing before events, correlation across markets, coarse backtests. It is not the same as an archived order book — you get a price line, not bid/ask ladders with size at each level.
Step 1: resolve token IDs with the Gamma API
The CLOB /prices-history endpoint requires a token ID. The Gamma API exposes market metadata, including clobTokenIds — a JSON-encoded array of outcome token IDs for each market.
Typical flow: search or list markets on Gamma, pick one, parse clobTokenIds, then pass the YES (or NO) token id to /prices-history. Polymarket's prices and order books docs walk through the same pattern in more detail.
Step 2: download history from Polymarket's CLOB API
The documented endpoint is GET https://clob.polymarket.com/prices-history. Important parameters:
- market (required) — outcome token ID.
-
interval — relative window such as
1h,1d,1w, ormax. Mutually exclusive with an absolute range. - startTs / endTs — Unix timestamps for a fixed window (use these when you need a specific date range).
- fidelity — sampling interval in minutes (default 1). Higher fidelity means more points.
The response shape is {"history": [{"t": ..., "p": ...}, ...]}. Public access — Polymarket applies IP-based rate limits and throttling, so pace bulk downloads and design for backoff rather than hammering the API.
Python example: official Polymarket price history
This script uses only Polymarket's public Gamma + CLOB APIs. Install requests if you need it (pip install requests).
import json
import time
from datetime import datetime, timezone
import requests
GAMMA = "https://gamma-api.polymarket.com"
CLOB = "https://clob.polymarket.com"
# 1. Resolve a market and its outcome token IDs (Gamma — public, no API key)
markets = requests.get(
f"{GAMMA}/markets",
params={"limit": 5, "active": True, "closed": False},
timeout=60,
)
markets.raise_for_status()
market = markets.json()[0]
token_ids = json.loads(market["clobTokenIds"])
yes_token_id = token_ids[0]
print(market["question"])
print("YES token:", yes_token_id[:12], "...")
# 2. Pull Polymarket price history (CLOB /prices-history — public, no API key)
history = requests.get(
f"{CLOB}/prices-history",
params={
"market": yes_token_id,
"interval": "1w", # or use startTs + endTs for an absolute window
"fidelity": 60, # minutes between points
},
timeout=60,
)
history.raise_for_status()
points = history.json().get("history", [])
for point in points[:5]:
ts = datetime.fromtimestamp(point["t"], tz=timezone.utc).isoformat()
print(ts, "implied prob", point["p"])
# 3. Export to CSV (polymarket price data download)
# with open("prices.csv", "w") as f:
# f.write("timestamp,price\n")
# for point in points:
# f.write(f"{point['t']},{point['p']}\n")
time.sleep(0.2) # pace yourself — IP-based rate limits apply
Practical tips:
- For long windows at fine
fidelity, chunk withstartTs/endTsinstead of relying oninterval=maxalone — community reports suggest very fine granularity on resolved markets can return sparse data unless you bound the range explicitly. - Loop one request per outcome token (YES and NO) if you need both sides.
- Add a short
sleepbetween markets when downloading many series — respect documented rate limits.
When the official API is enough
Stay on Polymarket's /prices-history when:
- You are exploring one market or a small set of markets.
- You need implied probability over time, not full book depth.
- You are fine resolving token IDs through Gamma yourself.
- Hourly or daily fidelity is sufficient for the question.
For many charting and research tasks, that is the right stopping point — and it costs nothing beyond your time.
When a historical archive helps
A third-party archive (or your own recorder) becomes useful when Polymarket historical data needs to look like a product API rather than a script that stitches Gamma + CLOB:
-
Unified queries — discover markets by slug and pull
/prices,/metrics, or/bookson the samestart_ts/end_tswindow without token-id plumbing each time. - Both outcomes in one response — archive APIs often key price series by outcome label (YES / NO) for a market slug.
- Historical L2 order books — if price history stops being enough and you need bid/ask ladders, see How to Get Historical Polymarket Order Book Data for Backtesting.
- Bulk polymarket data download — warehouse exports (Parquet, CSV) or scheduled pulls across hundreds of markets.
For the broader map of prices vs trades vs books vs API access, see Polymarket Historical Data: Prices, Trades, Order Books, and API Access.
Optional: same window through an archive API
If you already use a hosted historical API, the shape is similar — market discovery, then a prices route — but keyed by slug and paginated. Example with PolyOrderbooks (requires a free API key from the dashboard):
import os
from datetime import datetime, timedelta, timezone
import requests
BASE = "https://api.polyorderbooks.com"
HEADERS = {"X-API-Key": os.environ["POLYORDERBOOKS_API_KEY"]}
markets = requests.get(
f"{BASE}/v1/markets",
params={"search": "bitcoin", "limit": 1, "status": "active"},
headers=HEADERS,
timeout=60,
)
markets.raise_for_status()
slug = markets.json()["data"][0]["slug"]
end = datetime.now(timezone.utc)
start = end - timedelta(days=7)
prices = requests.get(
f"{BASE}/v1/markets/{slug}/prices",
params={
"start_ts": start.isoformat().replace("+00:00", "Z"),
"end_ts": end.isoformat().replace("+00:00", "Z"),
"resolution": "60s",
"limit": 500,
},
headers=HEADERS,
timeout=120,
)
prices.raise_for_status()
for outcome, series in prices.json()["data"].items():
print(outcome, len(series), "points")
This is optional. Start with Polymarket's official endpoint; move here when unified history, metrics, or book depth justify it. Docs: quickstart and historical overview.
Summary
Polymarket price history is available today through documented public APIs: resolve token IDs on Gamma, call /prices-history on the CLOB, export the series. That covers a large share of polymarket historical prices and polymarket price data use cases with no vendor lock-in.
Reach for an archive when you need one interface for prices, metrics, and stored L2 books — or when IP limits and multi-market orchestration become the bottleneck. Either way, you are downloading real market history, not guessing from live quotes alone.
Originally published on PolyOrderbooks.
Top comments (0)