# Steam Concurrent Players Monitor - Live Counts & History (`fanndev/steam-concurrent-players-monitor`) Actor

Track Steam player counts: live top 100, daily peak chart, live count for any game, monthly and hourly history, a 12,700-game long-tail ranking and total Steam users online. Built-in change detection for scheduled monitoring.

- **URL**: https://apify.com/fanndev/steam-concurrent-players-monitor.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Stats:** 4 total users, 3 monthly users, 88.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 results

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 Concurrent Players Monitor

Track how many people are playing games on Steam: right now, today, and over the years. Steam's own live charts, a live count for any game, monthly and hourly history, a long-tail ranking of ~12,700 games, and the total number of Steam users online. All from one actor.

Schedule it (for example every hour) and every record also tells you **how much the player count changed since the previous run**, with an optional alert flag for big swings.

### What you can collect

| Mode | What you get | Requests |
|---|---|---|
| **Live top 100 by current players** (`topConcurrent`) | Steam's live "Most Played" chart: players in-game now, today's peak, name, developer, release date | 1 |
| **Top 100 by daily peak** (`topDailyPeak`) | Yesterday's peak per game, plus its rank a week earlier | 1 |
| **Live player count for my games** (`appsCurrent`) | Live players for any game you list, optionally plus 24h peak, all-time peak and 30-day average | 1 per game |
| **Player history for my games** (`appHistory`) | Monthly average / gain / peak since launch, plus daily and hourly points | 2 per game |
| **Long-tail ranking** (`steamchartsTop`) | Up to ~12,700 games ranked by current players, with 30-day peak and hours played | 1 per 25 games |
| **Total Steam users online** (`steamOnline`) | Users logged in to Steam now, 48h peak and low, 5-minute series | 1 |

Games can be given as an appid (`730`), a Steam store / SteamCharts / SteamDB link, or just a name (`Elden Ring`).

### Example input

```json
{
    "mode": "appsCurrent",
    "apps": ["730", "https://store.steampowered.com/app/570/Dota_2/", "Elden Ring"],
    "includeSteamchartsStats": true,
    "compareWithPrevious": true,
    "alertChangePct": 20
}
```

### Example output

`topConcurrent` (real record, 2026-10-10):

```json
{
    "_input": "topConcurrent",
    "_source": "S1-steam-api-concurrent",
    "_scrapedAt": "2026-10-10T21:22:25Z",
    "recordType": "TOP_CONCURRENT",
    "rank": 1,
    "appid": 730,
    "concurrent_in_game": 1047853,
    "peak_in_game": 1404142,
    "name": "Counter-Strike 2",
    "storeUrl": "https://store.steampowered.com/app/730/CounterStrike_2",
    "isFree": true,
    "developers": ["Valve"],
    "publishers": ["Valve"],
    "releaseDate": "2012-08-21T17:00:00Z",
    "lastUpdate": "2026-10-10T21:18:11Z",
    "item": { "...": "raw Steam store item" },
    "previousPlayers": 1047853,
    "playersChange": 0,
    "playersChangePct": 0.0,
    "previousRank": 1,
    "rankChange": 0,
    "previousSnapshotAt": "2026-10-10T21:23:28Z",
    "isNewEntry": false,
    "sameUpstreamSnapshot": true
}
```

`appsCurrent` with SteamCharts stats:

```json
{
    "_input": "Elden Ring",
    "_source": "S1-steam-api-current",
    "recordType": "APP_CURRENT",
    "appid": 1245620,
    "player_count": 29280,
    "name": "ELDEN RING",
    "developers": ["FromSoftware, Inc."],
    "publishers": ["FromSoftware, Inc.", "Bandai Namco Entertainment"],
    "releaseDate": "2022-02-24T23:07:58Z",
    "checkedAt": "2026-10-10T21:23:23Z",
    "peak24h": 39449,
    "allTimePeak": 952523,
    "avgPlayersLast30Days": 28190.48
}
```

`appHistory` (series and months truncated):

