# OpenAI API Pricing Scraper (`axiomworks/openai-pricing-scraper`) Actor

Collects pricing tables from OpenAI’s public API documentation and returns records with model labels, sections, tiers, and available price fields. Includes input, cached input, output, and long-context rates; non-token prices are retained as notes instead of being converted.

- **URL**: https://apify.com/axiomworks/openai-pricing-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.98 / 1,000 results

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

## OpenAI Pricing Scraper

**Returns:** one row per model price with model, tier, inputPer1M, cachedInputPer1M, outputPer1M, blendedPer1M, cachedDiscountPct, sourceUrl.
**Input:** `{"sections": ["Flagship models"], "tiers": ["Standard"], "maxItems": 20}`
**Best for:** LLM cost tables, OpenAI price-change monitoring, budgeting and model-routing tools.

```json
{
  "model": "gpt-6-astra",
  "tier": "Standard",
  "inputPer1M": 10,
  "cachedInputPer1M": 1,
  "outputPer1M": 50,
  "blendedPer1M": 20,
  "sourceUrl": "https://developers.openai.com/api/docs/pricing.md"
}
```

### What does OpenAI Pricing Scraper do?

OpenAI Pricing Scraper reads the public OpenAI API pricing page and turns every price table into clean, structured records. Each record is one row of one table: a model, a processing tier and the prices that the page lists for it. You get the input price, the cached input price, the output price and, where the page lists them, the long-context rates and cache write price. Prices are returned as numbers in US dollars per 1M tokens, so you can load them straight into a spreadsheet, a database or a cost calculator without any manual cleanup.

The Actor reads the Markdown version of the pricing page. That is a single request, which makes a run fast and cheap and puts almost no load on the site. The parser does not depend on fixed column positions. It tracks the section headings (such as Flagship models or Finetuning) and the tier headings (Standard, Batch, Flex, Fast, Ultrafast), and it maps every column by the name in the table header. When the page adds a column or a model, the Actor picks it up. If no table can be parsed, the run succeeds with zero records and a status message asking you to report the changed source page. No error records are saved.

Typical uses:

- Loading current model prices into an internal cost table from the numeric price fields.
- Tracking price changes between runs by comparing the dataset of today with the dataset of last week.
- Feeding a budgeting or routing tool that needs the current price per 1M tokens of each model.
- Comparing the Standard and Batch tiers of the same model side by side.
- Building a dashboard of model prices for a team that uses several OpenAI models.

This Actor is not affiliated with or endorsed by OpenAI. It reads a public page that needs no login.

### What data can you get?

Every record has the fields below. Fields that a table does not contain are returned as null. For example, the Finetuning tables have a training price but no long-context columns, and the realtime tables have a modality column but no tier.

| Field | Type | Description |
| --- | --- | --- |
| id | string | Stable 16-character hash of section, tier, model label, modality and category. No duplicates in a run. |
| section | string | Pricing page section, for example Flagship models or Finetuning. |
| tier | string | Standard, Batch, Flex, Fast or Ultrafast. Null for tables without tiers. |
| model | string | Model name with context-length suffixes removed. |
| modelLabel | string | Model name exactly as printed on the page. |
| category | string | Category or use case column, used by the Specialized and Transcription tables. |
| modality | string | Modality column (Audio, Text, Image) for realtime and image tables. |
| inputPer1M | number | Input price in USD per 1M tokens. |
| cachedInputPer1M | number | Cached input price in USD per 1M tokens. |
| cacheWritePer1M | number | Cache write price in USD per 1M tokens, when listed. |
| outputPer1M | number | Output price in USD per 1M tokens. |
| longContextInputPer1M | number | Input price per 1M tokens above the long-context threshold. |
| longContextOutputPer1M | number | Output price per 1M tokens above the long-context threshold. |
| longContextCachedInputPer1M | number | Cached input rate per 1M tokens above the long-context threshold; null when absent. |
| longContextCacheWritePer1M | number | Cache write rate per 1M tokens above the long-context threshold; null when absent. |
| blendedPer1M | number | Input and output price blended at a 3:1 input:output token mix, USD per 1M tokens. Null if either price is missing. |
| cachedDiscountPct | number | Percent saved by cached input versus regular input. |
| changeStatus | string | Only with trackChanges: baseline, new, changed or unchanged versus the previous tracked run. |
| previousInputPer1M | number | Only with trackChanges: input price in the previous tracked run. |
| previousOutputPer1M | number | Only with trackChanges: output price in the previous tracked run. |
| training | string | Fine-tuning training price as printed, for example per hour. |
| unitPrice | number | Price per `priceUnit` for rows not priced per 1M tokens (for example 0.006 per minute). Null for token-priced rows. |
| priceUnit | string | Unit of `unitPrice`, such as `minute` or `1M characters`. |
| priceNote | string | Raw text of price cells that are not plain per-1M-token numbers, such as per minute or per character prices. |
| currency | string | Currency of all prices, always USD. |
| sourceUrl | string | The page the record was parsed from. |
| scrapedAt | string | ISO timestamp of the run. |

