# Steam Community Market Scraper - Prices, History & Order Books (`fanndev/steam-community-market-scraper`) Actor

Track the Steam Community Market economy for CS2, Dota 2, TF2, Rust and any Steam game: full price history back as far as 2014, live buy/sell order books, individual listings with float and pattern seed, catalogue search and a live feed of completed sales. No login needed.

- **URL**: https://apify.com/fanndev/steam-community-market-scraper.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 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

## Steam Community Market Scraper - Prices, History & Order Books

Track the in-game economy of the Steam Community Market: full price history going back as far as 2014, live buy and sell order books, individual listings with float and pattern seed, catalogue search across any game, and a live feed of completed sales. Works for CS2, Dota 2, TF2, Rust, Steam trading cards and every other game with a market. No Steam account, no login, no API key.

### Why use this actor

- **No Steam account required.** You get the complete price series as data, every day since an item was first sold plus hourly points for the last month. No login, no API key, no chart-reading.
- **The whole order book, not just the best price.** Every buy and sell price level with quantities and running depth. A popular case has thousands of levels on each side, enough for real liquidity and spread analysis.
- **Ready-made market statistics.** Each item comes with its bid/ask spread, 24-hour, 7-day, 30-day, 90-day and 1-year average price and units sold, all-time high and low (with dates), and the 7-day vs 30-day trend.
- **Float, pattern seed and stickers on every listing.** Sort a skin's listings by lowest float and stop at a float cap: the quickest way to find low-wear copies, specific patterns or sticker crafts.
- **Any currency.** Pick USD, EUR, GBP, IDR, BRL, or any of the 39 currencies Steam supports.
- **Clean, stable JSON** for spreadsheets, databases, dashboards and trading bots, with automatic retries and export to JSON, CSV or Excel.

### How it works

1. Choose what to collect: a catalogue search, item overviews, price history, order books, individual listings, or the recent sales feed.
2. List your items by name or paste their Steam market page URLs. Or leave the list empty and let a search pick them, e.g. "the 50 most popular CS2 cases".
3. Optionally turn on **Include every variant** to get every wear, StatTrak and Souvenir version of a skin in one go.
4. The actor collects everything, paging through long lists for you and retrying anything that stumbles.
5. Results land in the dataset, one clearly typed row per item, price point, listing or sale, ready to download or push onward.

No scrapers, browsers or blocks to babysit.

### Input

**Item overview** (one summary row per item):

```json
{
    "mode": "itemOverview",
    "items": [
        "AK-47 | Redline (Field-Tested)",
        "https://steamcommunity.com/market/listings/730/Dreams%20%26%20Nightmares%20Case"
    ],
    "appId": "730",
    "currency": "USD",
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}
```

**Price history of the 20 most popular CS2 cases**, one row per data point:

```json
{
    "mode": "priceHistory",
    "appId": "cs2",
    "searchFilters": { "Type": ["CSGO_Type_WeaponCase"] },
    "maxItems": 20,
    "historyDays": 90,
    "historyOutput": "perPoint",
    "currency": "USD"
}
```

**Lowest-float listings** of a skin:

