# Steam Game Reviews & Playtime Extractor (`dataspryva/steam-game-reviews-and-playtime-extractor`) Actor

Pull Steam customer reviews for any game by URL or name, with thumbs up/down verdicts, reviewer playtime, helpfulness votes, and language filters.

- **URL**: https://apify.com/dataspryva/steam-game-reviews-and-playtime-extractor.md
- **Developed by:** [Dataspryva](https://apify.com/dataspryva) (community)
- **Categories:** Automation, Developer tools, Videos
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 & Playtime Extractor

Export the actual customer-review feed for any Steam game — the review text, thumbs up/down verdict, reviewer profile, playtime, votes, and hardware shown on a store page. Pick games by app ID, store URL, community review URL, or plain name, then walk the full review history or stop at a fixed count. Every row is real Steam data; empty values are omitted instead of being filled with `0`, `false`, or `""`.

### What this actor does

- **Two output modes:** `reviews` emits one row per review; `gameSummary` emits one row per game with metadata, price, and the overall review score.
- **Flexible game selection:** numeric app IDs, store URLs, community review URLs, old review URLs, and game-name search all work in one run. Names prefer an exact title match.
- **Complete review filters:** language, review type, purchase type, sort order, helpfulness window, exact UTC date window, playtime range, Steam Deck, off-topic reviews, and review-quality ranking.
- **Rich reviewer context:** display name, profile and avatar URLs, SteamID, review counts, total/at-review/recent playtime, last played, Deck playtime, votes, comment count, reactions, purchase/refund/Early Access/Deck flags, and optional hardware details.
- **Unlimited history:** `maxReviews: 0` follows the review cursor until Steam runs out, with no 500-row ceiling.
- **Empty fields are omitted** at every nesting level, so a missing value is never confused with a real zero.

### Output per review (`mode` = `reviews`)

- `appId`, `gameTitle`, `gameUrl` — the game's Steam identity
- `reviewId`, `reviewText`, `reviewUrl` — Steam recommendation ID, body, and permalink
- `rating` — `Positive` or `Negative`; `votedUp` boolean form
- `authorSteamId`, `authorName`, `authorProfileUrl`, `authorAvatarUrl`
- `authorNumReviews`, `authorNumGamesOwned` — profile activity (games owned is omitted when private or zero)
- `authorPlaytimeForever`, `authorPlaytimeAtReview`, `authorPlaytimeLastTwoWeeks`, `authorDeckPlaytimeAtReview` — hours, one decimal
- `authorLastPlayed` — ISO 8601 UTC
- `votesHelpful`, `votesFunny`, `weightedVoteScore`, `commentCount`, `reactionCount`
- `steamPurchase`, `receivedForFree`, `refunded`, `writtenDuringEarlyAccess`, `primarilySteamDeck`
- `language`, `timestampCreated`, `timestampUpdated` — Steam language code and ISO 8601 UTC timestamps
- `developerResponse`, `developerResponseAt` — only when Steam returns a developer reply
- `hardware` — optional `{ os, cpu, gpu, systemRamMb, vramMb }`
- `game` — optional metadata block when `includeGameDetails` is on
- `recordType: "review"`, `scrapedAt`

### Output per game (`mode` = `gameSummary`)

- `appId`, `gameTitle`, `gameUrl`, `gameType`, `isFree`, `shortDescription`
- `developers[]`, `publishers[]`, `genres[]`, `categories[]`
- `platforms` — `{ windows, mac, linux }`
- `releaseDate`, `metacriticScore`, `headerImage`
- `price` — `{ currency, initial, final, discountPercent, formatted }` when a price exists
- `reviewSummary` — `{ reviewScore, reviewScoreDesc, totalPositive, totalNegative, totalReviews, positivePercent }`
- `recordType: "game"`, `scrapedAt`

`reviewSummary` is the game's overall score across all languages and purchase types, not the filtered review query.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `reviews` | `reviews` (one row per review) or `gameSummary` (one row per game) |
| `appIds` | array | – | Numeric IDs, store URLs, community review URLs, or old review URLs |
| `startUrls` | array | – | Legacy-compatible Steam store URLs; merged with `appIds` |
| `gameNames` | array | – | Names resolved through Steam search; exact title match preferred |
| `maxReviews` | int | `50` | Per-game review cap; `0` means all matching reviews |
| `maxGames` | int | `0` | Cap the merged game list; `0` means no cap |
| `reviewType` | string | `all` | `all`, `positive`, or `negative` |
| `language` | string | `all` | Steam language code or `all` |
| `sortBy` | string | `recent` | `recent`, `helpful`, `updated`, or `funny`; helpful and funny are ranked, not exhaustive |
| `helpfulWithinDays` | int | `30` | Helpful sort window (1–365 days) |
| `purchaseType` | string | `all` | `all`, `steam`, or `nonSteamPurchase` |
| `minPlaytimeHours` | int | `0` | Minimum hours at review; `0` = no minimum |
| `maxPlaytimeHours` | int | `0` | Maximum hours at review; `0` = no maximum |
| `steamDeckOnly` | boolean | `false` | Only reviews played primarily on Steam Deck |
| `includeOffTopic` | boolean | `false` | Include review-bomb/off-topic activity Steam hides by default |
| `useReviewQuality` | boolean | `true` | Apply Steam's quality ranking to `sortBy=helpful` |
| `reviewsFromDate` | string | – | Include reviews created on/after this UTC date (`YYYY-MM-DD`) |
| `reviewsToDate` | string | – | Include reviews created on/before this UTC date (`YYYY-MM-DD`) |
| `includeGameDetails` | boolean | `false` | Attach game metadata, price, and score to every review row |

At least one game source (`appIds`, `startUrls`, or `gameNames`) is required.

#### Example: the smallest daily run

```json
{
    "mode": "reviews",
    "startUrls": [{ "url": "https://store.steampowered.com/app/1174180/Red_Dead_Redemption_2/" }],
    "maxReviews": 3,
    "sortBy": "recent"
}
```

#### Example: negative English reviews in an exact date window

```json
{
    "mode": "reviews",
    "appIds": ["570"],
    "reviewType": "negative",
    "language": "english",
    "reviewsFromDate": "2024-01-01",
    "reviewsToDate": "2024-03-31",
    "maxReviews": 500
}
```

#### Example: long sessions on a Steam Deck

```json
{
    "mode": "reviews",
    "gameNames": ["Hades"],
    "steamDeckOnly": true,
    "minPlaytimeHours": 20,
    "sortBy": "helpful",
    "helpfulWithinDays": 90,
    "maxReviews": 200
}
```

#### Example: game metadata and score summaries

```json
{
    "mode": "gameSummary",
    "appIds": ["1145360", "1245620"],
    "gameNames": ["Baldur's Gate 3"],
    "maxGames": 3
}
```

### Use cases

- **Patch and DLC sentiment** — pull reviews from a narrow date window to see reaction before and after a release.
- **Competitive benchmarking** — compare review volume, positive share, playtime, and hardware mix across titles.
- **Community management** — filter negative reviews by language and date to triage bugs and crashes.
- **Reviewer vetting** — check total playtime, review history, and whether a copy was free or refunded.
- **Store dashboards** — run `gameSummary` for a clean one-row-per-game view of price, score, and metadata.
- **Localization research** — compare sentiment in specific Steam language markets.

### FAQ

**Where does the data come from?**
Steam's public store review services and store metadata endpoints — the same information shown under "Customer Reviews" and on a game's store page.

**Do I need a Steam account, API key, or proxy?**
No. The actor uses anonymous public endpoints, needs no login or key, and is configured without a proxy input.

**Are the date filters inclusive?**
Yes. `reviewsFromDate` starts at 00:00:00 UTC and `reviewsToDate` ends at 23:59:59 UTC, using the review's creation time. Reviews edited later do not move into an older window.

**Why are some fields missing from a row?**
Empty values are omitted deliberately. Hardware is only recorded when a reviewer shares it, reactions and developer responses are rare, and private profiles hide games-owned. If Steam's rich review service is unavailable, the actor switches to Valve's official review API, which omits reviewer display names and avatars. Absence means Steam did not provide the value.

**Does `maxReviews: 0` really return everything?**
With `recent` or `updated` it follows Steam's cursor until the source is exhausted. Ranked sorts (`helpful`, `funny`) only expose Steam's ranked subset. A safety cap of 1,000,000 reviews per game prevents runaway runs; narrow the date window or use `maxReviews` for very large titles.

**Is `sortBy=helpful` a full export?**
No. Helpful is Steam's ranked view inside `helpfulWithinDays`, and `funny` is likewise a ranked subset of the game's reviews; neither is exhaustive. Use `recent` or `updated` for full-history exports.

**What does `purchaseType` mean?**
`steam` means Steam records the copy as bought through Steam; `nonSteamPurchase` covers keys, gifts, and other acquisitions. On some free-to-play titles Steam's own purchase flag does not split cleanly, so treat that filter as Steam's classification rather than an independent audit.

**Why does `gameSummary` show a different score than a filtered review run?**
`reviewSummary` is always the game's overall score across all languages and purchase types. The review filters only affect which individual review rows are emitted.

**Can I mix IDs, URLs, and names in one run?**
Yes. All sources are merged and deduplicated by app ID, then capped by `maxGames`.

**Is this affiliated with Steam or Valve?**
No. This is an independent, third-party actor that reads Steam's public endpoints; it is not operated by Valve.

# Actor input Schema

## `mode` (type: `string`):

reviews = one row per review; gameSummary = one row per game with metadata and overall score.

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

Numeric app IDs, store URLs, community review URLs, or old appreviews URLs. Example: 1174180 or https://store.steampowered.com/app/1174180/

## `startUrls` (type: `array`):

Steam store page URLs for the games to scrape. Merged with appIds.

## `gameNames` (type: `array`):

Search Steam by name. An exact case-insensitive title match is preferred over the first search result.

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

Reviews to collect per game. Use 0 for every matching review (hard safety cap 1,000,000 per game).

## `maxGames` (type: `integer`):

Cap the merged game list. Use 0 for no cap.

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

Filter reviews by recommendation verdict.

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

Steam language code for review text. Select All Languages to include every language.

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

recent and updated walk the full history; helpful is a ranked sample inside the helpfulness window; funny is also ranked and not exhaustive.

## `helpfulWithinDays` (type: `integer`):

Only for sortBy=helpful: rank reviews from the last 1-365 days. Use recent for full history.

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

Whether the reviewer acquired the game through Steam, outside Steam, or either.

## `minPlaytimeHours` (type: `integer`):

Minimum hours played at the time of review. Use 0 for no minimum.

## `maxPlaytimeHours` (type: `integer`):

Maximum hours played at the time of review. Use 0 for no maximum.

## `steamDeckOnly` (type: `boolean`):

Only reviews written while playing primarily on a Steam Deck.

## `includeOffTopic` (type: `boolean`):

Include reviews Steam hides as off-topic review-bomb activity. Off by default, matching the store.

## `useReviewQuality` (type: `boolean`):

Only for sortBy=helpful: rank low-quality reviews lower.

## `reviewsFromDate` (type: `string`):

Include reviews created on or after this UTC date.

## `reviewsToDate` (type: `string`):

Include reviews created on or before this UTC date.

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

mode=reviews: attach game metadata, price and overall review summary to every review row.

## Actor input object example

```json
{
  "mode": "reviews",
  "appIds": [],
  "startUrls": [
    {
      "url": "https://store.steampowered.com/app/1174180/Red_Dead_Redemption_2/"
    }
  ],
  "gameNames": [],
  "maxReviews": 3,
  "maxGames": 0,
  "reviewType": "all",
  "language": "all",
  "sortBy": "recent",
  "helpfulWithinDays": 30,
  "purchaseType": "all",
  "minPlaytimeHours": 0,
  "maxPlaytimeHours": 0,
  "steamDeckOnly": false,
  "includeOffTopic": false,
  "useReviewQuality": true,
  "includeGameDetails": false
}
```

# Actor output Schema

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

Dataset containing scraped Steam review records or per-game summary records.

# 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 = {
    "mode": "reviews",
    "appIds": [],
    "startUrls": [
        {
            "url": "https://store.steampowered.com/app/1174180/Red_Dead_Redemption_2/"
        }
    ],
    "gameNames": [],
    "maxReviews": 3,
    "maxGames": 0,
    "reviewType": "all",
    "language": "all",
    "sortBy": "recent",
    "helpfulWithinDays": 30,
    "purchaseType": "all",
    "minPlaytimeHours": 0,
    "maxPlaytimeHours": 0,
    "steamDeckOnly": false,
    "includeOffTopic": false,
    "useReviewQuality": true,
    "includeGameDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataspryva/steam-game-reviews-and-playtime-extractor").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 = {
    "mode": "reviews",
    "appIds": [],
    "startUrls": [{ "url": "https://store.steampowered.com/app/1174180/Red_Dead_Redemption_2/" }],
    "gameNames": [],
    "maxReviews": 3,
    "maxGames": 0,
    "reviewType": "all",
    "language": "all",
    "sortBy": "recent",
    "helpfulWithinDays": 30,
    "purchaseType": "all",
    "minPlaytimeHours": 0,
    "maxPlaytimeHours": 0,
    "steamDeckOnly": False,
    "includeOffTopic": False,
    "useReviewQuality": True,
    "includeGameDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("dataspryva/steam-game-reviews-and-playtime-extractor").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 '{
  "mode": "reviews",
  "appIds": [],
  "startUrls": [
    {
      "url": "https://store.steampowered.com/app/1174180/Red_Dead_Redemption_2/"
    }
  ],
  "gameNames": [],
  "maxReviews": 3,
  "maxGames": 0,
  "reviewType": "all",
  "language": "all",
  "sortBy": "recent",
  "helpfulWithinDays": 30,
  "purchaseType": "all",
  "minPlaytimeHours": 0,
  "maxPlaytimeHours": 0,
  "steamDeckOnly": false,
  "includeOffTopic": false,
  "useReviewQuality": true,
  "includeGameDetails": false
}' |
apify call dataspryva/steam-game-reviews-and-playtime-extractor --silent --output-dataset

```

## MCP server setup

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

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/KcRtpVrqTcmshwJGE/builds/GxuUpYbrzkiWxwZa1/openapi.json
