# Steam Reviews Scraper & Monitor (by language) (`panda_studio/steam-reviews-monitor`) Actor

Scrape Steam reviews for any game in 30 languages. Per-language score breakdown and a monitor mode that returns only new reviews. No login, no API key, no proxies.

- **URL**: https://apify.com/panda\_studio/steam-reviews-monitor.md
- **Developed by:** [panda studio](https://apify.com/panda_studio) (community)
- **Categories:** Games, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 reviews

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

## Steam Reviews Scraper & Monitor (by language)

**Steam Reviews Scraper** downloads Steam user reviews for any game — review text, recommended/not recommended, playtime, helpfulness votes, Steam Deck and early-access flags — in any of Steam's 30 review languages. It also builds a **per-language score breakdown** (total, positive, negative, positive % and Steam's score label for every language) and has a **monitor mode** that returns only the reviews posted since your last run. It uses Valve's public review endpoint: no login, no Steam API key, no proxies.

### What does Steam Reviews Scraper do?

- Takes one or more games as **Steam store URLs or app IDs** (`https://store.steampowered.com/app/1245620/ELDEN_RING/` or `1245620`).
- Downloads reviews **newest first** for the languages you choose (`english`, `japanese`, `schinese`, `koreana`, `brazilian`, ... or `all`).
- Optionally adds one **language summary row per language** so you can compare how each localization is received.
- In **monitor mode**, remembers the newest review it has seen per game and language, and on the next run returns only newer reviews.
- Writes everything to an Apify dataset you can export as JSON, CSV, Excel or HTML, or send to Slack, Google Sheets, Make, Zapier or a webhook.

### Who is it for? Use cases

| Who | What they do with it |
|---|---|
| **Game developers & publishers** | Schedule monitor mode on your own game and get new (especially negative) reviews in Slack after a patch or a sale. |
| **Localization teams** | Compare the positive ratio per language. Real example from a run on 2026-09-24: ELDEN RING is 93.9% positive in English but 75.6% in Japanese. |
| **Community managers** | Read every new review in the languages your team covers. |
| **Market & competitor research** | Pull reviews of competing titles and feed them to an LLM to extract complaints and feature requests. |
| **Streamers & content creators** | Check how a game is received in your audience's language before covering it. |

### Why use this Steam reviews scraper?

- **Per-language score breakdown** — one row per language with total / positive / negative / positive ratio / Steam's label ("Very Positive", "Mostly Positive", ...) / share of all reviews. Steam's store page only shows the overall score and your own language.
- **Monitor mode** — returns only reviews posted since the previous run. The state is kept in a named key-value store in your own Apify account.
- **Privacy-safe by default** — reviewer SteamID, persona name and profile URL are *not* collected unless you turn on `includeAuthorIdentity`.
- **Language shortcuts** — `ja`, `jp`, `日本語`, `en`, `zh`, `ko`, `pt-br`, `es`, `de`, `fr`, `ru` are accepted as well as Steam's own codes.
- **Cost cap respected** — if you set *Maximum cost per run*, the Actor stops cleanly before exceeding it.
- **No proxy, no browser** — lightweight JSON requests only, 256 MB memory by default.

### What data do you get?

Review rows (`type: "review"`):

| Field | Description |
|---|---|
| `appId`, `appName` | Steam app ID and game name |
| `reviewId` | Steam recommendation ID |
| `language`, `languageName` | Language the reviewer selected on Steam |
| `votedUp` | `true` = recommended, `false` = not recommended |
| `text` | Review text |
| `votesUp`, `votesFunny`, `helpfulnessScore`, `commentCount` | Community reactions |
| `playtimeAtReviewHours`, `playtimeForeverHours` | Playtime when the review was written and in total (hours) |
| `steamPurchase`, `receivedForFree`, `writtenDuringEarlyAccess`, `primarilySteamDeck` | Purchase and context flags |
| `authorGamesOwned`, `authorReviewCount` | Reviewer's library size and number of reviews (no identity) |
| `developerResponse` | Developer's reply, if any |
| `createdAt`, `updatedAt`, `scrapedAt` | ISO 8601 timestamps (UTC) |
| `changeType` | `"new"` in monitor mode |
| `authorSteamId`, `authorName`, `reviewUrl` | Only when `includeAuthorIdentity` is on |