```json
{
    "mode": "listings",
    "items": ["AK-47 | Redline (Field-Tested)"],
    "listingSort": "floatAsc",
    "maxFloat": "0.16",
    "maxListingsPerItem": 100,
    "currency": "USD"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `mode` | string | `search`, `itemOverview`, `priceHistory`, `orderBook`, `listings` or `recentSales`. |
| `items` | array | Exact market names (`AK-47 \| Redline (Field-Tested)`) or Steam market page URLs. Leave empty to take items from a search. |
| `appId` | string | Game: a Steam app id (`730` CS2, `570` Dota 2, `440` TF2, `252490` Rust, `753` Steam) or `cs2`, `dota2`, `tf2`, `rust`, `pubg`, `steam`. |
| `currency` | string | Currency of all prices (USD, EUR, GBP, IDR...). Uses Apify Proxy. |
| `expandVariants` | boolean | Add every wear / StatTrak / Souvenir variant of each item. |
| `searchQuery` | string | Text to search for (`knife`, `case`, `redline`...). |
| `searchFilters` | object | Category filters, e.g. `{"Type": ["CSGO_Type_WeaponCase"]}`, `{"Exterior": ["WearCategory0"]}`, `{"Quality": ["strange"]}`. |
| `sortBy` | string | `popular`, `priceAsc`, `priceDesc`, `quantityDesc`, `quantityAsc`, `nameAsc`, `nameDesc`. |
| `minPrice` / `maxPrice` | integer | Price range for search, in US dollars. |
| `maxItems` | integer | How many items search returns, or picks for the item modes. |
| `historyDays` | integer | Keep only the last N days of history points (0 = all). |
| `historyOutput` | string | `perItem` (one row per item with a `prices` list) or `perPoint` (one row per data point). |
| `orderBookDepth` | integer | Price levels per side of the order book (0 = all). |
| `maxListingsPerItem` | integer | Listings to collect per item. |
| `listingSort` | string | `priceAsc`, `priceDesc`, `floatAsc`, `floatDesc`, `patternAsc`, `patternDesc`. |
| `minFloat` / `maxFloat` | string | Float range for listings, e.g. `0.15` to `0.16`. |
| `includeFullDescription` | boolean | Keep the full description text on every listing and sale row. |
| `recentSalesPolls` / `recentSalesIntervalSecs` | integer | Poll the recent sales feed several times to build a longer history. |
| `filterRecentSalesByApp` | boolean | Only keep sales from the selected game. |
| `maxConcurrency` | integer | Parallel requests (default 4). |
| `proxyConfiguration` | object | Residential proxy recommended. Its country sets the currency. |

### Output

Every row has `recordType` plus `_input` (what you asked for), `_source` and `_scrapedAt`. Steam's own field names are kept as they are, and readable decimal prices are added next to them. The samples below are real rows from a live run. Item-mode samples were captured from an Indonesian connection, so they are priced in IDR; with the default settings you get USD. Long lists are cut short.

**`search`, recordType `ITEM`** (search is always priced in USD):

```json
{
    "_input": "redline",
    "_source": "S1-market-rpc",
    "_scrapedAt": "2026-10-10T21:17:45Z",
    "recordType": "ITEM",
    "strHash": "AK-47 | Redline (Field-Tested)",
    "cSellOrders": 1657,
    "eCurrency": 1,
    "strMinSellSubtotal": "$25.58",
    "appid": 730,
    "marketHashName": "AK-47 | Redline (Field-Tested)",
    "type": "Classified Rifle",
    "sellListings": 1657,
    "minSellPrice": 25.58,
    "minSellFee": 3.33,
    "currency": "USD",
    "commodity": false,
    "bucketGroupId": "G1807209A023004",
    "bucketGroupName": "AK-47 | Redline",
    "marketUrl": "https://steamcommunity.com/market/listings/730/AK-47%20%7C%20Redline%20%28Field-Tested%29"
}
```

**`itemOverview`, recordType `ITEM_OVERVIEW`**:

```json
{
    "recordType": "ITEM_OVERVIEW",
    "marketHashName": "AK-47 | Redline (Field-Tested)",
    "type": "Classified Rifle",
    "tagsByCategory": { "Type": "Rifle", "Weapon": "AK-47", "ItemSet": "The Phoenix Collection", "Rarity": "Classified", "Exterior": "Field-Tested" },
    "currency": "IDR",
    "highestBuyOrder": 578192.0,
    "lowestSellOrder": 588401.0,
    "spread": 10209.0,
    "spreadPct": 1.74,
    "buyOrderQuantity": 48161,
    "sellOrderQuantity": 1195,
    "historyPoints": 5253,
    "firstSaleDate": "2014-02-21T00:00:00Z",
    "allTimeHigh": 1414082.5,
    "allTimeHighDate": "2025-05-11T00:00:00Z",
    "allTimeLow": 75902.6797,
    "allTimeLowDate": "2015-06-21T00:00:00Z",
    "avgPrice24h": 591720.2078,
    "volume24h": 86,
    "avgPrice7d": 621463.0296,
    "volume7d": 651,
    "avgPrice30d": 663293.2597,
    "volume30d": 2395,
    "change7dVs30dPct": -6.31,
    "buyOrders": [{ "price": 578192.0, "quantity": 34, "cumulativeQuantity": 34 }, "... 9 more"],
    "sellOrders": [{ "price": 588401.0, "quantity": 1, "cumulativeQuantity": 1 }, "... 9 more"]
}
```

**`priceHistory`, recordType `PRICE_HISTORY`** (with `perPoint`, each entry of `prices` becomes its own `PRICE_POINT` row):

```json
{
    "recordType": "PRICE_HISTORY",
    "marketHashName": "Dreams & Nightmares Case",
    "currency": "IDR",
    "historyPoints": 2413,
    "firstSaleDate": "2022-01-21T00:00:00Z",
    "lastMedianPrice": 25242.041,
    "allTimeHigh": 191060.2344,
    "allTimeHighDate": "2022-01-21T00:00:00Z",
    "volume24h": 108584,
    "volume30d": 3381228,
    "change7dVs30dPct": -8.64,
    "prices": [
        { "time": "2026-10-09T22:00:00Z", "unixTime": 1791583200, "medianPrice": 25186.6406, "volume": 6718 },
        { "time": "2026-10-09T23:00:00Z", "unixTime": 1791586800, "medianPrice": 25237.1562, "volume": 6089 },
        "... 20 more"
    ]
}
```

**`orderBook`, recordType `ORDER_BOOK`**:

```json
{
    "recordType": "ORDER_BOOK",
    "marketHashName": "Dreams & Nightmares Case",
    "currency": "IDR",
    "highestBuyOrder": 25319.0,
    "lowestSellOrder": 25504.0,
    "spreadPct": 0.73,
    "buyOrderQuantity": 2684479,
    "sellOrderQuantity": 537117,
    "buyPriceLevels": 1847,
    "sellPriceLevels": 9345,
    "buyOrders": [
        { "price": 25319.0, "quantity": 2, "cumulativeQuantity": 2 },
        { "price": 25113.0, "quantity": 1, "cumulativeQuantity": 3 },
        "... more levels"
    ],
    "sellOrders": [
        { "price": 25504.0, "quantity": 82, "cumulativeQuantity": 82 },
        { "price": 25508.0, "quantity": 1, "cumulativeQuantity": 83 },
        "... more levels"
    ]
}
```

**`listings`, recordType `LISTING`** (sorted by lowest float):

```json
{
    "recordType": "LISTING",
    "listingid": "555788776600426528",
    "marketHashName": "AK-47 | Redline (Field-Tested)",
    "listingRank": 1,
    "price": 5576192.0,
    "sellerReceives": 4848863.0,
    "fee": 727329.0,
    "currency": "IDR",
    "floatValue": 0.15054911375045776,
    "paintSeed": 480,
    "stickers": [],
    "charms": [],
    "inspectImages": ["https://shared.akamai.steamstatic.com/market_listings/ea/730/555788776600426528/0_7801115096502093935.avif", "... 2 more"]
}
```

**`recentSales`, recordType `SALE`**:

```json
{
    "recordType": "SALE",
    "appName": "Counter-Strike 2",
    "marketHashName": "Prisma Case",
    "type": "Base Grade Container",
    "soldAt": "2026-10-10T21:17:48Z",
    "soldPrice": 29024.0,
    "soldPriceText": "IDR 29,024",
    "listingId": "533270778485424586"
}
```

| Field | Description |
| --- | --- |
| `recordType` | `ITEM`, `ITEM_OVERVIEW`, `PRICE_HISTORY`, `PRICE_POINT`, `ORDER_BOOK`, `LISTING`, `SALE` or `ERROR`. |
| `marketHashName` | The item's exact market name. Use it as the item key. |
| `currency` | Currency of the prices on that row. |
| `minSellPrice` / `sellListings` | Search: cheapest listing and number of listings. |
| `highestBuyOrder` / `lowestSellOrder` / `spread` / `spreadPct` | Best bid, best ask and the gap between them. |
| `buyOrders` / `sellOrders` | Order book levels: `{price, quantity, cumulativeQuantity}`, best price first. |
| `avgPrice24h` ... `avgPrice365d`, `volume24h` ... `volume365d` | Volume-weighted average price and units sold per window. |
| `allTimeHigh` / `allTimeLow` | Highest and lowest daily price ever, with dates. |
| `prices` / `medianPrice` / `volume` | History points: median sale price and units sold per day, or per hour for the last month. |
| `price` / `sellerReceives` / `fee` | Listings: what the buyer pays, what the seller gets, and the fee. |
| `floatValue` / `paintSeed` / `stickers` / `charms` | Listings: wear float, pattern seed, applied stickers (with scrape level) and charms. |
| `soldAt` / `soldPrice` | Sales: when the item sold and for how much. |
| `_error` / `_errorDetail` | Error rows only, e.g. `item_not_found` or `commodity_no_listings`, with a plain-language explanation. |

### Notes and limits

- **Item names must be exact.** Copy them from the item's Steam market page, or paste the page URL itself. A name that doesn't exist comes back as an `item_not_found` row, never as a silent gap.
- **Cases, keys, stickers and other interchangeable items** are traded through the order book only, so `listings` reports `commodity_no_listings` for them. Use `orderBook` or `itemOverview` instead.
- **Search groups variants:** one search row per skin (all wears together). Turn on **Include every variant** in an item mode to get each wear separately.
- **Currency follows the proxy country.** Steam prices everything in the visitor's local currency, so pick a currency (or a proxy country) and keep the residential proxy on. Search results are always in USD.
- **Recent sales:** Steam shows the latest 50 sales and refreshes about every 30 seconds. Set several polls to build a longer feed.
- Listings come 20 per page, so `maxListingsPerItem: 1000` means about 50 requests for that item. Every other mode needs one request per item, or one per 100 search results.

# Actor input Schema

## `mode` (type: `string`):

search: browse or search the market catalogue. itemOverview: one summary row per item (bid/ask, spread, 24h/7d/30d average price and volume, all-time high). priceHistory: the full median price and sales volume series. orderBook: every buy and sell price level. listings: individual items for sale with float, pattern seed and stickers. recentSales: the live feed of completed sales.

## `items` (type: `array`):

For the item modes. Each line is an exact market name (e.g. AK-47 | Redline (Field-Tested)) or a market page URL from your browser. Leave empty to take the items from a search instead (see the search settings below).

## `appId` (type: `string`):

Which game's market. A Steam app id (730 = CS2, 570 = Dota 2, 440 = TF2, 252490 = Rust, 753 = Steam trading cards) or one of: cs2, dota2, tf2, rust, pubg, steam. Item URLs carry their own game and ignore this.

## `currency` (type: `string`):

Steam prices everything in the currency of the visitor's country, so this picks the proxy country for you (USD = United States, EUR = Germany, ...). Needs Apify Proxy. Leave empty to use the proxy settings as they are. Search results are always in USD.

## `expandVariants` (type: `boolean`):

Turn each item into all of its variants: every wear (Factory New ... Battle-Scarred), StatTrak and Souvenir version. A grouped market URL (ending in /G...) is always expanded.

## `searchQuery` (type: `string`):

Search mode, or item modes with no Items: text to search for (e.g. knife, case, redline). Leave empty to browse everything.

## `searchFilters` (type: `object`):

Market category filters, as {"category": \["tag", ...]}. Examples for CS2: {"Type": \["CSGO_Type_WeaponCase"]} (cases), {"Exterior": \["WearCategory0"]} (Factory New), {"Rarity": \["Rarity_Ancient_Weapon"]} (Covert), {"Quality": \["strange"]} (StatTrak).

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

Order of the search results.

## `minPrice` (type: `integer`):

Only items whose cheapest listing costs at least this much, in US dollars.

## `maxPrice` (type: `integer`):

Only items whose cheapest listing costs at most this much, in US dollars.

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

How many catalogue items to return (search mode) or to pick from the search (item modes with no Items). Up to 100 items per request.

## `historyDays` (type: `integer`):

Price history mode: keep only the last N days of data points. 0 = everything since the item was first sold. Summary statistics (averages, all-time high) always use the full history.

## `historyOutput` (type: `string`):

perItem: one row per item with all data points in a 'prices' list. perPoint: one row per data point (best for spreadsheets and charts).

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

How many price levels to return on each side of the order book. 0 = every level. Item overview always shows a 10-level preview.

## `maxListingsPerItem` (type: `integer`):

Listings mode: how many individual sell listings to collect for each item.

## `listingSort` (type: `string`):

Listings mode: price, float (wear) or pattern seed. Float sorting is how you find the lowest-wear copies of a skin.

## `minFloat` (type: `string`):

Listings mode: skip listings with a float below this (e.g. 0.15). Leave empty for no limit.

## `maxFloat` (type: `string`):

Listings mode: skip listings with a float above this (e.g. 0.16). With 'Float: lowest first' sorting the run stops as soon as it passes this value.

## `includeFullDescription` (type: `boolean`):

Listings and recent sales: keep the full item description text and sticker artwork details on every row. Off keeps rows small.

## `recentSalesPolls` (type: `integer`):

Recent sales mode: Steam shows the latest 50 sales and refreshes them about every 30 seconds. Poll several times to build a longer feed; duplicates are removed.

## `recentSalesIntervalSecs` (type: `integer`):

Recent sales mode: wait between polls. The feed refreshes about every 30 seconds.

## `filterRecentSalesByApp` (type: `boolean`):

Recent sales mode: keep only sales for the game in the Game field. Off returns sales from every game.

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

How many requests run at the same time.

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

Residential proxy is recommended: it spreads requests over many IPs and its country sets the currency of every price. The Currency field above overrides the country.

## Actor input object example

```json
{
  "mode": "itemOverview",
  "items": [
    "AK-47 | Redline (Field-Tested)",
    "https://steamcommunity.com/market/listings/730/Dreams%20%26%20Nightmares%20Case"
  ],
  "appId": "730",
  "currency": "USD",
  "expandVariants": false,
  "sortBy": "popular",
  "maxItems": 20,
  "historyDays": 0,
  "historyOutput": "perItem",
  "orderBookDepth": 50,
  "maxListingsPerItem": 100,
  "listingSort": "priceAsc",
  "includeFullDescription": false,
  "recentSalesPolls": 1,
  "recentSalesIntervalSecs": 30,
  "filterRecentSalesByApp": false,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Every market item, price history, order book, listing or recent sale from this run, plus any error records.

# 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 = {
    "mode": "itemOverview",
    "items": [
        "AK-47 | Redline (Field-Tested)",
        "https://steamcommunity.com/market/listings/730/Dreams%20%26%20Nightmares%20Case"
    ],
    "appId": "730",
    "currency": "USD",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/steam-community-market-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 = {
    "mode": "itemOverview",
    "items": [
        "AK-47 | Redline (Field-Tested)",
        "https://steamcommunity.com/market/listings/730/Dreams%20%26%20Nightmares%20Case",
    ],
    "appId": "730",
    "currency": "USD",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("fanndev/steam-community-market-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 '{
  "mode": "itemOverview",
  "items": [
    "AK-47 | Redline (Field-Tested)",
    "https://steamcommunity.com/market/listings/730/Dreams%20%26%20Nightmares%20Case"
  ],
  "appId": "730",
  "currency": "USD",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call fanndev/steam-community-market-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/steam-community-market-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/JSjTRzAz38Ppvo9bh/builds/g05Y6ZeAxk0aTaenN/openapi.json
