# Steam Game Reviews Scraper: review text, votes, playtime, bulk (`steadydata/steam-game-reviews`) Actor

Steam user reviews per game or app, up to 500 apps per run and up to 1,000 reviews each, newest first: review text, recommended or not, dates, helpful and funny votes, playtime at review, purchase flags and language, plus the app's review score. No reviewer names, ids or profiles. Pay per review.

- **URL**: https://apify.com/steadydata/steam-game-reviews.md
- **Developed by:** [Steadydata Team](https://apify.com/steadydata) (community)
- **Categories:** E-commerce, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.94 / 1,000 review listeds

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 Game Reviews Scraper: review text, votes, playtime, bulk

Steam user reviews per game or app, up to 500 apps per run and up to 1,000 reviews each, newest first: review text, recommended or not, dates, helpful and funny votes, playtime at review, purchase flags and language, plus the app's review score. No reviewer names, ids or profiles. Pay per review.

### Why this scraper

- **Only delivered results are charged.** Inputs that fail come back as clear error
  records at no cost.
- One store call per 100 reviews, straight from Steam's own review endpoint: no browser, no proxy tricks. Measured on the platform: 300 reviews of two games in 11 seconds for a fifth of a cent.
- No reviewer identity. Steam's response carries a Steam id, display name, profile URL and avatar with every review; none of that is delivered. What you get is the review itself: text, thumbs up or down, when it was written and last edited, helpful and funny votes, the weighted helpfulness score, comment count, hours played at review time and in total, whether it was a Steam purchase, received for free, written during early access or mostly on Steam Deck, and the language. Every row also carries the app's overall review label and total, so a sample can be read against the whole.
- Filters as on the store page: newest first, last edited first or Steam's helpfulness ranking; all, positive or negative; any Steam language or all; Steam purchases only or keys included.

### Who this is for

Paste Steam app ids or store URLs in `apps` (up to 500 per run) and set `maxReviewsPerApp` (default 100, ceiling 1,000). `language` takes a Steam language code (`english`, `german`, `schinese`, or `all`), `order` is `recent`, `updated` or `all`, `reviewType` is `all`, `positive` or `negative`, and `purchaseType` is `all`, `steam` or `non_steam_purchase`. Built for sentiment analysis, feedback and bug mining, patch reception tracking and competitor research on a game's reviews without building a profile of any player.

### Who this is not for

There is no reviewer name, id or profile link on purpose, so this is not a tool for finding or contacting players. Steam returns at most 1,000 reviews per query; for a game with millions of reviews you get the newest, last edited or most helpful thousand, not the whole archive. Paragraph breaks in a review are flattened to single spaces. An app id that does not exist and a game nobody reviewed look the same to Steam; both come back as a free `NO_REVIEWS` error row (measured: 2 of 300 reviews had no text at all, those rows keep an empty `reviewText`). The app's name is not on the row; combine with the Steam game details actor below when you need it.

### Input fields

| Field | Type | Required or default | What it does |
|---|---|---|---|
| `apps` | list of text | required | One per row, up to 500: a Steam app id (570) or a store URL (https://store.steampowered.com/app/570/Dota\_2/). |
| `maxReviewsPerApp` | number | 100 | Cost ceiling per app; reviews come in pages of 100. |
| `language` | text | english | Steam language code such as english, german, french, spanish, schinese, or all. |
| `order` | text (recent, updated, all) | recent | recent (newest first), updated (last edited first) or all (Steam's helpfulness ranking). |
| `reviewType` | text (all, positive, negative) | all | all, positive (recommended) or negative (not recommended). |
| `purchaseType` | text (all, steam, non\_steam\_purchase) | all | all, steam (bought on Steam) or non\_steam\_purchase (activated with a key). |

### Input example

```json
{
    "apps": [
        "570",
        "https://store.steampowered.com/app/1245620/ELDEN_RING/"
    ],
    "maxReviewsPerApp": 100,
    "language": "english",
    "order": "recent",
    "reviewType": "all",
    "purchaseType": "all"
}
```

### Output example

| Field | Type | What it holds | Example |
|---|---|---|---|
| `appId` | text | Steam's numeric id for the game, the key to join other rows on. | `570` |
| `reviewId` | text | Steam's id for the review, the key to its own page. | `236530635` |
| `recommended` | true/false | True when the reviewer recommends the game; this is the thumb Steam counts. | `False` |
| `reviewText` | text | The review text as the player wrote it. | `I stopped playing this game 2 months ago. Life's been goo...` |
| `language` | text | The language the reviewer wrote in, as Steam labels it. | `english` |
| `createdAt` | text | When the review was posted, in UTC. | `2026-09-30T08:17:34Z` |
| `updatedAt` | text | When the review was last edited; equal to createdAt for a review that was never changed. | `2026-09-30T08:17:34Z` |
| `votesHelpful` | number | How many people marked the review helpful. | `1` |
| `votesFunny` | number | How many people marked the review funny. | `0` |
| `weightedVoteScore` | number | Steam's own helpfulness score for the review, used to decide what surfaces first. | `0.5` |
| `commentCount` | number | How many comments the review received. | `0` |
| `playtimeAtReviewHours` | number | How long the reviewer had played when they wrote it, which says how much weight to give the opinion. | `3897` |
| `playtimeTotalHours` | number | How long the reviewer has played in total, up to now. | `3897` |
| `steamPurchase` | true/false | False means the key came from elsewhere, which Steam itself weighs differently. | `True` |
| `receivedForFree` | true/false | Whether the reviewer got the game for free, which they declare themselves. | `False` |
| `writtenDuringEarlyAccess` | true/false | Whether the review was written before the full release, so it may describe an older version. | `False` |
| `primarilySteamDeck` | true/false | Whether the reviewer mostly played on a Steam Deck. | `False` |
| `appReviewScore` | text | Steam's verdict over all reviews of the game, repeated on every row so one row carries its own context. | `Very Positive` |
| `appTotalReviews` | number | The total number of reviews of the game, repeated on every row for the same reason. | `2788377` |
| `url` | text | The review's own page on Steam. | `https://store.steampowered.com/app/570/` |

Error codes: `INVALID_APP`, `NO_REVIEWS`, `BLOCKED`.

One delivered row looks like this:

```json
{
  "appId": "1245620",
  "reviewId": "233901707",
  "recommended": false,
  "reviewText": "I love this game and up until now this was a positive review. Elden ring tarnished edition made me change my opinion. It's not about the money , it's about the disrespect.",
  "language": "english",
  "createdAt": "2026-08-28T13:17:45Z",
  "updatedAt": "2026-08-28T13:17:45Z",
  "votesHelpful": 199,
  "votesFunny": 7,
  "weightedVoteScore": 0.7655,
  "commentCount": 15,
  "playtimeAtReviewHours": 536.5,
  "playtimeTotalHours": 548.5,
  "steamPurchase": true,
  "receivedForFree": false,
  "writtenDuringEarlyAccess": false,
  "primarilySteamDeck": false,
  "appReviewScore": "Very Positive",
  "appTotalReviews": 1155045,
  "url": "https://store.steampowered.com/app/1245620/",
  "status": "ok"
}
```

### Related actors from steadydata

- [steam-app-details](https://apify.com/steadydata/steam-app-details): the game itself: price, genres, review score, DLC
- [youtube-search](https://apify.com/steadydata/youtube-search): what video makers say about the same game
- [google-trends-compare](https://apify.com/steadydata/google-trends-compare): whether interest in a game is rising or falling

### Pricing

Pay per event: one `review-listed` event per delivered result. No charge for inputs
that fail, no separate platform-usage surcharge.

**Free Apify plan:** this actor delivers up to 25 rows per run for accounts on the Apify free
plan, and then stops with a message. That limit is set by us, not by Apify. It exists so the
actor keeps paying for itself for the people who do pay. Any paid Apify plan runs it at full
size, billed per delivered row, with failed rows never charged.

**Reviews:** if this actor saves you time, a short review on this page is the one thing that
helps most. Ratings are what other buyers look at first, and we have no other way to ask.

### FAQ

**Is personal data collected?**
No. The Steam id, display name, profile URL and avatar that Steam sends with each review are dropped before anything is stored. Playtime figures are kept as plain numbers on the review, not linked to a person.

**Why is `appReviewScore` the same on every row of a game?**
It is the game's overall label and total from Steam, fetched once per app without filters, so you can weigh a sample of 200 negative reviews against 2.7 million in total.

**Can I get more than 1,000 reviews for one game?**
Not in one query; that is Steam's ceiling per ordering. Run the same game with `order` set to `recent`, `updated` and `all`, or split by `language` and `reviewType`, and deduplicate on `reviewId`.

**Do the counts change between runs?**
Yes. Votes, comment counts, playtime and the app totals are live figures; a review written this morning has zero votes now and may have fifty next week.

**Does a run cost anything when a game has no reviews?**
No. `NO_REVIEWS`, `INVALID_APP` and `BLOCKED` rows are free; only delivered reviews are charged.

**What happens when the source changes?**
Sources change from time to time; that is the nature of this work. The actor is
monitored daily and fixed fast, and while it is broken you are not charged, because
only delivered results cost anything.

# Changelog

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

# Actor input Schema

## `apps` (type: `array`):

One per row, up to 500: a Steam app id (570) or a store URL (https://store.steampowered.com/app/570/Dota\_2/).

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

Cost ceiling per app; reviews come in pages of 100.

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

Steam language code such as english, german, french, spanish, schinese, or all.

## `order` (type: `string`):

recent (newest first), updated (last edited first) or all (Steam's helpfulness ranking).

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

all, positive (recommended) or negative (not recommended).

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

all, steam (bought on Steam) or non\_steam\_purchase (activated with a key).

## Actor input object example

```json
{
  "apps": [
    "570",
    "https://store.steampowered.com/app/1245620/ELDEN_RING/"
  ],
  "maxReviewsPerApp": 100,
  "language": "english",
  "order": "recent",
  "reviewType": "all",
  "purchaseType": "all"
}
```

# Actor output Schema

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

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

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

```

## MCP server setup

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