# Steam Price & Market Monitor (`sashaebashu/steam-monitor`) Actor

Track Steam game prices and discounts — including exactly when each sale ends — plus live player counts, and Community Market item prices with listing counts and 24h volume. Monitor mode alerts you to price drops and sales starting or ending between runs.

- **URL**: https://apify.com/sashaebashu/steam-monitor.md
- **Developed by:** [Sasha Ebashu](https://apify.com/sashaebashu) (community)
- **Categories:** Games, E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 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.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Steam Price & Market Monitor

Tracks **Steam game prices and discounts** — including exactly when each sale ends — and
**Community Market item prices** with listing counts and 24-hour volume. In monitor mode it tells
you what moved since the last run.

Uses Steam's own public APIs. No key, no login, no browser, no CAPTCHA solving.

### Two modes

#### Store — games

Price, original price, discount % and **`discountEndsAt`**: the exact moment the sale expires.
That last one turns a price list into a deadline — «$17.99 instead of $59.99, until 10 August».

Optional extras, each one request per game:

- **`fullDetails`** — developers, publishers, genres, platforms, release date, Metacritic, plus
  Steam's own review verdict (`reviewScoreDesc`, e.g. *"Overwhelmingly Positive"*, with the total
  review count).
- **`withPlayerCount`** — **`playersOnline`**, how many people are in the game right now. Counter-Strike 2
  reads 672,128 as this is written. It is the demand signal a price-only scraper cannot give you.

Games come from any mix of: **search** by name, exact **app IDs**, or Steam's own **collections**
(`specials`, `top_sellers`, `new_releases`, `coming_soon`).

#### Market — Community Market items

CS2 skins, TF2 hats, Dota sets, trading cards. Per item: cheapest listing price, **how many are
listed**, median price, **24-hour sales volume**, item type, rarity colour, tradability and icon.
Price plus liquidity is what a trader actually reads.

Pick the game with `marketAppId`: 730 = CS2 (~34,700 items), 440 = Team Fortress 2 (~41,600),
570 = Dota 2 (~33,700), 252490 = Rust.

### Monitor mode

Compares against the previous run for the **same search and country**:

| `changeType` | Means |
|---|---|
| `new` | First time seen in this scope |
| `discount_start` | A sale just began |
| `discount_end` | The sale is over |
| `price_down` / `price_up` | The price moved with no change in sale status |
| `unchanged` | Nothing moved |

Sale start and end are checked **before** the plain price comparison, because a drop caused by a
sale is a different event from a permanent price change — only the former reverts. Rows also carry
`previousPrice`, `priceLow30` and `priceHigh30`.

Turn on **Output only changed items** so each run returns just what moved.

### Input

| Field | What it does |
|---|---|
| **What to track** | `store` (games) or `market` (Community Market items). Everything below is tagged with the mode it applies to. |
| **Search** | Game names in store mode, item keywords in market mode. |
| **App IDs** *(store)* | Exact games, e.g. `730`. Skips search entirely. |
| **Collections** *(store)* | Steam's own lists: `specials`, `top_sellers`, `new_releases`, `coming_soon`. Default `specials` — this is also the only source of `discountEndsAt`. |
| **Full game details** *(store)* | Developers, publishers, genres, platforms, release date, Metacritic, review verdict. One request per game. |
| **Add live player count** *(store)* | `playersOnline` — how many people are in the game right now. One request per game. |
| **Market app** *(market)* | Which game's items: `730` CS2, `440` TF2, `570` Dota 2, `252490` Rust. |
| **Add median price & 24h volume** *(market)* | Liquidity data per item. On by default. |
| **Country / currency** | Pricing region, e.g. `us`, `de`, `ru`. Some titles have no price in some regions. |
| **Max pages** *(market)* | The Market returns 10 items per page whatever you ask for, so pagination moves in tens. |
| **Max results / Max concurrency** | Overall row cap (0 = no cap) and parallel requests (default 4). |
| **Monitor mode / Output only changed items** | The alert behaviour above. |

### Notes & limits

Properties of Steam's API, measured rather than assumed:

- **Prices come 50 games per request, full details one at a time.** `appdetails` accepts a batch of
  app IDs only with `filters=price_overview`; asking for full data on two IDs returns nothing. That
  is why `fullDetails` is opt-in and flagged as costing one request per game.