Language summary rows (`type: "languageSummary"`): `language`, `languageName`, `totalReviews`, `positive`, `negative`, `positiveRatio`, `reviewScoreDesc`, `shareOfAllReviews`. Only languages with at least one review are listed (up to 30 rows per game).

The dataset has two views in the Console: **Reviews** and **Language breakdown**. A `RUN_SUMMARY` record in the default key-value store lists per-game counts and errors.

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

Pay per event. Platform usage is included — you only pay these events:

| Event | Price |
|---|---|
| Actor start | $0.00005 per run |
| Game checked (each game fetched successfully in a run) | $0.001 |
| Result (each review or language-summary row in the dataset) | $0.0008 ($0.80 per 1,000) |

Worked examples (calculated from the prices above):

| Scenario | Rows | Cost |
|---|---|---|
| 1 game, latest 100 reviews | 100 | $0.081 |
| 1 game, 1,000 reviews + language breakdown (30 languages) | 1,030 | $0.825 |
| 10 games × 500 reviews | 5,000 | $4.01 |
| Monitor 20 games once a day, a day with no new reviews | 0 | $0.020 per run (≈ $0.60 / 30 days) plus $0.0008 per new review |

Set **Maximum cost per run** in the run options to cap spending.

### How to scrape Steam reviews

1. Open the Actor and click **Try for free** (an Apify account is free).
2. Paste one or more Steam store URLs or app IDs into **Games**.
3. Pick languages (or leave `all`), set **Max reviews per game**, and optionally **Only reviews from the last N days**, **Review type** or **Purchase type**.
4. Turn on **Add per-language score breakdown** if you want the summary rows.
5. Click **Start**, then download the dataset as JSON, CSV or Excel.
6. For alerts: turn on **Monitor mode**, save the input as a Task, add a **Schedule** (e.g. hourly) and an **Integration** (Slack, email, webhook).

### Input example

```json
{
  "games": ["https://store.steampowered.com/app/1245620/ELDEN_RING/", "413150"],
  "languages": ["english", "japanese"],
  "maxReviewsPerGame": 500,
  "daysBack": 0,
  "reviewType": "all",
  "purchaseType": "all",
  "languageSummary": true,
  "monitorMode": false
}
```

| Input | Default | Notes |
|---|---|---|
| `games` | — (required) | Store URLs or app IDs |
| `languages` | `["all"]` | Steam language codes or the shortcuts above |
| `maxReviewsPerGame` | 500 | Shared across the selected languages, filled in the order you list them. 0 = no limit (big games have 1M+ reviews) |
| `daysBack` | 0 | Only reviews from the last N days (0 = no limit) |
| `reviewType` | `all` | `all`, `positive`, `negative` |
| `purchaseType` | `all` | `all`, `steam`, `non_steam_purchase` |
| `languageSummary` | false | Adds the per-language rows |
| `monitorMode` / `monitorId` | false / — | Only new reviews since the last run |
| `includeAuthorIdentity` | false | Adds SteamID, name and review URL |
| `requestIntervalSecs` | 1 | Pause between requests (0.5–10 s) |

### Output example

Real output from a run on 2026-09-24 with the input above (`maxReviewsPerGame: 3`).

A review row:

```json
{
  "type": "review",
  "appId": 1245620,
  "appName": "ELDEN RING",
  "reviewId": "236042749",
  "language": "english",
  "languageName": "English",
  "votedUp": true,
  "text": "Best game since skyrim 2011 nothing can compare to it even now in 2026",
  "votesUp": 0,
  "votesFunny": 0,
  "helpfulnessScore": 0.5,
  "commentCount": 0,
  "steamPurchase": true,
  "receivedForFree": false,
  "writtenDuringEarlyAccess": false,
  "primarilySteamDeck": false,
  "playtimeAtReviewHours": 2.1,
  "playtimeForeverHours": 2.1,
  "authorGamesOwned": 0,
  "authorReviewCount": 14,
  "developerResponse": null,
  "createdAt": "2026-09-24T13:04:56+00:00",
  "updatedAt": "2026-09-24T13:04:56+00:00",
  "scrapedAt": "2026-09-24T14:18:52+00:00"
}
```