Long-context cached input and cache write columns are returned separately from short-context rates. Only the seven selectable sections are extracted; tables in other sections, including Life sciences models, are excluded rather than assigned to the preceding section.

A dash on the page means the model has no such price, and the matching field is null. The word Free is returned as 0. Prices that are not per 1M tokens (per minute, per character, per hour) are never forced into the per-1M fields. The number and unit are also given in `unitPrice` and `priceUnit`, and the original text is kept in `priceNote` or `training` so no information is lost.

### How to use

1. Open the Actor in Apify Console and go to the Input tab.
2. Pick one or more sections. The default is all sections.
3. Optionally pick tiers, for example Standard and Batch, or leave the list empty to get all tiers.
4. Optionally type a model filter such as `gpt-5` or a regular expression such as `^gpt-4o`.
5. Set the maximum number of records and start the run.
6. Open the Output tab or download the dataset as JSON, CSV, Excel or XML.

A run finishes in a few seconds because it needs one request. You can schedule it daily or weekly and compare datasets over time to see price changes.

If your filters match nothing, the run ends successfully with zero items. The final status tells you to clear modelFilter or set sections and tiers to empty lists. If requests stay blocked after bounded retries, the status asks you to retry later or enable Apify Proxy. No placeholder records are written.

### Input

The optional `trackChanges` boolean (default false) stores each run's prices in a named key-value store. Set `changeStoreName` to keep separate histories for independent scheduled jobs; its default, `openai-pricing-previous`, preserves the existing history. Reusing a name shares that baseline across runs, so choose a different name when jobs should not affect each other. The first tracked run in a fresh store establishes a baseline. The next run with `trackChanges` set to true marks every row as new, changed or unchanged and adds the previous input and output prices.

| Field | Type | Description |
| --- | --- | --- |
| sections | array | Sections to extract: Flagship models, Cyber models, Realtime and audio generation models, Image generation models, Transcription models, Specialized models, Finetuning. Default: all sections. |
| tiers | array | Tiers to keep: Standard, Batch, Flex, Fast, Ultrafast. Empty means all. Tables without tier headings list one standard price, so they match Standard and are returned with a null tier. |
| modelFilter | string | Case-insensitive substring or regular expression matched against the model name. |
| modalities | array of strings | Exact source modality names, case-insensitive; empty includes all. A selection excludes null modality rows. |
| sortBy | string | source (default), model, inputPer1M, outputPer1M, blendedPer1M or cachedInputPer1M. Ascending, null values last; applied before maxItems. |
| models | array of strings | Exact model IDs or full model labels, matched without case sensitivity. Empty includes all models. |
| changeStoreName | string | History store used with trackChanges. Defaults to openai-pricing-previous. |
| maxItems | integer | Maximum total records across sections, tiers and model matches, 1 to 1000. Default 250. The Actor never returns more. |
| trackChanges | boolean | Compare with the previous tracked run and add changeStatus. Default false. |
| proxyConfiguration | object | Proxy settings. The default is no proxy because the page loads without one. Enable Apify Proxy if your requests get blocked. |

Example input:

```json
{
  "sections": ["Flagship models", "Finetuning"],
  "tiers": ["Standard", "Batch"],
  "modelFilter": "gpt-4",
  "maxItems": 40
}
```

For exact selection, use `models: ["gpt-6-astra"]`. This compares complete model IDs or complete `modelLabel` values without case sensitivity, so a short name cannot accidentally include similarly named models. Keep `models` empty for discovery, then copy IDs from the returned `model` field. Exact selection combines with the section, tier and regular expression filters: a row must satisfy every active filter. Unknown IDs return zero rows successfully. Clear `models` as well as `modelFilter` when broadening an empty search. This option uses the same public pricing document and does not add network requests.

For modality-specific comparisons, set `modalities` to `["Audio"]` or `["Text"]` and select the relevant realtime or image section. Values match the source modality exactly, ignoring case. A row without a modality is excluded when this filter is active, so a flagship text model with a null modality will not match `Text`. Empty lists retain the existing behavior and include all rows. The filter combines with every other selection; it does not infer a modality from the model name.

