# Steam Scraper - Game Prices, Reviews & Player Counts (`eiv/steam-scraper`) Actor

Any Steam game by app id or search term: price, discount, genres, developers, Metacritic, Steam's review rollup and the live player count. The same game priced on every storefront you list, each in its own currency. Individual reviews carry the playtime behind the verdict.

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

## Pricing

from $4.00 / 1,000 game scrapes

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 Game, Price & Review Scraper

Full store metadata for any Steam game, the **same game priced on every storefront you name**, live player counts, and reviews carrying **how long the author had played when they wrote it**.

```
Cyberpunk 2077      $59.99   87% of 973,115 reviews    31,294 playing   Metacritic 86
Counter-Strike 2      free   86% of 9,800,649         582,930 playing
Dota 2                free   81% of 2,760,382         433,500 playing

Cyberpunk 2077 on five storefronts
  us  USD    59.99      gb  GBP  49.99      de  EUR  59.99
  br  BRL   199.90      tr  USD  44.99   <- cheapest of the two USD storefronts

360 reviews   median playtime at review 5,679 minutes (95 hours)   5 written under an hour
```

**3 games and 360 reviews in 4.6 seconds**, over 24 requests and 1.0 MB — three app ids, five storefronts, 120 reviews each. No API key, no login, no browser. These are the storefront endpoints Steam serves to its own web pages.

***

### The same game, priced in five countries at once

Steam charges what each region will pay, and the gaps are not small. One game, one run:

| Storefront | Currency | Price |
|---|---|---|
| United States | USD | 59.99 |
| United Kingdom | GBP | 49.99 |
| Germany | EUR | 59.99 |
| Brazil | BRL | 199.90 |
| Turkey | USD | 44.99 |

Name the countries in `countries` and every one is read. The first is your home storefront and fills `price`, `currency` and `discountPercent`; the rest fill `regionalPrices`, each in its own currency.

**No rate is ever applied.** `cheapestCountry` and `dearestCountry` compare only storefronts quoting the same currency, and stay null when fewer than two of them do. The reason is in the table above: ranked by raw number, 199.90 BRL is the biggest figure on the page, so Brazil reads as the dearest storefront when it is about 37 dollars and genuinely the cheapest. Converting for you would mean picking a rate, and the rate would be wrong by the time you read it. You get every price, in the currency Steam quoted it, and the comparison is yours.

***

### A review is worth what the reviewer played

Every review carries `playtimeAtReviewMinutes`: minutes on the clock at the moment it was written, not today. Across 360 reviews in one run the median was **5,679 minutes, about 95 hours**, and **5 were written with under an hour played**.

That single field separates a verdict from a first impression, and nothing on the store page shows it to you. Sort on it and the reviews that survive are from people who finished the game. Filter the other way and you have the refund-window complaints, which is its own signal when you are watching a launch.