Language summary rows from the same run:

```json
[
  {"type": "languageSummary", "appId": 1245620, "appName": "ELDEN RING", "language": "english", "languageName": "English",
   "totalReviews": 572456, "positive": 537582, "negative": 34874, "positiveRatio": 0.9391,
   "reviewScoreDesc": "Very Positive", "shareOfAllReviews": 0.4951, "scrapedAt": "2026-09-24T14:18:52+00:00"},
  {"type": "languageSummary", "appId": 1245620, "appName": "ELDEN RING", "language": "schinese", "languageName": "Chinese (Simplified)",
   "totalReviews": 250435, "positive": 227064, "negative": 23371, "positiveRatio": 0.9067,
   "reviewScoreDesc": "Very Positive", "shareOfAllReviews": 0.2166, "scrapedAt": "2026-09-24T14:18:52+00:00"},
  {"type": "languageSummary", "appId": 1245620, "appName": "ELDEN RING", "language": "japanese", "languageName": "Japanese",
   "totalReviews": 6014, "positive": 4548, "negative": 1466, "positiveRatio": 0.7562,
   "reviewScoreDesc": "Mostly Positive", "shareOfAllReviews": 0.0052, "scrapedAt": "2026-09-24T14:18:52+00:00"}
]
```

### Monitor mode (new Steam reviews only)

1. Turn on `monitorMode` (optionally set a `monitorId` to name the watch list).
2. The first run fetches up to `maxReviewsPerGame` newest reviews and remembers the newest review timestamp per game and language.
3. Every later run returns only reviews written after that, marked `changeType: "new"`. If nothing new was posted, the dataset is empty and you pay only the start and game-checked events.
4. Add a schedule and an integration (Slack, email, Google Sheets, webhook, Make, Zapier).

The state is stored in a named key-value store in your own Apify account. Changing the games or languages (without a `monitorId`) starts a new watch list.

### Tips

- Start with `maxReviewsPerGame: 100` to check the output before large runs.
- List languages in priority order — the per-game limit is filled in that order.
- Use `daysBack` for "reviews since the last patch" pulls.
- The language breakdown needs about 30 small requests per game (one per language); turn it off if you only need review text.
- Use `reviewType: "negative"` with monitor mode for a complaints-only alert feed.