Use `sortBy: "inputPer1M"` or `sortBy: "outputPer1M"` to select the cheapest matching token rates before applying `maxItems`. Numeric sorting is ascending and puts missing prices last. `blendedPer1M` uses the existing fixed 3:1 input-to-output mix; it is not a personalized workload estimate. `cachedInputPer1M` helps compare listed cache-hit rates. `model` sorts names alphabetically, while the default `source` keeps the original page order. Sorting does not change the fields, prices, record IDs or network request count. Ties keep their source order. Non-token unit prices remain separate and are not compared with per-token prices.

### Output

Each dataset item is one price row. Example item from the Flagship models section, Standard tier:

```json
{
  "id": "67e58a240804cab4",
  "section": "Flagship models",
  "tier": "Standard",
  "model": "gpt-6-astra",
  "modelLabel": "gpt-6-astra",
  "category": null,
  "modality": null,
  "inputPer1M": 10,
  "cachedInputPer1M": 1,
  "cacheWritePer1M": 12.5,
  "outputPer1M": 50,
  "longContextInputPer1M": 20,
  "longContextOutputPer1M": 75,
  "blendedPer1M": 20,
  "cachedDiscountPct": 90,
  "changeStatus": null,
  "previousInputPer1M": null,
  "previousOutputPer1M": null,
  "training": null,
  "priceNote": null,
  "unitPrice": null,
  "priceUnit": null,
  "currency": "USD",
  "sourceUrl": "https://developers.openai.com/api/docs/pricing.md",
  "scrapedAt": "2026-10-13T02:36:13.787Z"
}
```

An item from a model that has a context-length note on the page keeps the raw text in `modelLabel` and the cleaned name in `model`:

```json
{
  "section": "Flagship models",
  "tier": "Standard",
  "model": "gpt-5.5",
  "modelLabel": "gpt-5.5 (<272K context length)",
  "inputPer1M": 5,
  "cachedInputPer1M": 0.5,
  "outputPer1M": 30,
  "longContextInputPer1M": 10,
  "longContextOutputPer1M": 45
}
```

The dataset has an Overview view that shows the most useful columns: section, tier, model, modality, the input, cached input and output prices, the long-context prices, currency, source URL and scrape time.

### How much does it cost?

The Actor is charged per result, which means per price record in the dataset. A typical run with the default settings returns a few dozen records. See the Pricing tab of the Actor for the current rate. Because the Actor makes one request per run, the platform usage of a run is very small. You control the total cost with the `maxItems` input: the Actor stops exactly at that number and never charges for more.

### Use with AI agents (MCP)

You can call this Actor from any MCP-compatible assistant through the Apify MCP server. Add the Actor to your client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=axiomworks/openai-pricing-scraper"
    }
  }
}
```

Example prompts:

- "Get the Standard and Batch prices of the flagship OpenAI models and tell me which has the cheapest output price per 1M tokens."
- "List the image generation models and their input and output prices."
- "Which fine-tunable models have a training price listed, and what is it?"
- "Find all models whose name contains gpt-5 and compare their cached input prices."

### Integrations and API

You can start the Actor from code, from a schedule or from automation tools such as Make, Zapier or n8n, and read the dataset through the Apify API.

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("axiomworks/openai-pricing-scraper").call(run_input={
    "sections": ["Flagship models"],
    "tiers": ["Standard"],
    "maxItems": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["model"], item["inputPer1M"], item["outputPer1M"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('axiomworks/openai-pricing-scraper').call({
    sections: ['Flagship models'],
    tiers: ['Standard'],
    maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => process.stdout.write(`${item.model} ${item.inputPer1M}\n`));
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~openai-pricing-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sections": ["Flagship models"], "tiers": ["Standard"], "maxItems": 20}'
```

### FAQ

**Which models are included?**
Every model that appears in a table of the selected sections on the pricing page at the time of the run. That includes models that are listed but not yet widely available, because the Actor reports what the page shows.

**Why are some price fields null?**
Either the page shows a dash for that model, or the table has no such column. Long-context prices only exist for some flagship models, and Finetuning tables have a training price instead.

**What does priceNote contain?**
Some rows, such as transcription by the minute or text to speech by the character, are not priced per 1M tokens. The raw text of those cells is kept in `priceNote` so you can still use it.

**Why does a model appear several times?**
The same model can have several rows: one per tier (Standard, Batch and so on) and, for image and realtime models, one per modality. Use the `tier` and `modality` fields to tell them apart.

