# Steam Store Scraper: Games, Prices & Regional Pricing (`arman-bd/steam-store-scraper`) Actor

Scrape the Steam store: game details, pricing across regions, discounts, genres, developers, publishers, release dates and Metacritic scores. No key, no login, no browser.

- **URL**: https://apify.com/arman-bd/steam-store-scraper.md
- **Developed by:** [Arman Hossain](https://apify.com/arman-bd) (community)
- **Categories:** E-commerce, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.74 / 1,000 game scrapeds

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/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 Store Scraper: Games, Prices & Regional Pricing

![Steam Store Scraper: Game details and live pricing in as many regions as you ask for, with discounts, genres and Metacritic scores](https://api.apify.com/v2/key-value-stores/ZQOcNAOHrIgTacAmy/records/steam-store-scraper.jpg)

**Steam Store Scraper** reads the Steam storefront API for any game: title, type, developers, publishers, genres, categories, platforms, Metacritic score, review count, release date and the live price, with discounts, in as many countries as you ask for.

It talks to `store.steampowered.com/api` the way Steam's own store pages do: **no key, no login, no proxy, no browser.** Give it app IDs, game names, or nothing at all and it takes Steam's featured lists.

**Agent skill: [SKILL.md](https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/steam-store-scraper.md)**

```
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/steam-store-scraper.md
```

### What you get

| Output field | Meaning |
|---|---|
| `appId`, `name`, `type` | Steam app ID, title, and whether it is a game, dlc, demo, music… |
| `isFree` | True for free-to-play titles, which carry no price block |
| `country`, `currency`, `priceInitial`, `priceFinal`, `discountPercent` | Live price in the first country you list, converted from Steam's minor units |
| `regionalPrices` | One `{country, currency, initial, final, discountPercent, finalFormatted}` entry per requested country |
| `developers`, `publishers` | Studio and publisher lists |
| `genres`, `categories` | Steam's own genre and feature tags ("RPG", "Single-player", "Steam Cloud") |
| `releaseDate`, `releaseDateIso`, `comingSoon` | Steam's display date, an ISO date when parseable, and the unreleased flag |
| `metacriticScore`, `metacriticUrl`, `recommendations` | Critic score with its source link, and the Steam review count |
| `platforms`, `requiredAge`, `supportedLanguages` | Supported OSes as an array, age gate, and the language list |
| `dlcCount`, `achievementsTotal`, `headerImage`, `website`, `shortDescription`, `storeUrl` | The rest of the store page, flattened |
| `scrapedAt` | Run timestamp |

A `RUN_SUMMARY` record in the key-value store holds per-run counts, resolved and unresolved search terms, unavailable app IDs, and any request that failed.

### Common use cases

- **Regional price comparison.** The same game at $17.99 in the US, ¥2,633 in Japan and R$59.97 in Brazil, in one row.
- **Discount-cycle monitoring.** Track `discountPercent` and `priceFinal` on a watchlist through a Steam sale.
- **Games-market research.** Genre, category, Metacritic and review-count distributions across the top sellers.
- **Catalogue enrichment.** Resolve a list of game names to app IDs and structured metadata.

### Quick start

Nothing at all, Steam's current specials, top sellers, new releases and upcoming titles:

```json
{}
```

A watchlist priced in four regions:

```json
{
 "appIds": ["1091500", "1086940", "292030"],
 "countryCodes": ["us", "de", "jp", "br"]
}
```

Resolve by name, in German:

```json
{
 "searchTerms": ["Baldur's Gate 3", "Hades II", "Elden Ring"],
 "countryCodes": ["de"],
 "language": "german"
}
```

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `appIds` | array | `[]` | Numeric app IDs or full store URLs. |
| `searchTerms` | array | `[]` | Game names, resolved through Steam's store search. Best single match per term. |
| `countryCodes` | array | `["us"]` | ISO alpha-2 codes. The first drives the full record; the rest add regional prices. |
| `language` | string | `english` | Steam language *name*, not a locale code. |
| `includeFeatured` | boolean | `false` | Append Steam's specials, top sellers, new releases and coming-soon lists. |
| `maxApps` | integer | `50` | Cap on games per run. `0` = no cap. |

#### Which combinations make sense

- **No input at all** turns `includeFeatured` on automatically and returns roughly 50 currently promoted apps. That is the intended zero-config run.
- `appIds` **and** `searchTerms` merge into one deduplicated list; the cap applies to the merged list.
- `countryCodes` beyond the first cost one extra request per 50 games, not one per game, so comparing eight regions across 50 games is 58 requests, not 400.
- `language` other than `english` leaves `releaseDateIso` null, because Steam returns a localised date string this Actor will not guess at.
- `maxApps: 0` with `includeFeatured` is safe (the featured lists hold ~60 IDs); `maxApps: 0` with a 5,000-ID list is a two-hour run at Steam's throttle.

### Output example

A real record from a live run (`categories` and `supportedLanguages` abridged):

```json
{
 "appId": 1091500,
 "name": "Cyberpunk 2077",
 "type": "game",
 "isFree": false,
 "country": "us",
 "currency": "USD",
 "priceInitial": 59.99,
 "priceFinal": 17.99,
 "discountPercent": 70,
 "priceFormatted": "$17.99",
 "regionalPrices": [
 { "country": "us", "currency": "USD", "initial": 59.99, "final": 17.99, "discountPercent": 70, "finalFormatted": "$17.99" },
 { "country": "de", "currency": "EUR", "initial": 59.99, "final": 17.99, "discountPercent": 70, "finalFormatted": "17,99€" },
 { "country": "jp", "currency": "JPY", "initial": 8778, "final": 2633, "discountPercent": 70, "finalFormatted": "¥ 2,633" }
 ],
 "developers": ["CD PROJEKT RED"],
 "publishers": ["CD PROJEKT RED"],
 "genres": ["RPG"],
 "categories": ["Single-player", "Steam Achievements", "Full controller support", "Steam Cloud"],
 "releaseDate": "Dec 9, 2020",
 "releaseDateIso": "2020-12-09",
 "comingSoon": false,
 "metacriticScore": 86,
 "metacriticUrl": "https://www.metacritic.com/game/pc/cyberpunk-2077?ftag=MCD-06-10aaa1f",
 "recommendations": 877998,
 "platforms": ["windows", "mac"],
 "requiredAge": 17,
 "dlcCount": 3,
 "achievementsTotal": 57,
 "supportedLanguages": ["English*", "French*", "Italian*", "German*", "Japanese*"],
 "headerImage": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1091500/…/header.jpg",
 "website": "https://www.cyberpunk.net",
 "shortDescription": "Cyberpunk 2077 is an open-world, action-adventure RPG set in the dark future of Night City…",
 "storeUrl": "https://store.steampowered.com/app/1091500/",
 "scrapedAt": "2026-08-06T11:45:11.158Z"
}
```

Two things about this record:

- **`regionalPrices` is omitted entirely** (not null) when you request a single country, so CSV exports of a one-region run stay narrow.
- **Prices are already converted.** Steam returns minor units for every currency including JPY, where `877800` means ¥8,778. The Actor divides by 100 once, consistently, and keeps Steam's own `finalFormatted` string alongside so you can check it.

#### `RUN_SUMMARY`

```json
{
 "appsRequested": 5,
 "appsSaved": 4,
 "appsUnavailable": 1,
 "unavailableAppIds": [999999999],
 "resolvedSearchTerms": [{ "appId": 1086940, "name": "Baldur's Gate 3" }],
 "unresolvedSearchTerms": ["zzzqqqnotathing"],
 "featuredIdsAdded": 0,
 "requestsFailed": 0,
 "failures": [],
 "filters": { "countryCodes": ["us", "de", "jp"], "language": "english", "includeFeatured": false, "maxApps": 10 },
 "finishedAt": "2026-08-06T11:45:11.162Z"
}
```

`appsUnavailable` and `requestsFailed` are different things: the first is Steam saying "this app is not sold here", the second is a request that never landed.

### Finding an app ID

The app ID is the number in the store URL: `store.steampowered.com/app/1091500/Cyberpunk_2077/` → **1091500**. You can paste the whole URL, the Actor extracts the number.

If you only have names, use `searchTerms`. The Actor calls Steam's own store search, takes the best result of type `app`, and logs which title it picked so you can check it. Steam's `ISteamApps/GetAppList` Web API method, the usual advice for bulk name lookup, now returns 404 and is no longer usable; store search is the working replacement.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/arman-bd~steam-store-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
 "appIds": ["1091500", "1086940"],
 "countryCodes": ["us", "de", "jp"]
 }'
```

### JavaScript example

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/steam-store-scraper').call({
 appIds: ['1091500', '292030'],
 countryCodes: ['us', 'de', 'jp', 'br'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const game of items) {
 const row = game.regionalPrices.map((p) => `${p.country}:${p.finalFormatted}`).join(' ');
 console.log(`${game.name}, ${row}`);
}
```

### Limits and behaviour

- **One app per full request.** Passing several IDs to `appdetails` without a filter returns HTTP 400, verified. The only exception is `filters=price_overview`, which does accept a list; 50 IDs came back in a single response, and that is exactly how the extra countries are fetched.
- **Steam throttles around 200 requests per 5 minutes.** Requests are paced 1.5 s apart, so budget about 40 games a minute, roughly 1,200 against the default 30-minute timeout. Raise the timeout for more.
- **A 429 is a timed ban, not a bucket.** Backoff is in minutes (60 s, then 120 s), and `Retry-After` is honoured when Steam sends it. A throttled `appdetails` sometimes answers HTTP 200 with a literal `null` body; that is treated as throttling too.
- **`success: false` is normal.** It means the ID does not exist, or the app is not sold in the requested country. Those IDs go to `RUN_SUMMARY.unavailableAppIds` and the run continues.
- **Regional prices can be sparse.** A game withdrawn from one region simply has no entry for it in `regionalPrices`, rather than a row of nulls.
- **`metacriticScore` is often null.** Steam only carries it where Metacritic has a PC score; plenty of top sellers have none.
- **Public data only.** No authentication, no personal data, no access-control bypass.

### FAQ

**Do I need a proxy?** No. Proxy configuration is not required to run this Actor.

**Do I need a Steam API key?** No. You supply no credentials.

**Why is `priceFinal` null?** Either the title is free-to-play (`isFree: true`), or it is a bundle/package with no per-app price, or it is not sold in the country you asked for. Check `isFree` first.

**Are prices really in cents?** Steam returns minor units for every currency, including ones that have no minor unit. `initial: 877800` for JPY means ¥8,778. The Actor divides by 100 across the board, which is correct for all of them.

**Can I get review scores?** `recommendations` is Steam's total review count and `metacriticScore` is the critic score. The positive/negative split lives on a different endpoint and is not included.

**How do I pick a country code?** Any ISO 3166-1 alpha-2 code Steam sells in, `us`, `gb`, `de`, `fr`, `jp`, `br`, `in`, `ru`, `tr`, `au`. Note that some regions are billed in USD rather than a local currency; the `currency` field tells you which.

**Can I schedule it?** Yes, it is designed for scheduled runs. A 50-game watchlist across three regions is about 55 requests and finishes in under two minutes.

**Can I integrate it with something else?** Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.

# Actor input Schema

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

Numeric Steam app IDs. the number in the store URL (store.steampowered.com/app/1091500/Cyberpunk\_2077 → 1091500). Full store URLs are accepted and reduced to the ID. An ID that does not exist, or that is not sold in your chosen country, comes back as 'unavailable' in RUN\_SUMMARY rather than failing the run.

## `searchTerms` (type: `array`):

Resolve games by name through Steam's own store search when you do not have the app ID. The single best 'app' match per term is used and logged, so be specific. 'Half-Life 2' rather than 'half life'. Terms that match nothing are listed in RUN\_SUMMARY.unresolvedSearchTerms.

## `countryCodes` (type: `array`):

ISO 3166-1 alpha-2 codes driving regional pricing. 'us', 'de', 'jp', 'br', 'in', 'tr'. The first one also sets which store the full record is read from. Add more to get a price-comparison array on every game at one extra request per 50 games. Empty defaults to 'us'.

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

Steam language name (not a locale code) for descriptions, genre and category labels: 'english', 'german', 'french', 'japanese', 'schinese', 'brazilian'. An unknown value silently falls back to English. Note that 'releaseDateIso' is only filled when this is 'english'. Steam localises the date string.

## `includeFeatured` (type: `boolean`):

Append the app IDs Steam is currently promoting (specials, top sellers, new releases and coming soon) to whatever you asked for. This is applied automatically when you give no app IDs and no search terms, which is what makes an empty input useful.

## `maxApps` (type: `integer`):

Cap on games fetched in one run. Full records cost one request each and Steam throttles around 200 requests per 5 minutes, so the Actor paces them 1.5 s apart. budget roughly 40 games per minute against the 30-minute default timeout. Set 0 for no cap.

## Actor input object example

```json
{
  "appIds": [
    "1091500",
    "https://store.steampowered.com/app/730/CounterStrike_2/"
  ],
  "searchTerms": [
    "Baldur's Gate 3",
    "Hades II"
  ],
  "countryCodes": [
    "us",
    "de",
    "jp",
    "br"
  ],
  "language": "english",
  "includeFeatured": false,
  "maxApps": 50
}
```

# Actor output Schema

## `items` (type: `string`):

Every record the run produced.

## `runsummary` (type: `string`):

The RUN\_SUMMARY record from the run's key-value store.

# 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 = {
    "appIds": [
        "1091500",
        "570",
        "292030"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arman-bd/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 = { "appIds": [
        "1091500",
        "570",
        "292030",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("arman-bd/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 '{
  "appIds": [
    "1091500",
    "570",
    "292030"
  ]
}' |
apify call arman-bd/steam-store-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arman-bd/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/cE8Wbenu68l7PRf2k/builds/iDcAdkyOMoZyo1iLT/openapi.json