### Integrations & API usage

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("panda_studio/steam-reviews-monitor").call(run_input={
    "games": ["1245620"],
    "languages": ["english", "japanese"],
    "maxReviewsPerGame": 200,
    "languageSummary": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["type"], item.get("text") or item.get("positiveRatio"))
```

Node.js:

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('panda_studio/steam-reviews-monitor').call({
    games: ['1245620'],
    languages: ['english'],
    maxReviewsPerGame: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

cURL (run and get the items in one call):

```bash
curl -X POST "https://api.apify.com/v2/acts/panda_studio~steam-reviews-monitor/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"games": ["1245620"], "languages": ["english"], "maxReviewsPerGame": 50}'
```

MCP (Claude, Cursor, VS Code and other AI agents): add the Apify MCP server with this Actor as a tool:

```json
{
  "mcpServers": {
    "apify": { "url": "https://mcp.apify.com?tools=panda_studio/steam-reviews-monitor" }
  }
}
```

### Is it legal to scrape Steam reviews?

This Actor reads the same public reviews anyone can see on the Steam store, through the review endpoint that Valve documents for developers (`store.steampowered.com/appreviews/<appid>?json=1`, "Getting user reviews" in the Steamworks documentation). The path is allowed by Steam's robots.txt, no login is used, and requests are spaced (1 s by default, with back-off on HTTP 429). Reviewer identity is not collected unless you enable it. You are responsible for how you use the data — for example, check your local privacy law before storing reviewer identities.

### FAQ

**How many reviews can I get?** As many as Steam serves through the endpoint, newest first, 100 per request. Popular games have hundreds of thousands per language, so set `maxReviewsPerGame` or `daysBack`.

**Do I need a Steam API key or account?** No.

**Can I search by game name?** Not yet — use the store URL or app ID (the number in the store URL).

**Why is there no reviewer name?** Privacy by default. Turn on `includeAuthorIdentity` if you have a legitimate need, e.g. replying to reviews of your own game.

**Is the review language reliable?** It is the language the reviewer selected on Steam, the same one Steam uses for its own language filter.

**Are the language-summary rows charged?** Yes, each row is one result ($0.0008), so a full breakdown is at most 30 rows ≈ $0.024 per game.

**What happens if an input is wrong?** An entry that is not an app ID or store URL, or a game Steam returns an error for, is listed under `errors` in `RUN_SUMMARY`; the other games still run. A valid-looking ID with no reviews simply returns 0 reviews.

**Can I get reviews between two exact dates?** You can limit to the last N days with `daysBack`. Arbitrary date windows are not supported.

### Changelog

- 0.1 — Initial release: multiple games, 30 languages, per-language breakdown, monitor mode, privacy-safe defaults, cost-cap aware stopping.

# Actor input Schema

## `games` (type: `array`):

One per line, e.g. <code>https://store.steampowered.com/app/1245620/ELDEN\_RING/</code> or just <code>1245620</code>.

## `languages` (type: `array`):

Steam language codes: <code>all</code>, <code>english</code>, <code>japanese</code>, <code>schinese</code>, <code>tchinese</code>, <code>koreana</code>, <code>russian</code>, <code>brazilian</code>, <code>spanish</code>, <code>latam</code>, <code>german</code>, <code>french</code>, ... (30 supported). Short aliases like <code>ja</code>, <code>en</code>, <code>zh</code>, <code>ko</code> also work.

## `maxReviewsPerGame` (type: `integer`):

Newest reviews first. 0 = no limit (big games have 1M+ reviews - set a limit!).

## `daysBack` (type: `integer`):

0 = no date limit.

## `reviewType` (type: `string`):

Filter by recommendation.

## `purchaseType` (type: `string`):

Filter by how the reviewer got the game.

## `languageSummary` (type: `boolean`):

Adds one <code>languageSummary</code> row per language that has reviews: total, positive, negative, positive ratio, Steam score label and share of all reviews. Ideal for deciding which localization to invest in, or checking how a translation is received.

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

Remembers the newest review seen per game and language (named key-value store in your account). Later runs return only newer reviews. Schedule it hourly/daily and pipe to Slack or a sheet.

## `monitorId` (type: `string`):

Runs with the same Monitor ID share memory. Empty = derived from games + languages.

## `includeAuthorIdentity` (type: `boolean`):

Off by default for privacy (GDPR-friendly). Playtime and review stats are always included.

## `requestIntervalSecs` (type: `number`):

Politeness delay; Steam rate-limits aggressive clients. Minimum 0.5.

## Actor input object example

```json
{
  "games": [
    "https://store.steampowered.com/app/1245620/ELDEN_RING/"
  ],
  "languages": [
    "all"
  ],
  "maxReviewsPerGame": 500,
  "daysBack": 0,
  "reviewType": "all",
  "purchaseType": "all",
  "languageSummary": false,
  "monitorMode": false,
  "includeAuthorIdentity": false,
  "requestIntervalSecs": 1
}
```

# Actor output Schema

## `reviews` (type: `string`):

No description

## `runSummary` (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 = {
    "games": [
        "https://store.steampowered.com/app/1245620/ELDEN_RING/"
    ],
    "languages": [
        "all"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("panda_studio/steam-reviews-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 = {
    "games": ["https://store.steampowered.com/app/1245620/ELDEN_RING/"],
    "languages": ["all"],
}

# Run the Actor and wait for it to finish
run = client.actor("panda_studio/steam-reviews-monitor").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 '{
  "games": [
    "https://store.steampowered.com/app/1245620/ELDEN_RING/"
  ],
  "languages": [
    "all"
  ]
}' |
apify call panda_studio/steam-reviews-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,panda_studio/steam-reviews-monitor"
        }
    }
}
```

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/fyzE0rhguPp3zfL6a/builds/EMOvjlPPkdJ3FLtVZ/openapi.json
