# Steam Reviews Scraper (`huggable_quote/steam-reviews-scraper`) Actor

Collect public Steam reviews from multiple games with language, sentiment, and date filters-without exposing reviewer identities.

- **URL**: https://apify.com/huggable\_quote/steam-reviews-scraper.md
- **Developed by:** [OrbitData Labs](https://apify.com/huggable_quote) (community)
- **Categories:** Games
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

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 Reviews Scraper

**Privacy-first bulk Steam review collection with predictable cost controls.**

Collect public Steam reviews from one or many games using app IDs or Steam Store URLs. Filter by language, recommendation type, sorting, and date range, set a hard result or cost limit, and export clean review, game-summary, and error records from one run. No login, no Steam API key, no browser, and no proxy by default. You are charged only for successfully stored results — never for failed runs, error records or skipped duplicates. A game with zero matching reviews stores (and charges) only its summary record, if enabled — the summary itself carries the rating data.

### Why this scraper

- **Full date-range filter** — `dateFrom`/`dateTo` work on the newest-first walk with inclusive day bounds, so "reviews between the last two updates" is a first-class query.
- **Multi-game batches** — mix store URLs and app IDs in one run; one failing game never kills the others (it becomes an `error` record instead).
- **Privacy-minimal by default** — no author Steam ID, username, profile URL, avatar or status is ever output. Anonymous statistics (playtime, games owned) are kept, and can be disabled too.
- **Honest billing** — no actor-start fee; per-review and per-summary events are charged only after the record is stored in the dataset.

### Input

| Field | Default | Notes |
|---|---|---|
| `games` (required) | — | Steam store URLs (`https://store.steampowered.com/app/1245620/...`) or app IDs (`"1245620"`), mixed freely |
| `maxReviewsPerGame` | `1000` | per-game cap |
| `maxTotalReviews` | `10000` | whole-run cap |
| `languages` | `["all"]` | Steam language codes (`english`, `koreana`, `japanese`, …) |
| `reviewType` | `all` | `all` / `positive` / `negative` |
| `sortBy` | `recent` | `recent` (newest first) or `helpful` |
| `dateFrom`, `dateTo` | — | `YYYY-MM-DD`, UTC, both inclusive. Requires `sortBy: "recent"` |
| `purchaseType` | `all` | `all` / `steam` / `non_steam_purchase` |
| `includeGameSummary` | `true` | one `game_summary` record per game |
| `includePlaytimeStats` | `true` | anonymous reviewer statistics on each review |
| `debugLog` | `false` | one diagnostic log line per fetched page (anonymized cursor hashes) |
| `proxyConfiguration` | off | Steam usually needs no proxy; enable datacenter proxies only if you see blocking |

#### Example 1 — simplest possible run

```json
{ "games": ["https://store.steampowered.com/app/1245620/ELDEN_RING/"] }
```

#### Example 2 — multiple games, negative Korean/English reviews only

```json
{
  "games": ["1245620", "570"],
  "languages": ["english", "koreana"],
  "reviewType": "negative",
  "maxReviewsPerGame": 500
}
```

#### Example 3 — reviews between two game updates

```json
{
  "games": ["1245620"],
  "sortBy": "recent",
  "dateFrom": "2026-06-01",
  "dateTo": "2026-06-30"
}
```

#### Example 4 — daily rating tracking with minimal review collection

```json
{
  "games": ["1245620", "570", "730"],
  "maxReviewsPerGame": 1,
  "includeGameSummary": true
}
```

You pay for 1 review + 1 summary per game and get each game's current review score, totals and positive/negative counts in the `game_summary` records.

### Output

All records go to the default dataset with a `recordType` discriminator: `review`, `game_summary`, `error`. To export only reviews as CSV, filter `recordType = review` in the export dialog (or in your integration).

#### `review` record (flat, CSV-friendly)

```json
{
  "recordType": "review",
  "appId": 1245620,
  "gameName": "ELDEN RING",
  "reviewId": "1234500001",
  "reviewText": "Synthetic sample review written for this documentation — it does not quote any real Steam user.",
  "language": "english",
  "votedUp": true,
  "votesUp": 12,
  "votesFunny": 0,
  "weightedVoteScore": 0.65,
  "commentCount": 0,
  "steamPurchase": true,
  "receivedForFree": false,
  "writtenDuringEarlyAccess": false,
  "refunded": false,
  "primarilySteamDeck": false,
  "createdAt": "2026-08-22T09:15:14.000Z",
  "updatedAt": null,
  "developerResponse": null,
  "developerRespondedAt": null,
  "playtimeForeverMinutes": 8123,
  "playtimeAtReviewMinutes": 6210,
  "playtimeLast2WeeksMinutes": 340,
  "lastPlayedAt": "2026-08-20T18:02:11.000Z",
  "authorNumGamesOwned": 42,
  "authorNumReviews": 7
}
```

#### `game_summary` record

Per game: `reviewScore`, `reviewScoreDesc`, `totalReviews`, `totalPositive`, `totalNegative` (as reported by Steam **for your applied filters** — a `languages` filter changes the totals), plus `collectedReviews`, `duplicatesSkipped`, `stoppedReason` and the filters used.

#### `error` record

Per failed input: `errorType` (`INVALID_INPUT`, `NOT_FOUND_OR_UNAVAILABLE`, `BLOCKED`, `HTTP_ERROR`), `message`, `httpStatus`. Error records are **never charged**.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Review stored | $0.00065 |
| Game summary stored | $0.002 |
| Actor start | **free** |

Reviews cost $0.00065 each and stored game summaries cost $0.002 each. There is no start fee. Empty results and error records are not charged.

| Run | Cost |
|---|---:|
| 100 reviews + 1 summary | $0.067 |
| 1,000 reviews + 1 summary | $0.652 |
| 10,000 reviews + 1 summary | $6.502 |
| 100,000 reviews + 1 summary | $65.002 |
| 10 games x 1,000 reviews + 10 summaries | $6.52 |

Upper bound for any run: `maxTotalReviews x $0.00065 + games x $0.002`.

Set a **maximum cost per run** in the Apify UI; the actor stops gracefully at the limit and reports exactly how many results were stored and charged. If storage and billing ever disagree, the run reports an explicit `WARNING` in its status — never a silent success.

### FAQ

**Why is there no author information?**
This Actor intentionally excludes direct reviewer identifiers such as Steam ID, persona name, profile URL, avatar, and persona status. Public non-identifying review statistics, including playtime and purchase flags, may still be included when Steam returns them. `reviewId` is the review's own public identifier (needed for deduplication); it is not an author identifier, though the review it points to is public on Steam.

**What do the summary totals mean?**
They are Steam's totals for your applied filters at scrape time — e.g. with `languages: ["koreana"]` you get Korean-review totals.

**Are review bombs included?**
Yes — off-topic review activity is included (`filter_offtopic_activity=0`), because complete data matters for analysis. Deduplication is by `reviewId`.

**Which games work?**
Anything with public reviews — including delisted games that still have review pages (their `gameName` may be `null`). Age-gated games work without cookies. Invalid IDs and games with no data produce `error` records, not charges.

**Limits & fairness**
Requests are rate-limited (~2.5 req/s max) with exponential backoff on errors; sustained blocking aborts the run gracefully with everything collected so far intact. You are responsible for complying with Steam's Terms of Service, GDPR and applicable laws when using extracted data.

# Actor input Schema

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

One or more Steam store URLs (https://store.steampowered.com/app/1245620/...) or numeric app IDs ("1245620"). Invalid entries produce error records instead of failing the run.

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

Maximum number of reviews collected per game.

## `maxTotalReviews` (type: `integer`):

Maximum number of reviews collected across all games in one run.

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

Steam language codes (e.g. english, koreana, japanese) or \["all"].

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

Collect all, only positive, or only negative reviews.

## `sortBy` (type: `string`):

recent = newest first (required for date filtering). helpful = most helpful first.

## `dateFrom` (type: `string`):

Only reviews created on or after this date. Requires sortBy=recent.

## `dateTo` (type: `string`):

Only reviews created on or before this date. Requires sortBy=recent.

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

Filter by how the reviewer obtained the game.

## `includeGameSummary` (type: `boolean`):

Adds a game\_summary record with review score, totals and collection stats.

## `includePlaytimeStats` (type: `boolean`):

Playtime and games-owned statistics without any author identity fields.

## `debugLog` (type: `boolean`):

Logs one line per fetched review page (counts and anonymized cursor hashes). For troubleshooting only.

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

Optional. Steam works without proxies from most environments; enable datacenter proxies only if you see blocking.

## Actor input object example

```json
{
  "games": [
    "https://store.steampowered.com/app/1245620/ELDEN_RING/"
  ],
  "maxReviewsPerGame": 1000,
  "maxTotalReviews": 10000,
  "languages": [
    "all"
  ],
  "reviewType": "all",
  "sortBy": "recent",
  "purchaseType": "all",
  "includeGameSummary": true,
  "includePlaytimeStats": true,
  "debugLog": false
}
```

# Actor output Schema

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

All stored records: review records, one game\_summary per game, and error records for failed inputs. Filter on the recordType field.

## `runSummary` (type: `string`):

Counts of stored and charged results, duplicates, failed inputs and any charging warning.

# 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/"
    ]
};

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

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

```

## MCP server setup

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