Steam Regional Price Scraper
Pricing
Pay per event
Steam Regional Price Scraper
Fetch Steam game prices across 60+ regions in one run. Compare USD-equivalent prices, spot regional discounts, and track arbitrage gaps. Public API, no login.
Pricing
Pay per event
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Steam Regional Price Scraper
We do the dirty work so your dataset stays clean. 😈
$1.05 / 1,000 rows — Fetch Steam game prices across 60+ regions in a single Actor run, derive a USD-equivalent for every region using Steam's own US price as the benchmark (no external FX API), and surface free-game and regionally-unavailable rows as first-class signals. Public Steam Store API. No login. No API key. No browser automation.
Steam quietly runs the world's largest regional-pricing matrix — the same game can list for $59.99 in the US, €49.99 in Germany, and ARS 4,249.99 in Argentina. This Actor scrapes the public store.steampowered.com/api/appdetails endpoint across a curated 60-region list (or any custom list you provide), normalizes everything into a flat dataset with one row per (appid × country_code), and includes the discount percentage, formatted local price, and a computed USD-equivalent. Ideal for indie devs setting regional prices, pricing analysts studying regional price discrimination, gift-card arbitrage trackers, and journalists writing "cheapest Steam region" comparisons.
🎯 What this scrapes
One row per (appid × country_code) pair. Every row carries the same 15 columns regardless of whether the game is paid, free, or regionally unavailable — the dataset is dense, never sparse.
| Field | Type | Description |
|---|---|---|
appid | integer | Steam app id |
app_name | string | Canonical English app name from Steam |
app_type | string | null | Steam app type (game, dlc, demo) |
country_code | string | ISO 3166-1 alpha-2 country code |
currency | string | null | ISO 4217 currency code from Steam |
initial_price_cents | integer | null | Pre-discount price (smallest currency unit) |
final_price_cents | integer | null | Post-discount price (smallest currency unit) |
discount_percent | integer | Discount percentage 0-100 |
usd_equivalent | number | null | Computed USD equivalent using Steam's US price |
usd_conversion_rate | number | null | Implied USD-per-local-unit rate |
is_free | boolean | True when the game is free in that region |
is_unavailable | boolean | True when Steam returns success: false for that pair |
formatted_local_price | string | null | Steam's human-formatted local price string |
store_url | string | Region-specific Steam store URL |
scraped_at | string | ISO 8601 UTC datetime this row was written |
🔥 Features
- Multi-region in one run — 60+ countries fetched sequentially from a single input; no per-region orchestration on the caller side.
- USD-equivalent built in — uses Steam's own US price as the benchmark, normalizes regional discounts via the locked formula
round((final/initial) * (us_initial/100), 4). No external FX API, no rate-source disagreement. - Free games emit rows —
is_free=Truerows with null price fields, never silent drops. Output is informative even when the game is free. - Regional unavailability is traceable —
is_unavailable=Truerows forsuccess: falseresponses (game not sold in that region or appid removed). - Name-to-appid resolution — pass
appNamesinstead ofappidsand the Actor fetchesGetAppList, case-insensitively matches each name to its appid, and logs a WARNING per miss. No extra orchestration required. - DLC filtering —
includeDlc=false(default) dropsapp_type=dlcrows when resolving by name; passincludeDlc=trueto keep them. - Rate-limit aware — respects Steam's ~200 req / 5 min limit by batching at 200 with a 60-second inter-batch sleep, and a 0.3s intra-batch pacing delay.
- Pydantic v2 input validation — XOR between
appidsandapp_namesenforced before any network call, ISO 3166-1 alpha-2 codes validated up-front. - Exponential backoff with
Retry-Afterhonoured for408 / 429 / 503responses; max 5 attempts. curl-cffiwith browser TLS impersonation (ADR-0002 house default) — robust to any future Steam fingerprinting changes.- Apify Proxy support via the
BUYPROXIES94952group — recommended on for IP-gated regions like RU and CN.
💡 Use cases
- Indie dev regional pricing audit — pull your own game across 60 regions and compare against Steam's recommended price tiers; spot gaps where you're priced above the regional median.
- Pricing analyst studies — compute the USD spread between regions for a basket of AAA titles to quantify Steam's regional price discrimination over time.
- Gift-card arbitrage tracking — monitor the USD-equivalent gap between regions like AR / TR / RU and the US to identify gift-card resale arbitrage opportunities.
- Cheapest-region journalism — generate "cheapest Steam region in 2026" comparisons across the AAA catalog with a single Actor run per article.
- Regional discount tracking — schedule recurring runs to catch
discount_percent > 0rows that hint at upcoming sales or regional promo windows. - Catalog availability monitoring — count
is_unavailable=truerows per region to track Valve's quiet regional content-policy changes.
⚙️ How to use it
- Open the Actor input form on the Apify Console.
- Provide either
appids(recommended; faster, deterministic) orappNames— not both. If you passappNames, the Actor fetches the full Steam app catalog (~150k entries) once and resolves names case-insensitively. - Set
countryCodesto a list of ISO 3166-1 alpha-2 codes (e.g.["US", "DE", "AR"]). Leave empty to use the curated 60-region default list. - Toggle
includeDlcif you're resolving by name and want DLC entries kept. Ignored when you passappidsdirectly. - Leave
computeUsdEquivalenton (default) unless you want to skip the per-appid US-price prefetch — disabling halves request count when you don't need the USD column. - Leave
useProxyon (default) for accurate regional prices. Some regions (RU, CN) are IP-gated and a US datacenter IP will return either US-fallback prices orsuccess: false. - Click Start. Results stream into the default dataset as JSON / CSV / Excel / XML.
Single game, three regions
{"appids": [1091500],"countryCodes": ["US", "DE", "AR"],"computeUsdEquivalent": true,"useProxy": true}
Resolve by name, full default region list
{"appNames": ["Cyberpunk 2077", "Counter-Strike 2", "Hades II"],"includeDlc": false,"computeUsdEquivalent": true,"useProxy": true}
📥 Input
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
appids | integer[] | XOR | — | List of Steam appids (1-500). XOR with appNames. |
appNames | string[] | XOR | — | List of game names (1-100), resolved via GetAppList. XOR with appids. |
countryCodes | string[] | no | 60-region default | ISO 3166-1 alpha-2 codes (2 uppercase letters each). |
includeDlc | boolean | no | false | When appNames mode, keep app_type=dlc rows. |
computeUsdEquivalent | boolean | no | true | Fetch US price per appid as USD benchmark. |
useProxy | boolean | no | true | Route through Apify Proxy (BUYPROXIES94952). |
Exactly one of appids or appNames must be provided. Passing both, or neither, raises a validation error before any network call.
📤 Output
One row per (appid × country_code) pair, pushed to the default dataset and available as JSON, CSV, Excel, or XML.
{"appid": 1091500,"app_name": "Cyberpunk 2077","app_type": "game","country_code": "AR","currency": "ARS","initial_price_cents": 424999,"final_price_cents": 424999,"discount_percent": 0,"usd_equivalent": 4.09,"usd_conversion_rate": 0.0000096,"is_free": false,"is_unavailable": false,"formatted_local_price": "ARS$ 4.249,99","store_url": "https://store.steampowered.com/app/1091500/?cc=AR","scraped_at": "2026-05-16T12:00:00.000Z"}
Export formats
- JSON — full fidelity, all 15 fields, newline-delimited
- CSV — flat, one row per
(appid × country)pair - Excel —
.xlsxvia the Apify dataset converter - XML — structured per-item
All formats are available via the Apify API: GET /datasets/{id}/items?format=csv&clean=true.
💰 Pricing
Pay-Per-Event (PPE) — you pay only for what you use:
| Event | Price (USD) | When |
|---|---|---|
actor-start | $0.05 | Once per run, at boot |
result-row | $0.001 | Per (appid × country) price row written |
Example costs
| Run | Rows | Cost |
|---|---|---|
| 1 game × 60 regions | 60 | $0.11 |
| 10 games × 60 regions | 600 | $0.65 |
| 50 games × 60 regions | 3,000 | $3.05 |
| 100 games × 60 regions | 6,000 | $6.05 |
At scale the per-row charge dominates: ~$1.05 per 1,000 rows. No competitor on the Apify Store offers multi-region Steam pricing with USD conversion at this price point.
🚧 Limitations
- Public Steam Store API only. The Actor uses
store.steampowered.com/api/appdetails— no authenticated calls, no Steam Web API key, no Steamworks endpoints. - One snapshot per run. Schedule recurring runs via Apify Schedules for time-series tracking; Steam does not expose historical prices.
- No SteamSpy concurrents or player counts. Out of scope; use a dedicated SteamSpy Actor.
- No reviews, screenshots, or descriptive metadata. Only price + free/unavailable flags +
app_name+app_type. - Regional IP gating. Steam uses request IP for some region gates (RU, CN) — without a regional exit IP you may see US-fallback prices or
is_unavailable=true. The Apify ProxyBUYPROXIES94952group is the default mitigation. - Steam rate limit. ~200 requests / 5 minutes per IP. The Actor enforces this with batch + 60-second inter-batch sleeps; very large runs (50+ games × 60 regions = 3,000+ requests) will take 15+ minutes.
- 7-day default storage retention on the Apify FREE tier. Export your dataset immediately after the run or upgrade for longer retention.
❓ FAQ
Do I need a Steam account?
No. The store.steampowered.com/api/appdetails endpoint is fully public and unauthenticated. The Actor reads only public regional price data that Valve already publishes on the Steam Store web pages.
Why does Argentina show much lower USD-equivalent prices?
Steam runs explicit regional pricing tiers — Valve sets recommended local-currency prices per region, and Argentina (along with Turkey, India, and a handful of others) has historically priced AAA games 50-90% below the US tier in USD-equivalent terms. The usd_equivalent field uses Steam's own US price as the benchmark via round((final/initial) * (us_initial/100), 4), so the value reflects what the AR price would be if the same discount applied at the US tier — not an FX-rate conversion.
What does is_unavailable=true mean?
Steam returned success: false for that (appid, country_code) pair. The two main causes: (a) the game is not sold in that region (Valve enforces regional content restrictions), or (b) the appid is invalid or removed. The Actor can't distinguish the two from the API response alone — both surface as the same flag.
Can I fetch more than 500 games per run?
No. appids is capped at 500 and appNames at 100 per Pydantic validation. Split larger workloads across multiple runs and concatenate the datasets — this is intentional to keep individual runs within Steam's rate-limit window.
Why use curl-cffi for a plain JSON REST API?
DevilScrapes house rule (ADR-0002) — curl-cffi is the default for every Actor because it impersonates a real browser's TLS fingerprint and survives any future Steam anti-bot tightening. The Steam Store API doesn't fingerprint today, but the cost of curl-cffi is zero and the upside is forward-compatibility.
Related Actors
Part of the Devil Scrapes Niche Marketplace Intel suite (in development):
- Reverb Sold Listings Scraper — sold-listing prices on Reverb for music-gear arbitrage.
- Discogs Sold Price Scraper — Discogs marketplace sold prices for vinyl-record collectors and resellers.
All three Actors share consistent pricing ($0.001 per row, $0.05 per run) and field-naming conventions (snake_case) so cross-marketplace arbitrage analyses can join cleanly.
💬 Your feedback
Found a bug, hit a rate limit, or need a new field on the output row? Open an issue on the Actor's Apify Store page or contact the Devil Scrapes team at apify.com/DevilScrapes. We ship updates within days of validated reports.