Fetch a Steam game's public page stats + apply the Boxleiter wishlist→revenue rule of thumb. The honest version: a heuristic with documented limits.
Project description
steam-page-stats
Fetch a Steam game's public page stats and apply the Boxleiter rule of thumb to estimate lifetime revenue from the review count. The honest version of a useful heuristic.
pip install steam-page-stats
steam-page-stats 1145360
Hades (appid 1145360)
developer: Supergiant Games
publisher: Supergiant Games
genres: Action, Indie, RPG
released: 17 Sep, 2020
price: $24.99
reviews: 205,000 total
review score: 97.56% positive
Boxleiter rule-of-thumb revenue estimate:
low (×30): $153.7M
median (×50): $256.1M
high (×63): $322.6M
⚠ This is a heuristic with ~24% of games off by >30% per the formula's
own author. For an empirically-validated P10–P90 cone with calibrated
80% coverage per genre, see https://steamforecast.app
Why this exists
The Boxleiter method (Mike Boxleiter, 2010s) is the de-facto rule of thumb for estimating lifetime Steam revenue from public page data:
revenue ≈ review_count × multiplier × price
Modern multiplier estimates range 30–63 sales per Steam review, with significant per-genre variance.
This package gives you:
- A multiplier-bracketed estimate (low / median / high) so you see the uncertainty inherent in the heuristic
- A clean Python API for use in your own analysis pipelines
- A CLI for quick one-off lookups
The package is deliberately small. It does not try to be a calibrated forecaster — for that, you need per-genre stratification, conformal prediction intervals, and a labelled corpus to validate against. That's a hard problem; the rule of thumb is not.
If you need calibrated revenue ranges with empirically-validated 80% coverage on a held-out launch corpus, plus causal estimates for marketing levers, see the full forecaster at https://steamforecast.app — methodology and per-genre coverage stats are open at /methodology.
Install
pip install steam-page-stats
Or with optional dev dependencies for tests / linting:
pip install "steam-page-stats[dev]"
CLI usage
# human-readable
steam-page-stats 1145360
# machine-readable JSON
steam-page-stats 1145360 --json
# just page stats, skip Boxleiter
steam-page-stats 1145360 --no-boxleiter
Python API
import asyncio
from steam_page_stats import fetch_page_stats, boxleiter_estimate
async def main():
stats = await fetch_page_stats(1145360)
print(f"{stats.name}: {stats.review_count_total:,} reviews")
if stats.review_count_total and stats.price_cents:
est = boxleiter_estimate(stats.review_count_total, stats.price_cents)
print(f"Lifetime revenue estimate: ${est.revenue_low_dollars:,.0f} – "
f"${est.revenue_median_dollars:,.0f} – ${est.revenue_high_dollars:,.0f}")
asyncio.run(main())
For batch use, instantiate the client directly to share the underlying HTTP connection pool:
from steam_page_stats import SteamPageStatsClient
async def fetch_many(appids):
async with SteamPageStatsClient(throttle_s=1.0) as client:
for appid in appids:
stats = await client.fetch(appid)
yield stats
Rate limits + etiquette
This package uses Steam's public, unauthenticated Storefront and appreviews endpoints. Steam tolerates roughly 200 req/5min from a single IP across these endpoints. The default throttle of 1 req/sec keeps you well below that.
We send a transparent User-Agent header so you're identifiable per RFC
etiquette:
steam-page-stats/0.1 (+https://github.com/GC108/steam-page-stats; calibration-sanity-check)
If you'd rather not advertise this package, override it:
async with SteamPageStatsClient(user_agent="my-research-bot/1.0") as c: ...
Limitations
The Boxleiter heuristic is structurally biased on:
- Top-decile breakouts (Peak, Webfishing, etc.) — single-multiplier can't capture viral discovery. Per the formula's own author, ~24% of games are off by more than 30%.
- Free-to-play with cosmetic monetization — the formula assumes
revenue ∝ price × sales; F2P breaks that. - Long-tailed mid-tier where individual conversion ratios diverge by 10–20× at comparable wishlist counts (see steamforecast.app/methodology for the variance data).
For these cases, a calibrated cone with empirically-validated coverage ranges beats a single-number heuristic. The rule of thumb is a useful sanity check, not a budget-decision tool.
Development
git clone https://github.com/GC108/steam-page-stats
cd steam-page-stats
pip install -e ".[dev]"
pytest
ruff check .
License
MIT — see LICENSE.
Related
- steamforecast.app — calibrated revenue cones with empirically-validated 80% coverage per genre, causal marketing-lever estimates, and Total Lift Attribution to recover paid campaign wishlists Steam's UTM dashboard misses.
- Steam Web API documentation
- Boxleiter method, Mike Boxleiter (2014, updated 2023) — the original formulation and 2023 retrospective.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file steam_page_stats-0.1.0.tar.gz.
File metadata
- Download URL: steam_page_stats-0.1.0.tar.gz
- Upload date:
- Size: 10.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffc3ad69482d1560507cc0b740b9de0e9370348b40fae7e60106878f74fec95e
|
|
| MD5 |
1f3735e1d406b535e55e003b8e9b7819
|
|
| BLAKE2b-256 |
f8ee4c3fc5b35a37f68d72e21f87bfd43ebd9f9d88e1fd883e6e8e695503923a
|
Provenance
The following attestation bundles were made for steam_page_stats-0.1.0.tar.gz:
Publisher:
publish.yml on GC108/steam-page-stats
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
steam_page_stats-0.1.0.tar.gz -
Subject digest:
ffc3ad69482d1560507cc0b740b9de0e9370348b40fae7e60106878f74fec95e - Sigstore transparency entry: 1486645405
- Sigstore integration time:
-
Permalink:
GC108/steam-page-stats@c663bb748b43599026943f78bb9e60c483e12ea0 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GC108
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c663bb748b43599026943f78bb9e60c483e12ea0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file steam_page_stats-0.1.0-py3-none-any.whl.
File metadata
- Download URL: steam_page_stats-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e272bfcbc09b7d5e3ae3b8637f111d80e49ba03eb9955b1e2a731773e0ef17e
|
|
| MD5 |
589b784ff12d5f6c4ce073f505ab1913
|
|
| BLAKE2b-256 |
962d8cd31aa1095083f9b0d11496c3c379f914a2a5d7963e60525fc92f3d9f5c
|
Provenance
The following attestation bundles were made for steam_page_stats-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on GC108/steam-page-stats
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
steam_page_stats-0.1.0-py3-none-any.whl -
Subject digest:
3e272bfcbc09b7d5e3ae3b8637f111d80e49ba03eb9955b1e2a731773e0ef17e - Sigstore transparency entry: 1486645570
- Sigstore integration time:
-
Permalink:
GC108/steam-page-stats@c663bb748b43599026943f78bb9e60c483e12ea0 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GC108
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c663bb748b43599026943f78bb9e60c483e12ea0 -
Trigger Event:
push
-
Statement type: