# Steam API & Store Scraper — Prices & Top Sellers | $0.50/1k (`glasswing/steam-store-scraper`) Actor

Scrape Steam game data by app ID, store URL, keyword or store list (top sellers, new releases, specials, coming soon): price and discount in any currency, review score with positive and negative counts, current players, genres, developers, publishers, release date. No login or API key.

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

## Pricing

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

### What does Steam Store Scraper do?

Steam Store Scraper turns **Steam app IDs, store URLs, search keywords and Steam's own store lists into clean game data**: current and regular price, discount and currency for any store country, release date, developers and publishers, genres and categories, platforms, Metacritic score, the Steam review score with **total positive and negative review counts**, the **number of people playing right now**, supported languages, DLC, age ratings, header image and screenshots. One row per game, as JSON, CSV or Excel.

It works as a **Steam store API** without a key or an account: the Actor reads the same public endpoints the Steam store uses for its own pages (app details, review summary, store search, live player count), so it is fast, cheap and needs no browser.

Typical use cases:

- **Price and discount tracking.** Schedule a daily run over your wishlist or a competitor's catalog and chart `priceFinal` and `discountPercent`, in any currency (`country`).
- **Market research.** Pull the top sellers, popular new releases, specials or upcoming games and compare genres, prices, review counts and live players.
- **Game databases and dashboards.** Enrich a list of app IDs with developers, publishers, release dates, platforms, languages and ratings.
- **Competitor and genre analysis.** Search a keyword (`roguelike`, `city builder`) and rank the results by `totalPositive`, `positivePercent` or `currentPlayers`.

This is a **game data** tool. It reads aggregate numbers only: no review texts, no user names, no profiles or anything else about individual people.

### Why use Steam Store Scraper?

- **Every way in.** App IDs, store links, Steam Community and SteamDB app links, store search URLs (their filters are kept), a keyword, or the lists top sellers, new releases, specials and coming soon.
- **More per row.** Price, reviews and live players in one row, with no second tool to join.
- **Cheap.** $0.50 per 1,000 games, with Apify platform usage included.
- **Fast.** The default run (6 games) finishes in under 10 seconds on Apify; 150 games took 53 seconds.
- **Honest results.** Every row carries `status` (`ok`, `not_found`, `error`). An unknown app ID or a search with no results is a free `not_found` row, so a script or an AI agent can tell "this game does not exist" apart from "the lookup failed".
- **Polite to Steam.** At most four calls at a time from one IP, automatic back-off when Steam rate-limits, and a clear `error` row instead of a silently missing game if throttling persists.

### What data can Steam Store Scraper extract?

| Field | Type | Description |
|---|---|---|
| `appId` | integer | Steam app ID |
| `name` | string | App name as shown on the store |
| `type` | string | `game`, `dlc`, `demo`, `music`, `video`, `hardware`, ... |
| `isFree` | boolean | Free-to-play |
| `priceFinal` | number | Current price in the store currency, after the discount (0 for free games) |
| `priceInitial` | number | Regular price before the discount |
| `discountPercent` | integer | Current discount in percent |
| `currency` | string | ISO 4217 currency of the prices (set by `country`) |
| `priceFormatted` | string | Price as the store displays it, e.g. `$24.99` |
| `releaseDate` | string | Release date as `YYYY-MM-DD` (English store language) |
| `releaseDateText` | string | Release date as shown on the store, e.g. `Q4 2026`, `Coming soon` |
| `comingSoon` | boolean | Not released yet |
| `developers` | array | Developer companies |
| `publishers` | array | Publisher companies |
| `genres` | array | Store genres, e.g. Action, RPG, Free To Play |
| `categories` | array | Store features, e.g. Single-player, Steam Achievements, Steam Cloud |
| `platforms` | array | `windows`, `mac`, `linux` |
| `metacriticScore` | integer | Metacritic score when the store shows one |
| `recommendationsTotal` | integer | Steam recommendations count |
| `reviewScore` | integer | Steam review score bucket 0-9 (9 = Overwhelmingly Positive) |
| `reviewScoreDesc` | string | Steam review label, e.g. `Very Positive` |
| `totalPositive` | integer | Total positive user reviews, all languages |
| `totalNegative` | integer | Total negative user reviews, all languages |
| `totalReviews` | integer | `totalPositive` + `totalNegative` |
| `positivePercent` | number | Share of positive reviews in percent |
| `currentPlayers` | integer | People playing right now (Steam's live count) |
| `headerImage` | string | Header image URL |
| `storeUrl` | string | Steam store page |
| `website` | string | The game's own website, when listed |
| `shortDescription` | string | Short store description, HTML removed |
| `supportedLanguages` | array | Supported languages, HTML removed |
| `fullAudioLanguages` | array | Languages with full audio |
| `dlcCount` | integer | Number of DLCs |
| `dlcAppIds` | array | App IDs of the DLCs |
| `parentAppId` | integer | For DLC, soundtracks and demos: the base game's app ID |
| `parentName` | string | For DLC, soundtracks and demos: the base game's name |
| `requiredAge` | integer | Minimum age Steam asks for (0 = none) |
| `ageRatings` | object | Age ratings by system, e.g. `{"esrb": "M", "pegi": "18"}` |
| `contentNotes` | string | The developer's mature content notes |
| `achievementsTotal` | integer | Number of Steam achievements |
| `controllerSupport` | string | `full` or `partial` |
| `screenshots` | array | Up to 10 full-size screenshot URLs |
| `source` | string | How the row was found: `appId`, `search`, `list` or `searchUrl` |
| `searchQuery` | string | The keyword that found the row |
| `list` | string | The store list that found the row: `topsellers`, `newreleases`, `specials`, `comingsoon` |
| `rank` | integer | Position in Steam's search result or list (1 = first) |
| `country` | string | Store country of the prices |
| `language` | string | Store language of the texts |
| `url` | string | Steam store page of the app (for `not_found`/`error` rows: what was asked) |
| `status` | string | `ok`, `not_found` or `error` (see below) |
| `error` | string | Reason when `status` is not `ok` |
| `scrapedAt` | string | ISO 8601 time of extraction |

A field is left out when Steam does not publish it for that app (free games have no currency, unreleased games no reviews or player count). An empty field is honest: it never means a guess.

#### Result status (tri-state output)

| `status` | Meaning | Billed? |
|---|---|---|
| `ok` | The game was found and extracted. | Yes |
| `not_found` | Steam answered, but has no store data for that app ID in the chosen country (wrong ID, removed, or not sold there), or the search found nothing. | No |
| `error` | Steam could not be read after retries (for example it kept rate-limiting). `error` says why. | No |

### How to scrape Steam game data

1. Open the Actor and click **Try for free**.
2. Paste app IDs or store links into **App IDs or store URLs**, type a **Search keyword**, or pick one or more **Store lists**.
3. Choose the **Store country** (currency and regional prices) and the **Language**.
4. Set **Maximum results** (the default 20 is a quick test) and click **Start**. Rows appear in the dataset as they are ready.
5. Download the results as JSON, CSV, Excel or HTML, or read them through the API.

To automate it, use the **API** tab (Node.js, Python, curl) or add a **Schedule**, and send the results to Google Sheets, Slack, a webhook, Zapier or Make.

### Input

See the **Input** tab for the full schema. The main options:

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array of strings | 6 example games | App IDs, store/Community/SteamDB app links, or store search URLs |
| `query` | string | - | Search keyword, e.g. `roguelike` |
| `lists` | array | - | `topsellers`, `newreleases`, `specials`, `comingsoon` |
| `maxItems` | integer | `20` | Total rows; app IDs first, the rest shared evenly by the keyword and the lists |
| `country` | string | `us` | Store country: currency and regional prices |
| `language` | string | `english` | Language of names, descriptions, genres |
| `includeReviewSummary` | boolean | `true` | Review score and positive/negative counts |
| `includePlayerCount` | boolean | `true` | People playing right now |
| `proxyConfiguration` | object | off | Optional Apify Proxy (datacenter) for large runs |

When you give a keyword or a list, the example app IDs are skipped, so you only get what you asked for.

Example input (the default run):

```json
{
    "startUrls": [
        "730",
        "https://store.steampowered.com/app/1245620/ELDEN_RING/",
        "1086940",
        "413150",
        "292030",
        "1091500"
    ],
    "maxItems": 20,
    "country": "us",
    "language": "english"
}
```

Top sellers and specials in Germany, in euros:

```json
{
    "lists": ["topsellers", "specials"],
    "country": "de",
    "maxItems": 100
}
```

### Output

You can download the dataset as JSON, CSV, Excel, XML or HTML. A real row from a cloud run of the default input (some arrays shortened here):

```json
{
    "url": "https://store.steampowered.com/app/292030/",
    "status": "ok",
    "scrapedAt": "2026-09-27T13:15:27.484Z",
    "appId": 292030,
    "name": "The Witcher 3: Wild Hunt - Complete Edition",
    "type": "game",
    "isFree": false,
    "priceInitial": 49.99,
    "priceFinal": 24.99,
    "discountPercent": 50,
    "currency": "USD",
    "priceFormatted": "$24.99",
    "releaseDate": "2015-05-18",
    "releaseDateText": "May 18, 2015",
    "comingSoon": false,
    "developers": [
        "CD PROJEKT RED"
    ],
    "publishers": [
        "CD PROJEKT RED"
    ],
    "genres": [
        "RPG"
    ],
    "categories": [
        "Single-player",
        "Steam Achievements",
        "Steam Trading Cards",
        "Steam Workshop",
        "Adjustable Text Size"
    ],
    "platforms": [
        "windows"
    ],
    "metacriticScore": 93,
    "recommendationsTotal": 834235,
    "reviewScore": 9,
    "reviewScoreDesc": "Overwhelmingly Positive",
    "totalPositive": 860453,
    "totalNegative": 28797,
    "totalReviews": 889250,
    "positivePercent": 96.8,
    "headerImage": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/292030/97cca1147b256f450331044255b1dbd2d57d609e/header_alt_assets_4.jpg?t=1788333513",
    "storeUrl": "https://store.steampowered.com/app/292030/",
    "website": "https://www.thewitcher.com/witcher3",
    "shortDescription": "You are Geralt of Rivia, mercenary monster slayer. Before you stands a war-torn, monster-infested continent you can explore at will. Your current contract? Tracking down Ciri — the Child of Prophecy, a living weapon that can alter the shape of the world.",
    "supportedLanguages": [
        "English",
        "French",
        "Italian",
        "German",
        "Spanish - Spain",
        "Arabic"
    ],
    "fullAudioLanguages": [
        "English",
        "French",
        "German",
        "Japanese"
    ],
    "dlcCount": 4,
    "dlcAppIds": [
        5006530,
        1229320,
        1233280,
        1233340
    ],
    "requiredAge": 17,
    "ageRatings": {
        "esrb": "M",
        "pegi": "18",
        "usk": "18",
        "oflc": "R18"
    },
    "contentNotes": "The Witcher 3: Wild Hunt contains strong language, intense violence, blood and gore, as well as nudity and sexual material.",
    "achievementsTotal": 78,
    "screenshots": [
        "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/292030/ss_5710298af2318afd9aa72449ef29ac4a2ef64d8e.1920x1080.jpg?t=1788333513",
        "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/292030/ss_0901e64e9d4b8ebaea8348c194e7a3644d2d832d.1920x1080.jpg?t=1788333513"
    ],
    "source": "appId",
    "country": "US",
    "language": "english",
    "currentPlayers": 20170
}
```

An app ID Steam does not know comes back as a free row (real row; a run with only such rows still ends as succeeded):

```json
{
    "url": "https://store.steampowered.com/app/999999999/",
    "status": "not_found",
    "error": "Steam has no store data for app 999999999 in country US: the id is wrong, the app was removed, or it is not sold in this country.",
    "scrapedAt": "2026-09-27T13:46:13.038Z"
}
```

### How much does it cost to scrape Steam?

This Actor uses **pay-per-event** pricing; Apify platform usage is included:

| Event | Price |
|---|---|
| Actor start | $0.005 per run |
| Result (`status: ok` row) | $0.0005 per game |

Example: 1,000 games cost $0.505 ($0.50 for the rows + $0.005 for the start). Rows with `status` `not_found` or `error` are never billed. You can cap spending with **Maximum results** and the run's **Max total charge** option; the Actor stops cleanly when the cap is reached.

### Benchmark (real cloud runs)

| Run | Games | Time | Calls to Steam | Errors |
|---|---|---|---|---|
| Default input | 6 | 9 s | 18 | 0 |
| Top sellers + specials + keyword `roguelike` | 150 | 53 s | 453 | 0 |
| All four store lists, 100 each, no proxy | 399 | 6 min 36 s | 1,108 | 0 |
| The same with Apify Proxy (datacenter) on | 399 | 3 min 48 s | 1,108 | 0 |

Honest notes: Steam lets one IP make roughly 300 store calls quickly and then answers "too many requests" for a while. The Actor then waits 30 seconds and tries again; in the 399-game run 32 calls needed one wait and none failed. So small runs are fast, and larger runs without a proxy settle at roughly 60 games per minute. With Apify Proxy on, each call can leave from another IP, Steam stops throttling, and the Actor runs 12 calls at a time instead of 4 (about 100 games per minute in the run above). Rows keep arriving either way. One list held a bundle, which is skipped, so that run returned 399 games instead of 400.

### Tips

- For runs of several hundred games, turn on **Apify Proxy** (datacenter): the calls are spread over more IPs and the run goes about twice as fast.
- Switch off **Review summary** when you only need prices and details: it halves the store calls per game.
- Put many app IDs in one run instead of many one-game runs; you pay the start fee once.
- `rank` keeps Steam's order for keyword searches and lists; sort by it to rebuild the list.

### Limitations

- Prices, lists and availability depend on the store country. An app that is not sold in that country is a `not_found` row.
- Release dates become ISO dates only when the language is English; other languages keep the text in `releaseDateText`.
- Each keyword search or list reads up to about 5,000 games. Bundles and packages in search results are skipped; the Actor returns apps.
- `currentPlayers` is empty for unreleased games and apps without live stats.
- The data is what the Steam store shows at the time of the run. If Steam changes an endpoint, rows come back as `error` and the Actor is updated; report it in the **Issues** tab.

### FAQ

**Do I need a Steam account or a Steam Web API key?** No. The Actor uses only public store endpoints that need no login and no key.

**Does it scrape user reviews?** No. It reads the review summary only: the score label and the total positive and negative counts. No review texts and no reviewer names.

**Can I get prices in euros, pounds or yen?** Yes. Set **Store country** (`de`, `gb`, `jp`, ...) and the prices come in that store's currency.

**Why did I get fewer rows than `maxItems`?** The search or list had fewer games, some results were bundles (skipped), or the run hit your **Max total charge**. The run log shows the plan and why it stopped.

**Can an AI agent call this Actor?** Yes. All inputs are optional plain values, every row explains itself with `status` and `error`, and results are available through the dataset API and the Apify MCP server.

**Is this the Steam Web API?** No. It is an independent tool that reads Steam's public store endpoints and returns tidy rows.

### Related Actors

- [App Store Scraper](https://apify.com/glasswing/app-store-scraper) - use it for mobile app data instead of PC games.
- [Google Play Scraper](https://apify.com/glasswing/google-play-scraper) - use it for Android app and game data instead of Steam's PC catalog.
- [Discord Server Stats](https://apify.com/glasswing/discord-server-stats) - use it to check a game's community activity alongside its store data.

### Legal and data-protection notice

This Actor extracts only data that the Steam store publishes publicly about apps and companies (prices, descriptions, aggregate review counts, player counts). It does not extract personal data such as user names, profiles, review texts, e-mail addresses or phone numbers, and it does not log in or get around access controls. Personal data is protected by the GDPR in the European Union and by other regulations around the world; you should not scrape personal data unless you have a legitimate reason to do so. You are responsible for complying with Steam's terms of service and applicable law when using the extracted data.

Steam Store Scraper is an independent tool and is not affiliated with, endorsed by or sponsored by Valve Corporation or Steam. Steam and the Steam logo are trademarks of Valve Corporation; all other trademarks belong to their respective owners.

# Changelog

This Actor's version history is a separate document: https://apify.com/glasswing/steam-store-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

One per line: a Steam app ID (`570`), a store page (`https://store.steampowered.com/app/570/Dota_2/`), a Steam Community or SteamDB app URL, or a store search URL (`https://store.steampowered.com/search/?term=roguelike&specials=1`, its filters are kept). Leave empty when you use a keyword or a list.

## `query` (type: `string`):

Search the Steam store like its search box does (a game name, a genre, a franchise), e.g. `roguelike` or `portal`. Rows keep Steam's result order in `rank`. When you use this, the example app IDs above are skipped.

## `lists` (type: `array`):

Read Steam's own store lists for the chosen country, in Steam's order (`rank`). maxItems is shared evenly between the lists and the keyword. When you use this, the example app IDs above are skipped.

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

Total rows to save. App IDs come first (one row each); the rest is shared evenly by the keyword and the lists. Each saved row with status `ok` is one billable result.

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

Two-letter country code of the Steam store to read: sets the currency and regional prices, and what the lists contain. Examples: `us`, `gb`, `de`, `fr`, `jp`, `br`, `ca`, `au`.

## `language` (type: `string`):

Language of names, descriptions, genres, categories and the review score label. Release dates are also turned into ISO dates when the language is English.

## `includeReviewSummary` (type: `boolean`):

Add Steam's review score and the total positive and negative review counts (aggregate numbers only, never review texts or reviewer names). One extra call per game.

## `includePlayerCount` (type: `boolean`):

Add the number of people playing right now (Steam's live count). One extra call per game; empty for apps without live stats such as DLC and soundtracks.

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

Optional. Steam's store API is public and works from Apify's datacenter IPs. For runs of several hundred games, Apify Proxy (datacenter) spreads the calls over more IPs so Steam's per-IP rate limit is reached less often. Residential proxies are not needed.

## `maxResults` (type: `integer,string`):

Alias of maxItems for API callers.

## Actor input object example

```json
{
  "startUrls": [
    "730",
    "https://store.steampowered.com/app/1245620/ELDEN_RING/",
    "1086940",
    "413150",
    "292030",
    "1091500"
  ],
  "maxItems": 20,
  "country": "us",
  "language": "english",
  "includeReviewSummary": true,
  "includePlayerCount": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "startUrls": [
        "730",
        "https://store.steampowered.com/app/1245620/ELDEN_RING/",
        "1086940",
        "413150",
        "292030",
        "1091500"
    ],
    "maxItems": 20,
    "country": "us",
    "language": "english",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("glasswing/steam-store-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 = {
    "startUrls": [
        "730",
        "https://store.steampowered.com/app/1245620/ELDEN_RING/",
        "1086940",
        "413150",
        "292030",
        "1091500",
    ],
    "maxItems": 20,
    "country": "us",
    "language": "english",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("glasswing/steam-store-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 '{
  "startUrls": [
    "730",
    "https://store.steampowered.com/app/1245620/ELDEN_RING/",
    "1086940",
    "413150",
    "292030",
    "1091500"
  ],
  "maxItems": 20,
  "country": "us",
  "language": "english",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call glasswing/steam-store-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,glasswing/steam-store-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/rmcpLwVy2Qp77WjNe/builds/7bpasmeP7OQVldSNm/openapi.json