Beside it: `playtimeForeverMinutes` for what they have played since, `weightedVoteScore` (Steam's own usefulness weighting, the thing that orders the store page), `steamPurchase`, `receivedForFree`, `refunded`, `writtenDuringEarlyAccess`, `onSteamDeck`, and the author's library size and review count.

***

### What you get

**Per game** — `name`, `type`, `isFree`, `developers`, `publishers`, `genres`, `categories`, `releaseDate` + `daysSinceRelease` + `comingSoon`, `reviewScoreDesc`, `totalReviews` / `totalPositive` / `totalNegative` / **`positiveRate`**, `metacriticScore`, **`currentPlayers`**, `currency` / `price` / `initialPrice` / `discountPercent` / `onSale`, **`regionalPrices`** + `cheapestCountry` / `dearestCountry`, `platforms`, `achievements`, `dlcCount`, `requiredAge`, `controllerSupport`, `headerImage`, `website`, `storeUrl`, `shortDescription`, and the full description on request.

**Per review** — `review`, `language`, `votedUp`, `votesUp`, `votesFunny`, `weightedVoteScore`, `commentCount`, **`playtimeAtReviewMinutes`** and `playtimeForeverMinutes`, `steamPurchase`, `receivedForFree`, `refunded`, `writtenDuringEarlyAccess`, `onSteamDeck`, `createdAt` / `updatedAt`, `authorSteamId`, `authorGamesOwned`, `authorReviewCount`.

An app id Steam has no store page for gets its own row with `recordType: "app-error"` and an `errorCode`, so a gap in your list is visible rather than silent.

***

### Who this is for

- **Game developers watching competitors.** Player counts, review velocity and discount behaviour on the games you are shipping against, run daily and diffed.
- **Publishers setting regional prices.** What your catalogue and everyone else's actually costs in each territory, in the local currency, without a spreadsheet of guessed conversions.
- **Deal sites and price trackers.** `discountPercent`, `initialPrice` and `onSale` across every storefront you cover, on a schedule.
- **Market research and investment.** Genre mix, Metacritic, positive rate, concurrent players and review sentiment, joined on one row per game.
- **Anyone doing review analysis.** 360 reviews with playtime attached beats 360 star ratings.

***

### Input

```json
{
  "appIds": ["1091500", "730", "https://store.steampowered.com/app/570/Dota_2/"],
  "countries": ["us", "gb", "de", "br", "tr"],
  "includeReviews": true,
  "maxReviewsPerApp": 120,
  "includePlayerCount": true
}
```

That is the run at the top of this page: 3 games, 360 reviews, 5 storefronts, 4.6 seconds.

| Option | Default | Notes |
|---|---|---|
| `appIds` | — | The number or the store URL. `store.steampowered.com/app/730/` is 730 |
| `searchTerms` | — | Steam's own store search; returns ids, which are then read in full |
| `maxSearchResults` | `50` | Steam's search caps at 100 per term |
| `countries` | `["us"]` | Two-letter codes. **The first is the home storefront** and fills the top-level price |
| `includePlayerCount` | `true` | One extra call per game, about 65 ms |
| `includeReviews` | `false` | Off by default, because reviews are most of the payload |
| `maxReviewsPerApp` | `200` | 100 per page, so 120 costs two pages |
| `reviewLanguage` | `all` | Steam's own names: `english`, `schinese`, `brazilian` |
| `reviewFilter` | `recent` | `recent`, `updated` or `all` |
| `genres` / `keywords` | — | Substring, case-insensitive. Keywords also search developer and publisher |
| `freeOnly` / `onSaleOnly` | `false` | |
| `minPrice` / `maxPrice` | — | Home storefront. A floor drops unpriced games; a ceiling keeps them |
| `minMetacritic` | — | Unscored games are dropped by this, because no score is not a low score |
| `minPositiveRate` | — | `0.8` and `80` both mean 80 per cent |
| `releasedWithinDays` | — | Unreleased games are kept only where Steam says "coming soon" |
| `includeDescription` | `false` | Takes a game from 16 KB to 35 KB on the wire |
| `flattenOutput` | `false` | Dot-notation columns for CSV |
| `maxConcurrency` | `3` | Up to 8. See the rate limit note below |

***

### Eight things worth knowing

Each was found by running against live Steam.

**`appdetails` takes one app per request, and every batched form returns HTTP 400.** Passing several ids is widely documented and does not work: `appids=730,570` answers 400 with a country, without a country, with filters and without them. Confirmed again while writing this page. So there is no bulk query, one request per game is the floor, and every filter in this Actor runs after the fetch rather than inside a query that does not exist.

**The `basic` filter does not include developers or publishers.** Trimming the payload to the fields the record uses looked free and was not: `basic` is not the basics, and both fields came back empty on every game, with no error and no warning to say so. They are named explicitly now, along with price, Metacritic, genres, categories, platforms, achievements, release date and recommendations. Screenshots, movies and backgrounds stay out, which is what takes a game from 35 KB on the wire down to 16 KB.

**Prices are never converted between currencies, so cheapest and dearest only compare within one.** Ranking 44.99 USD against 199.90 BRL by raw number called Brazil the dearest storefront when it is about 37 dollars and actually the cheapest of the five. It is the same fault as taking a median across pounds and lei. Only storefronts sharing the home currency are ranked, and with fewer than two of them both fields stay null. In the five-country run above that left the United States against Turkey, which is how `cheapestCountry` came back as `tr`.

**A storefront can quote a currency that is not its own.** Turkey returns `USD 44.99`, not lira. That is Valve's pricing rather than a parsing slip, and it is the reason the comparison found anything at all in a run where three of the five countries quoted three different currencies. Read `regionalPrices[].currency` instead of assuming the country implies it.

**Free games carry no `price_overview` at all, so `price` is null and not zero.** Counter-Strike 2 and Dota 2 both come back with the field absent entirely. Writing zero would be an invention that reads as "this game costs nothing today", which is also what a 100 per cent discount looks like. `isFree` answers the question `price: 0` was pretending to.

**Steam repeats its review cursor at the end of the list.** The last page hands back the cursor you sent it, so the obvious loop asks for the same 100 reviews until it reaches your cap and then reports a full set of duplicates as a result. The loop stops when the cursor repeats, when a page is empty, or when a page contains nothing new, and review ids are deduplicated regardless.

**A delisted or non-existent app id answers `success: false` under HTTP 200.** App 999999999 returns a perfectly healthy response containing a refusal. It becomes an `app-error` row with `errorCode: "NOT_FOUND"` rather than an empty game record, because an empty game and a game that is not there are different answers and only one of them means your input was wrong.

**Steam writes release dates for humans.** "Dec 9, 2020" is a date; "Q1 2025", "Coming soon" and a bare year are not, and `Date.parse` turns the last three into 1 January, which is a fabrication with a timestamp on it. Only strings carrying an actual day become `releaseDate`. Everything else stays null, and `comingSoon` carries what Steam actually said.

***

### Output

```json
{
  "recordType": "game",
  "appId": "1091500",
  "name": "Cyberpunk 2077",
  "developers": ["CD PROJEKT RED"],
  "genres": ["RPG"],
  "releaseDate": "2020-12-09T00:00:00.000Z",
  "daysSinceRelease": 2079,
  "reviewScoreDesc": "Very Positive",
  "totalReviews": 973115,
  "positiveRate": 0.8681,
  "metacriticScore": 86,
  "currentPlayers": 31294,
  "currency": "USD", "price": 59.99, "discountPercent": 0, "onSale": false,
  "regionalPrices": [
    { "country": "us", "currency": "USD", "price": 59.99 },
    { "country": "gb", "currency": "GBP", "price": 49.99 },
    { "country": "de", "currency": "EUR", "price": 59.99 },
    { "country": "br", "currency": "BRL", "price": 199.90 },
    { "country": "tr", "currency": "USD", "price": 44.99 }
  ],
  "cheapestCountry": "tr",
  "dearestCountry": "us"
}
```

```json
{
  "recordType": "review",
  "appId": "570",
  "gameName": "Dota 2",
  "reviewId": "233175787",
  "language": "russian",
  "votedUp": false,
  "weightedVoteScore": 0.5,
  "steamPurchase": true,
  "refunded": false,
  "playtimeAtReviewMinutes": 12,
  "playtimeForeverMinutes": 12,
  "authorGamesOwned": 1430,
  "createdAt": "2026-08-19T06:07:52.000Z"
}
```

Set `flattenOutput: true` for CSV: arrays become pipe-delimited strings, `regionalPrices` becomes a count plus a JSON column.

***

### Honest limits

- **Steam only.** No Epic, GOG, itch or console storefronts. A price comparison here is across Steam's own regions, not across shops.
- **There is no "every game on Steam" query.** You supply ids or search terms, and a search term returns at most 100 ids. A run is as long as its list.
- **Steam publishes no sales, revenue or owner counts**, and this Actor does not estimate them. `currentPlayers` is concurrent players right now, which is a real measurement and not a stand-in for units sold.
- **No currency conversion, anywhere.** `cheapestCountry` and `dearestCountry` are null unless at least two storefronts quote the same currency, and they rank only those. Everything else sits in `regionalPrices` for you to convert with a rate you trust.
- **A storefront that does not sell a game answers successfully with no price.** That is recorded as a null price for that country rather than dropped, so a gap in availability stays visible.
- **The rollup is Steam's, over every review the game has**; the reviews you receive are a sample, most recent first by default. `totalReviews` and `positiveRate` describe the whole population, `maxReviewsPerApp` describes your slice, and the two should not be read as the same thing.
- **Reviews are ordered, not sampled at random.** `reviewFilter` changes which end of the list you get. It does not remove the bias, it chooses it.
- **Metacritic is absent on plenty of good games.** Counter-Strike 2 has no score at all. `minMetacritic` therefore drops unscored games, which is deliberate and the reason it is off by default.
- **Player counts are not published for every app.** Null means Steam reported none, not that nobody is playing.
- **Only real dates become `releaseDate`.** A quarter or a bare year stays null rather than becoming 1 January.
- **Steam is documented at roughly 200 requests per five minutes.** Twenty-five sequential calls produced zero failures, but a long run at `maxConcurrency: 8` will find the ceiling. The Actor keeps a 250 ms gap between calls for one app and reports an HTTP 429 plainly if one arrives.
- **Games your filters removed, and app ids Steam has no page for, are never charged.**

***

### Pricing

| Event | Price | When |
|---|---|---|
| Actor start | $0.005 | Once per run |
| Game scraped | $0.004 | Per game returned after filtering, including every storefront price, the player count and the review rollup |
| Review scraped | $0.0004 | Per review returned |

**$4 per 1,000 games and $0.40 per 1,000 reviews.** The run at the top of this page, 3 games with 120 reviews each, costs **$0.161**. A daily watch on 20 competitor titles across five storefronts with reviews off is **$0.085 a run**. Full working in [docs/PRICING.md](docs/PRICING.md).

***

### Tips

- **Run daily and diff on `currentPlayers` and `totalReviews`.** A review count climbing faster than usual is a launch, a sale or a controversy, and the reviews themselves tell you which.
- **Leave `includeReviews` off when you only want prices.** Reviews are most of the payload and most of the bill.
- **Sort reviews on `playtimeAtReviewMinutes` before reading any of them.** The median in one run was 95 hours, so the half below it includes people reviewing on a demo's worth of play.
- **Put your own market first in `countries`.** The first entry fills `price` and `currency`, so the top-level fields are the ones you care about and the rest sit in `regionalPrices`.
- **Use `searchTerms` to discover and `appIds` to monitor.** Search once to find the competitors, then pin the ids so tomorrow's run reads the same games.
- **`onSaleOnly: true` across a watchlist is a discount alert** in one field, with `initialPrice` beside it so you can see how deep it goes.

# Actor input Schema

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

Steam app ids, one per line. 1091500 is Cyberpunk 2077, 730 is Counter-Strike 2. Paste the whole store URL if you prefer — store.steampowered.com/app/730/ is reduced to 730 for you. Anything that is neither a number nor a store URL is dropped with a warning. Steam answers appdetails for one app per request and rejects a batch of ids with HTTP 400, so a long list is a long run, not a single call.

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

Phrases to put through the Steam store search, e.g. 'roguelike deckbuilder'. Every app id the search returns is then read in full, the same as an id you typed. The store ranks by its own relevance and answers with what it chooses to; this is a discovery aid, not an exhaustive catalogue query.

## `maxSearchResults` (type: `integer`):

Cap on the app ids taken from each search term. Steam's search page returns at most 100 per call, so a higher number is trimmed to 100.

## `countries` (type: `array`):

Two-letter storefront codes. The first is the home storefront: it supplies the full record and the top-level price, currency and discount fields. The rest are asked for price only and land in regionalPrices. Regional pricing is real — the same game measured $59.99 in us, GBP 49.99 in gb, EUR 59.99 in de, BRL 199.90 in br and $44.99 in tr. Nothing is converted between currencies, so cheapestCountry and dearestCountry are worked out only among storefronts quoting the home currency; comparing across currencies is left to you and a rate you trust. Each extra storefront is one more request per game.

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

Adds currentPlayers, read live from Steam's own counter. One keyless request of about 65ms per game. Some apps report nothing, and those come back null rather than 0 — no answer is not the same as an empty server.

## `includeReviews` (type: `boolean`):

Off by default. Steam's review rollup — score description, totals, positive rate — is on every game record either way; this adds one row per review on top. Reviews page 100 at a time by cursor, so 500 reviews means five extra requests and roughly 450 KB for that game.

## `maxReviewsPerApp` (type: `integer`):

Ceiling per game, reached a page of 100 at a time. Ignored unless reviews are switched on. Paging stops when Steam repeats its cursor, so a game with fewer reviews than the cap simply returns what it has.

## `reviewLanguage` (type: `string`):

A Steam language name such as english, russian or schinese, or all. This narrows which reviews come back. It does not change totalReviews or positiveRate, which stay game-wide — the count for the language you asked for is reported separately as reviewsInLanguage.

## `reviewFilter` (type: `string`):

recent is newest first, all is Steam’s own usefulness order, updated is recently edited. This decides whether weightedVoteScore means anything: on recent the reviews are minutes old with no votes, so Steam returns a flat 0.5 for every one of them, while all gave 78 distinct weights across 100 reviews of the same game. Use all if you want to rank by how useful other players found a review.

## `genres` (type: `array`):

Keep only games carrying one of these genres. Matched case-insensitively and as a substring, so 'rpg' catches 'RPG' and 'action' catches 'Action-Adventure'. Any one matching is enough.

## `keywords` (type: `array`):

Any one matching is enough. Searched in the name, the short description, the genre and category lists, and the developer and publisher names. Not the long description, which is only fetched when you ask for it.

## `freeOnly` (type: `boolean`):

Keep only games Steam flags as free to play. Free games carry no price block at all — CS2 and Dota 2 return nothing where the price would be — so their price, currency and discount fields are null, not zero.

## `onSaleOnly` (type: `boolean`):

Keep only games discounted right now on the home storefront. A game on sale in another region but not at home is dropped, because the top-level discount is the home storefront's.

## `minPrice` (type: `number`):

In the home storefront's own currency, in units rather than cents: 19.99, not 1999. No conversion is applied anywhere, so a floor of 20 means 20 dollars on a us run and 20 pounds on a gb one. Free and unreleased games have no price and are dropped by a floor, because a price floor is a question only a priced game can answer.

## `maxPrice` (type: `number`):

Same units, and the same currency caveat as the floor. Unlike the floor this keeps unpriced games: a free game satisfies any budget. A ceiling below the floor is ignored with a warning rather than quietly returning nothing.

## `minMetacritic` (type: `integer`):

0 to 100. This drops every game with no Metacritic score, which is most of Steam — plenty of well-regarded games were never scored there. Leave it empty and use the positive review rate instead if you want a quality floor that does not throw the unscored away.

## `minPositiveRate` (type: `number`):

The share of Steam reviews that are positive — the number the store badge is built from. Give a rate (0.85) or a percentage (85); anything above 1 is read as a percentage. A game with no reviews has no rate and is dropped by this.

## `releasedWithinDays` (type: `integer`):

Drop anything released longer ago than this. Games marked 'coming soon' are kept, because an unreleased game is not an old one. Steam writes some release dates for humans ('Q1 2025', 'Coming soon'); those are left null rather than guessed into 1 January, and games carrying one are kept.

## `includeDescription` (type: `boolean`):

Adds the long store description with the HTML stripped out, and lifts the field filter on appdetails so the fetch goes from 6-15 KB to 15-34 KB per game. Be aware how little some of it is worth: Steam’s detailed\_description is marketing HTML, and for the biggest games it is almost entirely images. Stripped, Cyberpunk 2077 yields 47 characters and The Witcher 3 yields 55, against 3,750 for Stardew Valley and 2,933 for GTA V. The short description is included either way and is a real sentence every time.

## `flattenOutput` (type: `boolean`):

Emit flat dot-notation columns instead of nested objects. It mainly affects regionalPrices, which is otherwise one object per storefront.

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

Games read in parallel. Each game is several requests — one per storefront, one per page of reviews, one for the player count — with a 250ms gap between the calls belonging to one game. 25 sequential requests drew no complaint from Steam, which is documented at roughly 200 requests per 5 minutes; three at a time keeps a long run inside that.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout. A page of 100 reviews is about 90 KB, so the default is generous for everything except a congested proxy.

## `maxRetries` (type: `integer`):

Retries for connection resets and 5xx responses. An HTTP 429 is not retried into the ground: that game is reported with errorCode HTTP\_429 so you can lower the concurrency and run it again.

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

Optional. Steam's store endpoints need no key and did not block a direct run. Worth adding for a long list, or when your own address is already being rate limited. A proxy exit in another country does not change which storefront answers — that is what the storefront list is for.

## Actor input object example

```json
{
  "appIds": [
    "1091500",
    "730"
  ],
  "maxSearchResults": 50,
  "countries": [
    "us",
    "gb",
    "de"
  ],
  "includePlayerCount": true,
  "includeReviews": false,
  "maxReviewsPerApp": 200,
  "reviewLanguage": "all",
  "reviewFilter": "recent",
  "freeOnly": false,
  "onSaleOnly": false,
  "includeDescription": false,
  "flattenOutput": false,
  "maxConcurrency": 3,
  "requestTimeoutSecs": 60,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Game records carry recordType 'game'; reviews carry 'review'; ids with no store page carry 'app-error'.

# 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",
        "730"
    ],
    "countries": [
        "us",
        "gb",
        "de"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eiv/steam-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",
        "730",
    ],
    "countries": [
        "us",
        "gb",
        "de",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("eiv/steam-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",
    "730"
  ],
  "countries": [
    "us",
    "gb",
    "de"
  ]
}' |
apify call eiv/steam-scraper --silent --output-dataset

```

## MCP server setup

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