**Why do I get no results when I pick a tier?**
Tables without tier headings have a null tier. They match Standard, and they are also included when the tier list is empty. Clear tiers to include every table in your selected sections.

**How up to date is the data?**
The Actor reads the live page on every run. `scrapedAt` tells you when that happened.

**What happens if the page layout changes?**
Columns are matched by header name, so added columns and models are handled. If no table can be parsed at all, the run succeeds with zero records and a status message asking you to report the page layout change.

**Does it need a proxy?**
No. The page is public and loads without one. A proxy option is available if you run into blocks.

### Is it legal to scrape OpenAI pricing?

The Actor reads one public page that needs no login and contains no personal data. It sends a single request per run, which keeps the load on the site minimal. Prices are factual information. You remain responsible for how you use the data, and you should check the terms of the site and the rules that apply to you. This Actor is an independent tool and is not affiliated with OpenAI. Nothing here is legal advice.

### Feedback

If a table is parsed wrongly, a section is missing or you need an extra field, open an issue from the Actor page in Apify Console, including the section and model concerned. Reports with an example row from the pricing page are the fastest to fix.

# Actor input Schema

## `sections` (type: `array`):

Sections to include, e.g. \["Flagship models", "Finetuning"]. Choose the listed section names; an empty list or omitted field includes all sections. Filters combine with tiers and modelFilter. The prefill selects Flagship models.

## `tiers` (type: `array`):

Tiers to include, e.g. \["Standard", "Batch"]. Choose Standard, Batch, Flex, Fast or Ultrafast. Empty or omitted includes all tiers. Tables without tier headings match Standard but retain tier: null in output. Applies within sections.

## `modelFilter` (type: `string`):

Case-insensitive model-name filter, e.g. "gpt-5" or "^gpt-4o". Matches model and modelLabel as a regular expression; invalid regex is treated as literal text. Empty or omitted keeps all models. If no rows match, the run succeeds with zero items; clear or broaden this filter.

## `trackChanges` (type: `boolean`):

Set true to compare returned rows with the previous tracked run, e.g. true. Default false leaves change fields null. Uses changeStoreName (default openai-pricing-previous); baseline is the first tracked run, then new, changed or unchanged. Compares inputPer1M and outputPer1M only.

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

Total result limit across all selected sections, tiers and models, e.g. 20. Use 1-1000; default 250. Stops at this shared limit or when matching rows run out. Use 1 for a small sample; each row is a separately charged result.

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

Proxy configuration object, e.g. {"useApifyProxy": false}. Default uses no proxy. Set {"useApifyProxy": true} to retry through Apify Proxy if the public page is blocked. A source that stays unavailable returns zero items with a status message; retry later or check proxy settings.

## `models` (type: `array`):

Exact model IDs or full model labels to include, e.g. \["gpt-6-astra"]. Case-insensitive; empty or omitted includes all models. Combines with sections, tiers and modelFilter. Unknown IDs produce zero results; use an empty list to discover current IDs.

## `changeStoreName` (type: `string`):

Named key-value store for trackChanges, default openai-pricing-previous. Keep the name stable across scheduled runs; use different names for independent monitoring jobs. Ignored when trackChanges is false. Changing the name starts a new baseline.

## `modalities` (type: `array`):

Exact modality values from the source, e.g. \["Audio", "Text"]. Case-insensitive; empty (default) includes all rows, including rows with modality null. Nonempty excludes null modalities. Combines with sections, tiers and model filters; no matches succeeds with zero items.

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

Order matching rows before maxItems is applied. Default source preserves page order. Model sorts alphabetically; numeric options sort ascending with null values last. Use inputPer1M, outputPer1M or blendedPer1M to return the cheapest matching token-price rows first.

## Actor input object example

```json
{
  "sections": [
    "Flagship models"
  ],
  "tiers": [
    "Standard"
  ],
  "modelFilter": "",
  "trackChanges": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "models": [],
  "changeStoreName": "openai-pricing-previous",
  "modalities": [],
  "sortBy": "source"
}
```

# 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 = {
    "sections": [
        "Flagship models"
    ],
    "tiers": [
        "Standard"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/openai-pricing-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 = {
    "sections": ["Flagship models"],
    "tiers": ["Standard"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/openai-pricing-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 '{
  "sections": [
    "Flagship models"
  ],
  "tiers": [
    "Standard"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call axiomworks/openai-pricing-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/openai-pricing-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/Dr10HrDg302Bcj0S9/builds/FaqnJhw6Vpe2kiyKS/openapi.json
