# Steam Reviews & Game Details Scraper — No login (`cliqtomedia/steam-reviews`) Actor

Export Steam game reviews with verdict, text, playtime, votes and date, plus price, genres, release date and review score per game. Filter by language, verdict and date. No login.

- **URL**: https://apify.com/cliqtomedia/steam-reviews.md
- **Developed by:** [Cliqto Media](https://apify.com/cliqtomedia) (community)
- **Categories:** Videos, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.28 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 & Game Details exports Steam game reviews by app ID or store link. Each review comes with the verdict, text, language, playtime, helpful votes and date, and each game gets one row with price, genres, release date and review score.

Use it to study what players like or hate, to watch new reviews after a patch, or to compare games. The smallest run is one app ID, for example `730`, and 20 reviews. No Steam login or API key is needed. That prefill run (20 reviews and one game row) costs about $0.01.

![Steam Reviews & Game Details: add app IDs or store URLs, get reviews with playtime and votes, plus one game details row with price, genres, release date and review score](https://api.apify.com/v2/key-value-stores/PD9yuVABa3qLPPmaY/records/README-HERO-20261017-v2.png)

### Table of contents

- [What it does](#what-it-does)
- [How it works](#how-it-works)
- [Quick start](#quick-start)
- [Use cases](#use-cases)
- [Input](#input)
- [Output](#output)
- [Pricing](#pricing)
- [Limits](#limits)
- [Scheduled runs: only new reviews](#scheduled-runs-only-new-reviews)
- [API, export and AI agents](#api-export-and-ai-agents)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Related Actors](#related-actors)
- [Support](#support)

### What it does

You give the Actor Steam app IDs or store links. For each game it reads the public review list of the Steam store and saves one dataset row per review. It can also save one game details row with the current store price, discount, genres, release date, developers and the whole-game review score.

You choose the review language, verdict (Recommended or Not recommended), order (newest, recently updated or most helpful), purchase type and a date period. The Actor stops at your number of reviews per game, at the end of the list, or at your maximum charge.

#### Good fit

- Read player feedback for your game or a competitor's game in one table.
- Collect only reviews written after a date, for example after a patch or sale.
- Compare price, discount, genres and review score of many games at once.
- Build a sentiment or topic dataset in one language.

#### Not a fit

- Only the Steam store. Bundles, packages, DLC lists, workshop items and player profiles are not supported.
- Player data stays minimal: you get the reviewer's `steamId` and the public review link, not names, avatars or friend lists.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### How it works

1. The Actor reads each game's public review list from Steam's official review service, page by page, with your language, verdict, order, purchase type and date period applied by Steam.
2. It stops a game at your review count, at the end of the list or at your start date, and asks the Steam store once per game for price, genres, release date and review score.
3. It saves one row per review and one game row per game to the dataset, the game rows also as the `GAMES` record, and a `RUN_SUMMARY` record with the run status and a checkpoint for the next scheduled run.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Quick start

[![Input form: box 1 marks the prefilled app ID 730 in Steam app IDs, box 2 the Steam store URLs field, box 3 Max reviews per game set to 20](https://api.apify.com/v2/key-value-stores/PD9yuVABa3qLPPmaY/records/quick-start-form-20261028.png)](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)

1. Open the **Input** tab. **Steam app IDs** already holds `730`, Counter-Strike 2 (box 1 in the picture). The ID is the number in the store link: `store.steampowered.com/app/730/`.
2. Keep it, or paste store links of your games into **Steam store URLs** (box 2).
3. Keep **Max reviews per game** at the prefilled `20` (box 3), then click **Start** at the bottom of the form.
4. Open the **Reviews** view of the output and look at the verdict, review text and hours played (box 4 in the picture below). The **All rows** view adds the game row with price and review score.

   [![Output table: box 4 marks the Recommended, Review, Language and Hours at review columns of sample review rows for Stardew Valley](https://api.apify.com/v2/key-value-stores/PD9yuVABa3qLPPmaY/records/output-table-20261028b.png)](https://api.apify.com/v2/key-value-stores/PD9yuVABa3qLPPmaY/records/output-table-20261028b.png)

Expected result: 20 review rows and 1 game row in a few seconds.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Use cases

| Buyer job | Input path | Output entity | Key fields | Next integration |
| --- | --- | --- | --- | --- |
| Find top complaints about a game | `appIds`, `reviewType: negative`, `language: english` | review rows | `text`, `votesUp`, `playtimeHours` | Topic or sentiment analysis in Sheets or an LLM |
| Check reaction to a patch | `reviewsSince: "2026-10-01"`, `reviewsUntil: "2026-10-07"` | review rows | `recommended`, `createdAt` | Share of positive reviews per day |
| Compare a genre | 20–100 `appIds`, `maxReviews: 0` | game rows | `price`, `discountPercent`, `genres`, `positivePercent` | Price and score table |
| Track a competitor's sale | `appIds`, `countryCode`, scheduled | game rows | `price`, `initialPrice`, `discountPercent` | Alert when the discount changes |

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Input

#### Input fields

| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect | Example | Recommendation |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `appIds` | Steam app IDs | array of strings | one of `appIds`/`gameUrls` | none (prefill `["730"]`) | numbers 1–2147483647 | Games to read | `["730", "570"]` | Easiest way to start |
| `gameUrls` | Steam store URLs | array of URLs | one of `appIds`/`gameUrls` | none | `store.steampowered.com/app/…`, `steamcommunity.com/app/…` | Same as app IDs, from links | `["https://store.steampowered.com/app/413150/"]` | Paste links when you do not know the ID |
| `maxReviews` | Max reviews per game | integer | no | `100` (prefill `20`) | 0–50000 | Stop after this many reviews for each game. `0` = only the game row | `200` | Start small, then raise |
| `language` | Review language | string | no | `all` | Steam names (`english`, `russian`, `schinese`, `brazilian`, `koreana` …) or codes (`en`, `ru`, `pt-br`) | Only reviews written in this language | `english` | Set it for text analysis |
| `reviewType` | Verdict | enum | no | `all` | `all`, `positive`, `negative` | Only Recommended or only Not recommended | `negative` | `negative` to find problems fast |
| `sortBy` | Order | enum | no | `recent` | `recent`, `updated`, `helpful` | Which reviews come first | `helpful` | `recent` for monitoring, `helpful` for the best-known opinions |
| `reviewsSince` | Only reviews since | string | no | none | date `2026-01-31`, ISO time, or period `7 days` / `30d` | Skip older reviews | `2026-10-01` | Use with scheduled runs |
| `reviewsUntil` | Only reviews until | string | no | none | date `2026-03-31` (to the end of that day UTC), ISO time, or period `30 days` | Skip newer reviews | `2026-10-31` | With `reviewsSince` for a closed period |
| `purchaseType` | Purchase type | enum | no | `all` | `all`, `steam`, `non_steam_purchase` | Only Steam buyers or only keys bought elsewhere | `steam` | Keep `all` unless you study key resellers |
| `includeGameDetails` | Add game details row | boolean | no | `true` | `true`, `false` | One extra row per game with price, genres and score | `false` | Turn off if you need reviews only |
| `countryCode` | Store country | string | no | `us` | two letters, e.g. `us`, `de`, `gb` | Price and currency of the game row | `de` | Games not sold there get no game row |

Add at least one app ID or game URL. Up to 100 games per run; duplicates (the same game as an ID and as a link) are processed once. An entry that is not a Steam app ID or store link (for example a bundle link) is skipped with a free `error` row (`errorCode: INVALID_INPUT`), and the other games still run; the run then ends as `PARTIAL` with reason `SOME_INPUTS_INVALID`. Only when no entry is valid does the run stop with `INVALID_INPUT`, and you pay only the $0.001 start fee.

#### Interacting settings

| When | Input A | Input B | Effective behavior | Example | Cost/result effect |
| --- | --- | --- | --- | --- | --- |
| Monitoring | `sortBy: recent` | `reviewsSince` | Stops as soon as reviews get older than the date | `"reviewsSince": "7 days"` | Fast and cheap: one review page per game when nothing is new |
| Best reviews of a period | `sortBy: helpful` | `reviewsSince` | Steam's most helpful reviews written in that period | `"reviewsSince": "2026-01-01"` | Charged per saved review only |
| Closed period | `reviewsSince` | `reviewsUntil` | Only reviews created between the two times; Steam applies both | `"reviewsSince": "2026-10-01", "reviewsUntil": "2026-10-07"` | Fewer rows, so cheaper |
| Only the game row | `maxReviews: 0` | `includeGameDetails: true` | No reviews, one game row per game | `"maxReviews": 0` | $0.0012 per game |
| Filters | `language`, `reviewType`, `purchaseType` | `maxReviews` | Steam applies the filters; `maxReviews` counts only matching reviews | `"language": "english"` | Fewer rows when few reviews match |

#### Input examples

##### Recent negative English reviews of two games

```json
{
  "appIds": ["1091500"],
  "gameUrls": ["https://store.steampowered.com/app/413150/Stardew_Valley/"],
  "language": "english",
  "reviewType": "negative",
  "maxReviews": 200
}
```

Expected behavior: reads the newest Not recommended English reviews of both games.
Expected output: up to 200 review rows per game (`recommended: false`, `text`, `playtimeHours`) plus 2 game rows.
Limit or cost note: up to $0.16 for 400 reviews on the Free plan, plus start, game and game-row fees.

##### Only game details for a list of games

```json
{
  "appIds": ["730", "570", "1245620", "1086940"],
  "maxReviews": 0,
  "countryCode": "de"
}
```

Expected behavior: no review pages, one store request per game.
Expected output: 4 game rows with euro `price`, `discountPercent` and `reviewScoreDesc`.
Limit or cost note: $0.0058 in total.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Output

All rows go to one dataset with two views: **Reviews** and **All rows**. The game rows are also saved alone as the `GAMES` record in the key-value store, so you get a clean game table. Every row has `type`, `source`, `url` and `fetchedAt`.

| Row `type` | One row per | Main fields |
| --- | --- | --- |
| `review` | review | `recommended`, `text`, `language`, `playtimeHours`, `votesUp`, `createdAt` |
| `game` | game (when `includeGameDetails` is on) | `price`, `discountPercent`, `genres`, `releaseDateIso`, `reviewScoreDesc`, `positivePercent` |
| `not_found` | app ID that Steam does not know | `appId`, `message` |
| `error` | game that failed after retries, or an entry that is not a Steam app ID | `appId`, `input`, `errorCode`, `message` |

#### Output fields

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

| Field | Meaning | Type | Can be empty? | Example / enum | Source / notes |
| --- | --- | --- | --- | --- | --- |
| `appId` | Steam app ID | string | no | `"730"` | from your input |
| `gameName` | Game name | string | yes, if Steam gives no name | `"Counter-Strike 2"` | store details or review totals |
| `reviewId` | Steam review ID, stable key | string | no | `"219989924"` | Steam `recommendationid` |
| `steamId` | Reviewer's public Steam ID (64-bit) | string | yes | `"76561198351194597"` | |
| `recommended` | Recommended (`true`) or Not recommended (`false`) | boolean | no | `false` | |
| `text` | Review text as written | string | no (may be `""`) | `"The gameplay is nice…"` | Steam formatting tags kept |
| `language` | Steam language name | string | yes | `"english"` | |
| `playtimeHours` | Hours played when the review was written | number | yes | `3097.1` | Steam minutes ÷ 60, one decimal |
| `playtimeForeverHours` | Total hours played now | number | yes | `3108.1` | |
| `playtimeLastTwoWeeksHours` | Hours in the last two weeks | number | yes | `0` | |
| `votesUp` | "Helpful" votes | integer | yes | `940` | changes over time |
| `votesFunny` | "Funny" votes | integer | yes | `57` | |
| `helpfulScore` | Steam helpfulness score 0–1 | number | yes | `0.91` | |
| `commentCount` | Comments under the review | integer | yes | `22` | |
| `steamPurchase` | Bought on Steam | boolean | yes | `true` | |
| `receivedForFree` | Got the game for free | boolean | yes | `false` | |
| `refunded` | Refunded | boolean | yes | `false` | |
| `writtenDuringEarlyAccess` | Written in Early Access | boolean | yes | `false` | |
| `primarilySteamDeck` | Played mostly on Steam Deck | boolean | yes | `false` | |
| `developerResponse` | Developer's reply | string | yes, no reply | `null` | |
| `developerRespondedAt` | Reply time (ISO) | string | yes | `null` | |
| `createdAt` | Review time (ISO, UTC) | string | yes | `"2026-03-06T15:36:44.000Z"` | |
| `updatedAt` | Last edit time (ISO, UTC) | string | yes | `"2026-03-06T15:36:44.000Z"` | |
| `url` | Public review page | string | yes | `"https://steamcommunity.com/profiles/…/recommended/730/"` | |
| `storeUrl` | Game store page | string | no | `"https://store.steampowered.com/app/730/"` | |
| `source`, `fetchedAt` | Data source and fetch time | string | no | `"steam"` | |

##### Game rows (`type: "game"`)

| Field | Meaning | Type | Can be empty? | Example / enum | Source / notes |
| --- | --- | --- | --- | --- | --- |
| `appId`, `gameName`, `appType` | ID, name, Steam type | string | `gameName`/`appType` yes | `"730"`, `"game"` | |
| `isFree` | Free to play | boolean | yes | `true` | |
| `price`, `initialPrice` | Current and full price in major units | number | yes, if not sold | `17.99`, `59.99` | store of `countryCode` |
| `currency` | ISO currency | string | yes (free games) | `"USD"` | |
| `discountPercent` | Current discount | integer | yes | `70` | |
| `priceFormatted` | Price as shown in the store | string | yes | `"$17.99"` | |
| `genres`, `categories` | Steam genres and features | array | no (may be empty) | `["RPG"]` | |
| `releaseDate` | Release date as Steam shows it | string | yes | `"Dec 9, 2020"` | |
| `releaseDateIso` | Same as `YYYY-MM-DD` when Steam gives a full date | string | yes | `"2020-12-09"` | |
| `comingSoon` | Not released yet | boolean | yes | `false` | |
| `developers`, `publishers`, `platforms` | Who made it, where it runs | array | no (may be empty) | `["windows"]` | |
| `metacriticScore` | Metacritic score | integer | yes | `86` | |
| `recommendationsTotal` | Steam recommendations counter | integer | yes | `5315663` | |
| `reviewScore` | Steam score 1–9 | integer | yes | `8` | |
| `reviewScoreDesc` | Score label | string | yes | `"Very Positive"` | |
| `totalPositive`, `totalNegative`, `totalReviews` | Whole-game review counts | integer | yes | `9927956` | |
| `positivePercent` | Positive share, % | number | yes | `85.8` | |
| `requiredAge` | Age limit | integer | yes | `0` | |
| `shortDescription`, `headerImage`, `website` | Store text, image and site | string | yes | | |
| `countryCode` | Store country used for price | string | no | `"us"` | |
| `url`, `source`, `fetchedAt` | Store page, source, fetch time | string | no | | |

##### Issue rows (`type: "not_found"` or `"error"`)

`appId`, `gameName`, `input` (what you entered), `errorCode`, `message`, `url`, `source`, `fetchedAt`. On an `INVALID_INPUT` row `appId` and `url` are `null`, because the entry was not a Steam app ID. Issue rows are not charged; each app ID the run starts costs only the $0.0002 game-processed fee.

#### Output entities and surfaces

| Situation | Dataset/API/KVS/live view | Result shape | User action |
| --- | --- | --- | --- |
| Normal item | Dataset views **Reviews** and **All rows**, `GAMES` record | review and game rows | Open, export or read `reviewId` |
| Domain-empty result | Dataset and `RUN_SUMMARY` | no review rows, `stopReason: end_of_reviews` or `since_reached` | Widen filters or the date |
| Unknown app ID | Dataset, `RUN_SUMMARY` | `not_found` row, status `NOT_FOUND` when every ID is unknown | Fix the ID |
| Partial result | `RUN_SUMMARY` | status `PARTIAL` with reason `CHARGE_LIMIT`, `DEADLINE`, `SOME_GAMES_FAILED` or `SOME_INPUTS_INVALID` | Read the reason and the issue rows |
| Technical failure or retry | Dataset `error` rows, `RUN_SUMMARY` | `errorCode`, `message`; saved rows kept | Run the failed games again later |

The `RUN_SUMMARY` record has the run status (`COMPLETE`, `PARTIAL`, `NOT_FOUND`, `ERROR`, `INVALID_INPUT`), the reason, counts, and one line per game with the number of reviews, why it stopped and `newestReviewAt`.

#### Output example

A review row (real, from the Counter-Strike 2 review list):

```json
{
  "type": "review",
  "appId": "730",
  "gameName": "Counter-Strike 2",
  "reviewId": "219989924",
  "steamId": "76561198351194597",
  "recommended": false,
  "text": "The gameplay is nice but the game is infested with cheaters :(",
  "language": "english",
  "playtimeHours": 3097.1,
  "playtimeForeverHours": 3108.1,
  "playtimeLastTwoWeeksHours": 0,
  "votesUp": 940,
  "votesFunny": 57,
  "helpfulScore": 0.9106771349906921,
  "commentCount": 22,
  "steamPurchase": true,
  "receivedForFree": false,
  "refunded": false,
  "writtenDuringEarlyAccess": false,
  "primarilySteamDeck": false,
  "developerResponse": null,
  "developerRespondedAt": null,
  "createdAt": "2026-03-06T15:36:44.000Z",
  "updatedAt": "2026-03-06T15:36:44.000Z",
  "url": "https://steamcommunity.com/profiles/76561198351194597/recommended/730/",
  "storeUrl": "https://store.steampowered.com/app/730/",
  "source": "steam",
  "fetchedAt": "2026-10-17T11:57:22.670Z"
}
```

A game row (trimmed: `categories` and `shortDescription` shortened):

```json
{
  "type": "game",
  "appId": "730",
  "gameName": "Counter-Strike 2",
  "appType": "game",
  "isFree": true,
  "price": 0,
  "initialPrice": 0,
  "currency": null,
  "discountPercent": null,
  "priceFormatted": "Free",
  "genres": ["Action", "Free To Play"],
  "categories": ["Multi-player", "Steam Workshop", "In-App Purchases"],
  "releaseDate": "Aug 21, 2012",
  "releaseDateIso": "2012-08-21",
  "comingSoon": false,
  "developers": ["Valve"],
  "publishers": ["Valve"],
  "platforms": ["windows", "linux"],
  "metacriticScore": null,
  "recommendationsTotal": 5315663,
  "reviewScore": 8,
  "reviewScoreDesc": "Very Positive",
  "totalPositive": 8517496,
  "totalNegative": 1410460,
  "totalReviews": 9927956,
  "positivePercent": 85.8,
  "requiredAge": 0,
  "shortDescription": "For over two decades, Counter-Strike has offered an elite competitive experience…",
  "headerImage": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/730/…/header.jpg",
  "website": "http://counter-strike.net/",
  "countryCode": "us",
  "url": "https://store.steampowered.com/app/730/",
  "source": "steam",
  "fetchedAt": "2026-10-17T11:46:53.575Z"
}
```

`null` means Steam did not give a value (for example no Metacritic score, or no currency for a free game). `0` is a real zero. Review text is kept exactly as written, including Steam formatting tags like `[b]` or `[spoiler]`. Steam decides which reviews it shows: reviews that Steam hides (for example off-topic review bombs) or deletes are not returned.

#### Use case → fields

| Buyer job | Input path | Output entity | Key fields | Next integration |
| --- | --- | --- | --- | --- |
| Sentiment dataset | `language`, `maxReviews` | review rows | `recommended`, `text` | LLM or classifier |
| Patch monitoring | `sortBy: recent`, `reviewsSince` | review rows | `createdAt`, `recommended` | Daily chart |
| Price and score table | `maxReviews: 0` | game rows | `price`, `positivePercent` | Sheets or BI |

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Pricing

#### Pricing unit

Pay per event: you pay for each saved review and game row, plus a small start and per-game fee. Apify platform usage is included.

| Event | When | Price (USD) |
| --- | --- | ---: |
| Actor start | once per run; the fee is counted per GB of run memory (one fee at the default 256 MB) | 0.001 |
| Game processed | per app ID the run starts, also an unknown ID | 0.0002 |
| Review | per saved review | 0.0004 Free · 0.00036 Bronze · 0.00032 Silver · 0.00028 Gold and above |
| Game details row | per game row (`includeGameDetails: true`) | 0.001 |

A valid run with no matching reviews (a filter or a date with nothing new) costs the start fee plus $0.0002 per game, plus the game row if it is on. An unknown app ID costs only the $0.0002 game-processed fee. Issue rows (`not_found`, `error`) and entries that are not Steam app IDs are free. A failed game is never charged more than a successful one: you pay only for the rows that were saved.

#### Cost examples

| Scenario | Input scope | Expected item/event count | Base charge | Optional charge | Stop/cap behavior |
| --- | --- | ---: | ---: | ---: | --- |
| Prefill | 1 game, 20 reviews | 20 reviews + 1 game row | $0.0102 Free, $0.0078 Gold | game row included | stops at 20 |
| One game in depth | 1 game, 1,000 reviews | 1,000 reviews + 1 game row | $0.40 Free, $0.28 Gold | game row included | stops at 1,000 |
| Ten games | 10 games, 100 reviews each | 1,000 reviews + 10 game rows | $0.41 Free, $0.29 Gold | game rows included | stops at 100 per game |
| Game rows only | 100 games, `maxReviews: 0` | 100 game rows | $0.12 | none | — |
| Unknown IDs | 100 unknown app IDs | 100 `not_found` rows | $0.021 | none | `NOT_FOUND` |

Set **Maximum cost per run** in the run options to cap a run: the Actor stops before a charge would go above it and returns what it already paid for (status `PARTIAL`, reason `CHARGE_LIMIT`).

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Limits

- Only the Steam store: no bundles, packages, DLC lists, workshop items or player profiles. Such links are skipped with an `INVALID_INPUT` row.
- Up to 100 games per run and up to 50,000 reviews per game in the input. In our tests 1,000 reviews took about 6 seconds and 5,551 reviews about 38 seconds (roughly 145 reviews per second), so at that rate the default 300-second timeout fits about 40,000 reviews (an estimate: our largest tested run saved 24,000 reviews per game); Steam rate limits can make it fewer. For more reviews, raise the run timeout or split the games over several runs.
- Steam limits the request rate. The Actor waits between requests and slows down on rate limits, so big runs take minutes, not seconds.
- If the run reaches its time limit, it stops about 15 seconds before the timeout and keeps all saved rows. The Apify run then shows FAILED, while `RUN_SUMMARY` says `PARTIAL` with reason `DEADLINE` when rows were saved (or `ERROR` when none were).
- If the run reaches your maximum charge, it stops, keeps all saved rows and ends as `PARTIAL` with reason `CHARGE_LIMIT`.
- If Steam fails for one game, other games continue; the failed game gets an `error` row and the run is `PARTIAL` with `SOME_GAMES_FAILED`.
- A `reviewsSince` date without a time means midnight UTC, and only reviews created strictly after it are returned. A `reviewsUntil` date without a time means the end of that day (23:59:59 UTC), and reviews created up to it are included.
- Steam shows brand-new reviews with a short delay (its own cache; in our tests about 10 minutes), so a review written just before a run may only appear in the next one.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Scheduled runs: only new reviews

1. Run once with `sortBy: recent`.
2. In `RUN_SUMMARY`, copy `newestReviewAt` of the game.
3. In the schedule input, set `reviewsSince` to that time.

Only reviews created strictly after `reviewsSince` are returned, so the checkpoint review itself does not come back and a run with no new reviews returns no review rows. Steam itself filters by creation date in `recent` and `helpful` order, so such a run reads the game details and one review page per game; in `updated` order the Actor checks update times and stops at the first older one. Use `newestReviewAt` as a checkpoint only with `sortBy: recent`; in `helpful` order it is just the newest of the returned reviews.

A review that Steam shows late (see [Limits](#limits)) normally comes in the next scheduled run, because it is newer than the checkpoint.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### API, export and AI agents

- **Export:** the dataset downloads as JSON, CSV, Excel, XML or HTML. The **Reviews** view shows review columns (game and status rows appear there too; filter by `type = review` for a pure review table); `GAMES` gives the game table as JSON.
- **API:** start a run with `POST https://api.apify.com/v2/acts/cliqtomedia~steam-reviews/runs` and the input JSON; read rows from the run's dataset.
- **Scheduling, webhooks, Make, Zapier, n8n:** use the standard Apify integrations; the next system reads review rows by `reviewId`.

#### Use with AI agents (MCP)

- MCP server with only this Actor: `https://mcp.apify.com?tools=cliqtomedia/steam-reviews`
- Smallest useful input: `{"appIds": ["730"], "maxReviews": 20}`
- Key output fields: `recommended` (true = Recommended), `text` (review), `playtimeHours` (hours played at review time), `votesUp` (helpful votes), `createdAt` (UTC time). Game rows have `price`, `reviewScoreDesc` and `positivePercent`.
- The smallest run takes a few seconds and costs about $0.01; 1,000 reviews take about 6 seconds and cost $0.28–$0.40. Keep `maxReviews` small for quick answers.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Troubleshooting

#### I got a `not_found` row

Symptom: no reviews and a `not_found` row.
Likely reason: the ID is wrong, or the app has no store page (removed games, some tools and servers).
Check: open `store.steampowered.com/app/<id>/` in a browser.
Action: fix the ID or use the store link.

#### I got an `error` row with `INVALID_INPUT`

Symptom: an `error` row with `appId: null` and the run is `PARTIAL` with `SOME_INPUTS_INVALID`.
Likely reason: the entry is not a Steam app ID or a store link with `/app/<id>/` (for example a bundle, package or profile link, or a typo).
Check: the `input` and `message` of the row.
Action: replace it with the app ID or the game's store link.

#### Fewer reviews than I asked for

Symptom: a game has fewer rows than `maxReviews`.
Likely reason: the filters (`language`, `reviewType`, `purchaseType`, `reviewsSince`) leave fewer reviews, or Steam has no more.
Check: `stopReason` for the game in `RUN_SUMMARY` (`end_of_reviews`, `since_reached`, `max_reviews`).
Action: widen the filters.

#### No game row for a game

Symptom: reviews are there, the game row is missing.
Likely reason: the game is not sold in `countryCode`.
Check: `detailsMissing` in `RUN_SUMMARY` counts.
Action: try `us` or another country.

#### The run ended with `SOURCE_ERROR` or `SOME_GAMES_FAILED`

Symptom: `error` rows for some games.
Likely reason: Steam did not answer after several retries.
Check: `errorCode` of the `error` rows; saved rows are kept.
Action: run the failed games again later.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### FAQ

#### Do I need a Steam account or API key?

No. The Actor reads public Steam store data. No login, cookies or key.

#### Is personal data included?

Only the public `steamId` and the public review link. No names, avatars or profile details.

#### Are the numbers live?

Yes, each run reads Steam at that moment; `fetchedAt` shows when. Counters like `votesUp` and `totalReviews` change over time.

#### Why are the playtime numbers decimals?

Steam stores minutes. The Actor turns them into hours with one decimal place.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Related Actors

- [Google Play Reviews Scraper: Ratings, Replies & Versions](https://apify.com/cliqtomedia/google-play-reviews-scraper) — the same review analysis for a mobile game or app on Android.
- [Apple App Store Reviews Scraper: Ratings & Review Text](https://apify.com/cliqtomedia/apple-app-store-reviews-scraper) — reviews of the iOS version of a game.
- [Reddit Scraper: Posts, Comments & Subreddits (No login)](https://apify.com/cliqtomedia/reddit-scraper) — what players say about the game in its subreddit.
- [YouTube Comments Scraper: Replies & CSV Export](https://apify.com/cliqtomedia/youtube-comments-scraper) — comments under trailers and gameplay videos.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

### Support

For a bug, question or feature request, open an issue on the Actor's **Issues** tab. Add the run ID and your input. Never post tokens or private data.

Data comes from the official [Steam Web API review service](https://partner.steamgames.com/doc/webapi/IUserReviewsService) and the public Steam store (Valve Corporation). Your use of the data is subject to the [Steam Web API Terms](https://steamcommunity.com/dev/apiterms) and the [Steam Subscriber Agreement](https://store.steampowered.com/subscriber_agreement/). Review texts belong to their authors. This Actor is not affiliated with or endorsed by Valve.

> **👉 [Try it now: open the input form](https://console.apify.com/actors/kkBuupseS2Bjw92JA/input)**

# Changelog

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

# Actor input Schema

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

Numeric app IDs from the store URL, e.g. 730 for Counter-Strike 2 (store.steampowered.com/app/730/). Up to 100 games together with game URLs; duplicates are listed once.

## `gameUrls` (type: `array`):

Store or community links such as https://store.steampowered.com/app/1091500/Cyberpunk_2077/ or https://steamcommunity.com/app/730/reviews/. Bundle, package and profile links are not supported: they are skipped with a free error row and the other games still run.

## `maxReviews` (type: `integer`):

Reviews to return for each game. 0 returns only the game details row. Big games have millions of reviews: a run stops at this number, at the end of the list, or at your maximum charge.

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

Steam language name (english, russian, schinese, brazilian, koreana ...) or a code like en, ru, pt-br. all returns reviews in every language.

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

All reviews, only Recommended or only Not recommended.

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

recent: newest written first. updated: newest edited first. helpful: Steam's most helpful of all time, or of the reviewsSince period when it is set.

## `reviewsSince` (type: `string`):

Only reviews created after this time. A date (2026-01-31), a full ISO time or a period like 7 days. For scheduled runs pass newestReviewAt from the last run report: the review it came from is not returned again.

## `reviewsUntil` (type: `string`):

Only reviews created up to this time, inclusive. A date (2026-03-31, counted to the end of that day UTC), a full ISO time or a period like 30 days (that many days ago). Use it with Only reviews since for a closed period, for example the week after a patch.

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

All reviews, only from Steam buyers, or only from keys bought elsewhere.

## `includeGameDetails` (type: `boolean`):

One extra row per game with price, discount, genres, release date, developers, platforms, Metacritic and the whole-game review score.

## `countryCode` (type: `string`):

Two-letter country for price and currency, e.g. us, de, gb. Games not sold there come without a game details row.

## Actor input object example

```json
{
  "appIds": [
    "730"
  ],
  "maxReviews": 20,
  "language": "all",
  "reviewType": "all",
  "sortBy": "recent",
  "purchaseType": "all",
  "includeGameDetails": true,
  "countryCode": "us"
}
```

# Actor output Schema

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

One row per review with verdict, text, playtime, votes and date.

## `games` (type: `string`):

Only the game rows (JSON): price, genres, release date and review score per game.

## `allRows` (type: `string`):

Reviews, game rows and not_found or error rows in one table.

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

Counts, why each game stopped, newestReviewAt for the next scheduled run and safe error details.

# 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": [
        "730"
    ],
    "maxReviews": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/steam-reviews").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": ["730"],
    "maxReviews": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/steam-reviews").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": [
    "730"
  ],
  "maxReviews": 20
}' |
apify call cliqtomedia/steam-reviews --silent --output-dataset

```

## MCP server setup

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

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/kkBuupseS2Bjw92JA/builds/4IZD30B4EXIaan2IQ/openapi.json
