# Polymarket Historical Snapshots & Delisting Tracker (`fetchfinch/polymarket-historical-snapshot-exporter`) Actor

Capture recurring Polymarket snapshots with canonical IDs, changes, lifecycle events, conservative delisting detection, and research-ready history.

- **URL**: https://apify.com/fetchfinch/polymarket-historical-snapshot-exporter.md
- **Developed by:** [Fetch Finch](https://apify.com/fetchfinch) (community)
- **Categories:** Developer tools, Automation, News
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 market snapshots

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Polymarket Historical Snapshot Exporter

Create reliable, research-ready Polymarket history from recurring market snapshots.

This Actor collects normalized market data from Polymarket's public Gamma and CLOB APIs. It tracks listings, metadata changes, prices, volume, liquidity, lifecycle events, disappearances, and relistings across runs.

Use it to:

- Build a historical market catalog from the time you start collecting
- Monitor a focused watchlist or the full active market inventory
- Detect question, deadline, outcome, token, and resolution-rule changes
- Track new listings, closures, suspected disappearances, confirmed delistings, and relistings
- Generate semantic alerts for price, volume, liquidity, metadata, and lifecycle changes
- Export consistent records for databases, notebooks, dashboards, and data warehouses

No Polymarket account, wallet, browser, proxy, or API key is required.

### What makes this Actor reliable

A current-market export is not a historical dataset. Polymarket price history also does not reconstruct past liquidity, volume, metadata, market membership, order status, or resolution rules.

This Actor records those values as they are observed on every run. It also includes safeguards designed to keep the resulting history suitable for research:

- Stable event, market, and outcome identifiers
- CLOB token IDs preserved as strings without precision loss
- Typed and normalized prices, outcomes, volume, liquidity, dates, tags, and event references
- Persistent history shared across runs with the same monitor
- Deterministic record IDs for downstream deduplication
- A completeness and quality manifest for every run
- Direct verification before a missing market advances toward delisted status
- Configurable multi-run delisting confirmation
- Separate closed, archived, out-of-scope, and delisted states
- No disappearance confirmation or market alerts from incomplete snapshots

### Quick start

#### Monitor a watchlist

Use condition IDs whenever possible because they are the stable market identifiers.

```json
{
  "monitorKey": "research-watchlist",
  "status": "all",
  "conditionIds": [
    "0x1234..."
  ],
  "outputMode": "full_and_changes",
  "persistHistory": true,
  "emitAlertRecords": true
}
```

#### Collect all active markets

```json
{
  "monitorKey": "all-active-hourly",
  "status": "active",
  "maxMarkets": 0,
  "persistHistory": true,
  "missingConfirmationRuns": 3,
  "emitAlertRecords": true
}
```

One run produces a complete point-in-time snapshot. To build history or detect changes, save the input as an Apify Task and add a recurring schedule.

### Recurring collection

A schedule is required only when you want ongoing history, delisting detection, or alerts. It is not required for a one-time export.

Recommended starting cadences:

| Use case | Suggested cadence |
|---|---|
| Small, time-sensitive watchlist | Every 5 to 15 minutes |
| Broad active-market catalog | Every 30 to 60 minutes |
| General research archive | Every 6 to 24 hours |
| Closed-market inventory | Daily |

For consistent history:

1. Save the Actor input as an Apify Task.
2. Attach an exclusive schedule so runs do not overlap.
3. Keep the same `monitorKey` for the same logical monitor.
4. Keep scope inputs stable unless you intentionally want a new comparison scope.
5. Review the `run_manifest` record to confirm that each snapshot was complete and committed.

Collection begins with the first successful run. A later schedule cannot reconstruct full snapshots from before that time. Optional CLOB price backfill is available for historical outcome prices, but it is clearly labeled and is not treated as a historical full-market snapshot.

### Stable identifiers

Polymarket's data model is event to market to outcome token. Slugs are useful aliases, but they can change and are not used as primary keys.

| Entity | Canonical key | Source identifier |
|---|---|---|
| Event | `polymarket:event:<gamma_event_id>` | Gamma event ID |
| Market | `polymarket:condition:<lowercase_condition_id>` | Condition ID |
| Outcome | `polymarket:token:<clob_token_id>` | CLOB token ID |

Every market snapshot also includes the Gamma market ID, condition ID, question ID, slug, event references, tags, and outcome-token mappings.

### Output record types

Use `recordType` to select the records needed by your pipeline.

#### `market_snapshot`

One normalized market at one observation time. It includes identifiers, contract metadata, lifecycle status, outcomes, prices, volume, liquidity, spread, important dates, event references, tags, and optional raw source data.

#### `market_change`

Emitted when tracked research fields differ from the preceding committed observation.

```json
{
  "recordType": "market_change",
  "marketKey": "polymarket:condition:0x...",
  "changedFields": ["description", "endDate", "outcomes"],
  "changes": [
    {
      "field": "endDate",
      "previous": "2026-08-30T00:00:00Z",
      "current": "2026-09-15T00:00:00Z"
    }
  ]
}
```

Source timestamp churn and unmodeled raw-payload changes do not create research changes.

#### `lifecycle_event`

Lifecycle events include:

- `NEW_MARKET`
- `MARKET_MISSING_SUSPECTED`
- `MARKET_DELISTED_CONFIRMED`
- `MARKET_RELISTED`
- `MARKET_OUT_OF_SCOPE`
- `MARKET_STATUS_CHANGED`

#### `alert`

Semantic alert records can report:

- New listings, status changes, suspected or confirmed disappearance, and relisting
- Outcome price moves
- Total-volume increases
- Liquidity drops
- Contract metadata and resolution-rule changes
- Incomplete-run health warnings

Thresholds are configurable. Alerts for the initial snapshot are suppressed by default to prevent a notification flood.

#### `price_history`

Optional first-seen price backfill from Polymarket's public CLOB endpoint. Each record contains the returned series for one outcome token. It is identified separately from observed full-market snapshots.

#### `run_manifest`

The final record reports the scope, sequence, completeness, state-commit status, history dataset, pagination counts, upstream requests, retries, missing candidates, output counts, billing-event counts, warnings, and errors.

### Delisting detection

Absence from one API response is not enough to call a market delisted.

When a previously tracked market is missing from an otherwise complete scan, the Actor checks that market directly using its Gamma market ID:

1. If the market still exists and matches the scope, the run is marked incomplete.
2. If it exists but no longer matches the configured status or filters, it becomes `out_of_scope`, not delisted.
3. If the direct lookup returns 404, the Actor emits `MARKET_MISSING_SUSPECTED` and advances the consecutive-missing counter.
4. After the configured number of complete, directly verified missing runs, it emits `MARKET_DELISTED_CONFIRMED`.
5. If the market later returns, it emits `MARKET_RELISTED`.

Capped and incomplete scans never advance delisting state. `maxMarkets` is useful for previews, but a truncated broad scan cannot establish that a market disappeared.

### Persistent history

With `persistHistory` enabled, the Actor appends the complete event stream to a named dataset:

```text
polymarket-history-<monitorKey>
```

Use `historyDatasetName` to choose another name. The default dataset for the current run follows `outputMode`, while the named history dataset keeps the complete records needed for longitudinal analysis.

Changing scope-defining inputs produces a new `scopeHash` and independent comparison state. This prevents a narrower or different query from creating false disappearances.

Dataset delivery is at-least-once. If a run stops after writing data but before committing state, a retry can repeat an observation. Use `recordId` or `observationId` to deduplicate downstream.

### Alerts and webhooks

Alerts are always available as dataset records when `emitAlertRecords` is enabled. Set `alertWebhookUrl` to receive one batched JSON POST after snapshot data and state have been committed.

```json
{
  "monitorKey": "politics-alerts",
  "status": "active",
  "tagIds": ["2"],
  "priceMoveThreshold": 0.05,
  "volumeDeltaThreshold": 25000,
  "liquidityDropPctThreshold": 0.5,
  "alertWebhookUrl": "https://example.com/polymarket-alerts"
}
```

The generic webhook can connect to automation tools, messaging adapters, databases, or internal services. By default, a webhook failure is logged without invalidating research data that was already committed. Enable `failOnAlertDeliveryError` if delivery failure should fail the run.

### Billing units

The Actor uses transparent pay-per-event billing:

- `market-snapshot` is charged once for each market that is observed, normalized, compared, and delivered according to the selected output settings.
- `price-history-series` is charged once for each successfully saved CLOB outcome-token price-history series.
- Change records, lifecycle events, semantic alerts, run manifests, and webhook delivery do not add separate event charges.
- `outputMode` changes where records appear, but it does not change how many markets the Actor processes.

Customers can set a maximum charge for each run. Before processing market observations, the Actor checks how many events fit within the remaining budget. If the budget cannot cover the complete selected market scope, it returns a partial snapshot with `snapshotComplete: false` and does not commit comparison state or advance delisting counters. Optional price-history backfill stops separately when its event budget is exhausted, without invalidating an otherwise complete market snapshot.

The `billing` object in every `run_manifest` reports the pricing model, whether the charge limit was reached, and the delivered and charged counts for each custom event.

### Filters and input behavior

- Exact market IDs, condition IDs, and slugs use OR semantics.
- Multiple tag IDs use OR semantics.
- Multiple search strings use OR semantics.
- Search, volume, and liquidity filters are applied after retrieval.
- Slugs are accepted for convenience but stored only as aliases.
- `includeRaw` can substantially increase storage usage and should normally remain disabled.
- Use a new `monitorKey` for a logically different monitor.
- Use an exclusive schedule to avoid overlapping runs.

### Important limitations

- The Actor records public upstream observations, not exchange-certified timestamps.
- `observedAt` is the Actor observation time. `sourceUpdatedAt` is Polymarket's source timestamp when available.
- Full snapshot history starts with the first successful collection run.
- Capped and incomplete runs remain visible with quality flags but do not become committed comparison state.
- Public APIs and upstream schemas can change. Automated pipelines should inspect `run_manifest.errors`, `run_manifest.warnings`, and `schemaVersion`.
- This Actor is an independent data tool. It is not affiliated with Polymarket, does not place trades, and does not provide financial advice.

### Data schema version

Current schema version: `1.0.0`.

Backward-compatible additions retain the major version. Breaking field or semantic changes require a new major version.

# Actor input Schema

## `monitorKey` (type: `string`):

Stable name for this monitor. Runs with the same key and scope share history and state.

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

Active scans open markets, closed scans closed markets, and all performs both complete scans.

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

Optional exact Gamma market IDs. Exact selectors are combined with OR semantics.

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

Optional exact condition IDs. This is the recommended stable market selector.

## `slugs` (type: `array`):

Optional market URL slugs. Slugs are treated as aliases, not canonical identifiers.

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

Optional Gamma tag IDs. Multiple tags use OR semantics.

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

Optional case-insensitive text filters over question, description, slug, event titles, and tags. Multiple values use OR semantics.

## `minVolume` (type: `number`):

Local filter in USD. Markets falling below it are out of scope, never called delisted.

## `minLiquidity` (type: `number`):

Local filter in USD. Markets falling below it are out of scope, never called delisted.

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

Safety cap. Zero means unlimited. A capped run is marked incomplete and cannot confirm disappearances.

## `outputMode` (type: `string`):

The persistent history dataset always receives full snapshots. This controls the current run dataset.

## `persistHistory` (type: `boolean`):

Append full records to a named dataset shared across runs.

## `historyDatasetName` (type: `string`):

Optional named dataset. Defaults to polymarket-history-<monitorKey>.

## `includeRaw` (type: `boolean`):

Preserve the complete upstream market object in every snapshot. This substantially increases storage.

## `missingConfirmationRuns` (type: `integer`):

Number of consecutive complete runs with a direct 404 needed before MARKET\_DELISTED\_CONFIRMED.

## `backfillPriceHistory` (type: `boolean`):

Fetch official CLOB price history the first time each market is observed.

## `historyInterval` (type: `string`):

Lookback interval requested from the official CLOB price-history endpoint.

## `historyFidelityMinutes` (type: `integer`):

Requested spacing between backfilled price observations.

## `maxHistoryMarkets` (type: `integer`):

Limits first-seen markets whose outcome price history is fetched in one run.

## `emitAlertRecords` (type: `boolean`):

Write alert rows derived from lifecycle, price, volume, liquidity, metadata, and run-health changes.

## `alertOnInitialSnapshot` (type: `boolean`):

Usually leave this off to avoid a flood during the first run.

## `priceMoveThreshold` (type: `number`):

Absolute probability move, where 0.05 means five percentage points.

## `volumeDeltaThreshold` (type: `number`):

Minimum increase in total USD volume between observations that emits VOLUME\_SPIKE.

## `liquidityDropPctThreshold` (type: `number`):

Fractional drop, where 0.5 means 50%.

## `alertWebhookUrl` (type: `string`):

Optional HTTP(S) endpoint that receives one batched semantic-alert POST after committed runs.

## `failOnAlertDeliveryError` (type: `boolean`):

If enabled, a failed semantic-alert webhook makes the Actor run fail after data and state are committed.

## `requestTimeoutSecs` (type: `integer`):

Timeout applied to individual Gamma and CLOB HTTP requests.

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

Retries for timeouts, rate limits, and transient upstream server errors.

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

Markets requested per Gamma pagination call.

## Actor input object example

```json
{
  "monitorKey": "default",
  "status": "active",
  "marketIds": [],
  "conditionIds": [],
  "slugs": [],
  "tagIds": [],
  "searchQueries": [],
  "minVolume": 0,
  "minLiquidity": 0,
  "maxMarkets": 0,
  "outputMode": "full_and_changes",
  "persistHistory": true,
  "includeRaw": false,
  "missingConfirmationRuns": 3,
  "backfillPriceHistory": false,
  "historyInterval": "max",
  "historyFidelityMinutes": 60,
  "maxHistoryMarkets": 25,
  "emitAlertRecords": true,
  "alertOnInitialSnapshot": false,
  "priceMoveThreshold": 0.05,
  "volumeDeltaThreshold": 10000,
  "liquidityDropPctThreshold": 0.5,
  "failOnAlertDeliveryError": false,
  "requestTimeoutSecs": 30,
  "maxRequestRetries": 4,
  "pageSize": 500
}
```

# Actor output Schema

## `results` (type: `string`):

All records emitted to this run's default dataset according to outputMode.

## `researchView` (type: `string`):

The run dataset with identifier, status, outcome, price, volume, liquidity, and timing fields selected.

## `runSummary` (type: `string`):

Machine-readable summary containing completeness, persistent history dataset ID, counts, billing events, and warnings.

# 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("fetchfinch/polymarket-historical-snapshot-exporter").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("fetchfinch/polymarket-historical-snapshot-exporter").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 fetchfinch/polymarket-historical-snapshot-exporter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetchfinch/polymarket-historical-snapshot-exporter"
        }
    }
}

```

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/OL3CwKwY9XvdJgFcD/builds/19HvEbIbdwBTuwL89/openapi.json