```json
{
    "_input": "730",
    "_source": "S1-steamcharts-app",
    "recordType": "APP_HISTORY",
    "appid": 730,
    "name": "Counter-Strike 2",
    "currentPlayers": 1122810,
    "currentPlayersAt": "2026-10-10T20:01:55Z",
    "peak24h": 1402441,
    "allTimePeak": 1818368,
    "months": [
        {"month": "Last 30 Days", "avgPlayers": 810166.22, "gain": 4528.4, "gainPct": 0.56, "peakPlayers": 1450705},
        {"month": "September 2026", "avgPlayers": 805637.82, "gain": -19619.98, "gainPct": -2.38, "peakPlayers": 1450705},
        "... 170 more"
    ],
    "series": [
        {"timestamp": "2012-07-01T00:00:00Z", "players": 1642, "resolution": "monthly"},
        "... 948 more"
    ],
    "seriesPoints": 949
}
```

`steamOnline`:

```json
{
    "recordType": "STEAM_ONLINE",
    "label": "Steam users logged in",
    "usersOnline": 32606690,
    "usersOnlineAt": "2026-10-10T21:13:25Z",
    "peak48h": 42789427,
    "peak48hAt": "2026-10-10T14:42:46Z",
    "low48h": 25153899,
    "low48hAt": "2026-10-08T23:38:51Z",
    "seriesPoints": 604
}
```

Inputs that cannot be processed still produce a row with `recordType: "ERROR"` and a reason (`not_found`, `not_tracked`, `invalid_input`, ...), so you can always see which games failed and why.

### Monitoring (change detection)

With **Compare with previous run** on (the default), the actor remembers each game's number per mode in the named key-value store `steam-players-monitor-snapshots` and adds:

- `previousPlayers`, `playersChange`, `playersChangePct`: movement since the last run
- `previousRank`, `rankChange`: positive means the game climbed
- `isNewEntry`: the game wasn't in the previous snapshot (new on the chart)
- `sameUpstreamSnapshot`: Steam hadn't refreshed its data since your last run, so a 0 change means "no new data", not "no movement"
- `alert`: the change is at least **Alert threshold (%)**

Steam refreshes the live chart every few minutes and the daily-peak chart once a day; SteamCharts refreshes about hourly. Scheduling more often than that only repeats the same numbers.

### Good to know

- **Two sources, slightly different numbers.** Live counts (`topConcurrent`, `appsCurrent`) come straight from Steam's official API. History, 24h/all-time peaks and the long-tail ranking come from SteamCharts, which reads Steam about once an hour, so its "current" figure can be up to an hour old.
- **SteamCharts does not track every game.** Some new releases are missing (e.g. AION 2, #3 on Steam at test time). `appHistory` returns `not_tracked` for them; `appsCurrent` still returns the live count.
- **History resolution** (as of October 2026): monthly from launch until mid-2026, then daily, then hourly for the last ~30 days.
- **Official charts stop at 100 games.** Use `steamchartsTop` for anything below the top 100.
- **No login, no proxy needed.** None of the endpoints used is blocked or rate-limited at normal volumes. The proxy setting is there only for very large, very frequent jobs.

### Technical notes

- **WAF:** none on any surface (api.steampowered.com, store.steampowered.com, steamcharts.com), tested 2026-10-11. Even a bare Python client gets HTTP 200; 100 parallel API calls drew no 429s. `curl_cffi` with the `chrome124` TLS profile is used as insurance, rotating to safari17_0 / firefox133 / edge101 and a new exit IP if a gate ever appears.
- **Endpoints:** `ISteamChartsService/GetGamesByConcurrentPlayers` and `GetMostPlayedGames` (with `input_json.data_request`, so names come in the same call), `ISteamUserStats/GetNumberOfCurrentPlayers`, `IStoreBrowseService/GetItems` (batches of 100), `store/api/storesearch` for name lookup, `store/stats/userdata.json`, `steamcharts.com/app/{id}`, `/app/{id}/chart-data.json` and `/top/p.{n}`.
- **Quirk:** `GetMostPlayedGames` accepts `top_played_period` but ignores it (every value returns the same daily ranking), so it isn't exposed.
- SteamDB is intentionally not used: its terms prohibit automated access.

# Actor input Schema

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

topConcurrent = Steam's live top 100 games by players right now (+ today's peak). topDailyPeak = Steam's top 100 by yesterday's peak, with last week's rank. appsCurrent = live player count for the games you list. appHistory = player history for the games you list (monthly average/peak since launch + daily and hourly points). steamchartsTop = the long tail: up to ~12,700 games ranked by current players with 30-day peak and hours played. steamOnline = total Steam users online, last 48 hours.

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