- **The Market returns 10 items per request** whatever `count` says (verified up to 200), so market
  pagination moves in tens and a whole-game dump is expensive — narrow it with a keyword.
- **No rate limiting at a sane pace** — twelve rapid price lookups in a row all returned 200 — but
  the Actor still backs off and retries on HTTP 429.
- **Some titles have no price in some regions.** `cc=ru` in particular returns no price for many
  games; those rows come back with `price: null` rather than a guess.
- **Sale end times come from Steam's featured collections**, which is the only place
  `discount_expiration` is published — a game found purely by search may therefore have a discount
  but no `discountEndsAt`.
- Cost measured at **$0.06 per 1,000 rows**.

# Actor input Schema

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

«Store» tracks game prices, discounts and when each sale ENDS. «Market» tracks Community Market items (CS2 skins, TF2 items, cards) — cheapest listing, median price and 24h volume.

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

Store mode: game names (e.g. \["Cyberpunk", "Witcher"]). Market mode: item keywords (e.g. \["AK-47", "Karambit"]). Leave empty in market mode to walk the whole app.

## `appIds` (type: `array`):

Exact Steam app IDs to track, e.g. 1091500. Combine with or instead of search.

## `collections` (type: `array`):

Steam's own lists to pull in: specials (current sales), top\_sellers, new\_releases, coming\_soon.

## `fullDetails` (type: `boolean`):

Adds developers, publishers, genres, platforms, release date, review count, Metacritic and description. COSTS ONE EXTRA REQUEST PER GAME — Steam only returns full data for a single app at a time, while prices come back 50 at a time. Leave off for large price-watch runs.

## `withPlayerCount` (type: `boolean`):

Adds `playersOnline` — how many people are IN the game right now, from Steam's public stats API. A demand signal that price-only scrapers do not carry. Costs one extra request per game.

## `marketAppId` (type: `integer`):

Which game's Community Market to read: 730 = CS2 (34,700 items), 440 = Team Fortress 2 (41,600), 570 = Dota 2 (33,700), 252490 = Rust.

## `withMarketPrice` (type: `boolean`):

The search result already carries the cheapest listing and the number of listings. This adds the median price and 24-hour sales volume per item — the liquidity signal — at one extra request per item.

## `country` (type: `string`):

Two-letter country code for store prices: us, gb, de, br… NOTE: many titles return no price for cc=ru, so those rows come back without a price.

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

The Community Market returns 10 items per request regardless of what is asked, so this is pages of 10.

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

Stop after this many rows. 0 = no limit.

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

Parallel requests. Steam throttles hard bursts with HTTP 429; the Actor backs off and retries, but keep this modest.

## `monitorMode` (type: `boolean`):

Compare against the previous run for the SAME search and country, and label every row: new / price\_down / price\_up / discount\_start / discount\_end / unchanged, plus previous price and 30-day low & high.

## `onlyChanges` (type: `boolean`):

Monitor mode only — drop `unchanged` rows so each run returns just what moved.

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

Steam needs no special proxy. The cheap datacenter default just spreads heavy runs across IPs.

## Actor input object example

```json
{
  "mode": "store",
  "searchQueries": [
    "Cyberpunk"
  ],
  "collections": [
    "specials"
  ],
  "fullDetails": false,
  "withPlayerCount": false,
  "marketAppId": 730,
  "withMarketPrice": true,
  "country": "us",
  "maxPages": 5,
  "maxItems": 0,
  "maxConcurrency": 4,
  "monitorMode": false,
  "onlyChanges": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `market` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `details` (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 = {
    "searchQueries": [
        "Cyberpunk"
    ],
    "collections": [
        "specials"
    ],
    "country": "us",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("sashaebashu/steam-monitor").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 = {
    "searchQueries": ["Cyberpunk"],
    "collections": ["specials"],
    "country": "us",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("sashaebashu/steam-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "Cyberpunk"
  ],
  "collections": [
    "specials"
  ],
  "country": "us",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call sashaebashu/steam-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=sashaebashu/steam-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RjiEIWzEUxan6czhe/builds/AhLhYNyQaPdXbJtHh/openapi.json