One per line: a Steam appid (730), a Steam store / SteamCharts / SteamDB app URL, or a game name (resolved through Steam store search; an exact title match wins). Only used by the appsCurrent and appHistory modes.

## `maxItems` (type: `integer`):

Maximum ranked games to return. The two official Steam charts stop at 100; steamchartsTop goes up to ~12,700.

## `minPlayers` (type: `integer`):

Skip games below this many players (current players for live charts, daily peak for topDailyPeak). 0 = no filter. In steamchartsTop the run stops at the first game below the threshold, so a high value is also a cheap way to cap the run.

## `compareWithPrevious` (type: `boolean`):

Remember each game's player count between runs and add previousPlayers, playersChange, playersChangePct, previousRank and rankChange. Schedule the actor (e.g. hourly) to turn it into a monitor. Snapshots are kept per mode in the named key-value store 'steam-players-monitor-snapshots'.

## `alertChangePct` (type: `integer`):

When comparing with the previous run, mark records whose player count moved by at least this percentage (up or down) with alert: true. 0 = off.

## `includeStoreDetails` (type: `boolean`):

Add name, store URL, developers, publishers, release date and the raw Steam store item. Costs one extra request per 100 games for appsCurrent; free for the two official charts.

## `includeSteamchartsStats` (type: `boolean`):

appsCurrent only: also read SteamCharts for each game's 24-hour peak, all-time peak and last-30-days average (one extra request per game). Games SteamCharts does not track keep their live count and get steamchartsError.

## `includeSeries` (type: `boolean`):

appHistory: add every player-count point (monthly since launch, then daily, then hourly for the last ~30 days). steamOnline: add the 48-hour series at ~5-minute steps. Turn off to get only the summary.

## `historyDays` (type: `integer`):

appHistory only: keep only points and months from the last N days. 0 = full history since launch.

## `country` (type: `string`):

Two-letter country code used for game details (store URL, availability). Player counts are global and do not change with it.

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

Steam language name for game names and descriptions (english, german, japanese, koreana, schinese, ...).

## `maxConcurrency` (type: `integer`):

Parallel requests for per-game modes and steamchartsTop pages.

## `maxRetries` (type: `integer`):

Attempts per request with exponential backoff before a game is reported as an error.

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

Not needed: none of the Steam or SteamCharts endpoints used is blocked or rate-limited for normal volumes. Turn on Apify Proxy (Residential) only if you run very large, very frequent jobs and start seeing errors.

## Actor input object example

```json
{
  "mode": "topConcurrent",
  "apps": [
    "730",
    "https://store.steampowered.com/app/570/Dota_2/",
    "Elden Ring"
  ],
  "maxItems": 100,
  "minPlayers": 0,
  "compareWithPrevious": true,
  "alertChangePct": 0,
  "includeStoreDetails": true,
  "includeSteamchartsStats": false,
  "includeSeries": true,
  "historyDays": 0,
  "country": "US",
  "language": "english",
  "maxConcurrency": 5,
  "maxRetries": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Every ranked game, per-game count, history and diagnostic record from this run.

# 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": "topConcurrent",
    "apps": [
        "730",
        "https://store.steampowered.com/app/570/Dota_2/",
        "Elden Ring"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/steam-concurrent-players-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 = {
    "mode": "topConcurrent",
    "apps": [
        "730",
        "https://store.steampowered.com/app/570/Dota_2/",
        "Elden Ring",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("fanndev/steam-concurrent-players-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 '{
  "mode": "topConcurrent",
  "apps": [
    "730",
    "https://store.steampowered.com/app/570/Dota_2/",
    "Elden Ring"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call fanndev/steam-concurrent-players-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/steam-concurrent-players-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/OZtxW1etOhmYlW4ur/builds/kljTxcP3guEDK95Vk/openapi.json
