Steam Regional Price Scraper avatar

Steam Regional Price Scraper

Pricing

Pay per event

Go to Apify Store
Steam Regional Price Scraper

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

DevilScrapes

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Steam Regional Price Scraper

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.

FieldTypeDescription
appidintegerSteam app id
app_namestringCanonical English app name from Steam
app_typestring | nullSteam app type (game, dlc, demo)
country_codestringISO 3166-1 alpha-2 country code
currencystring | nullISO 4217 currency code from Steam
initial_price_centsinteger | nullPre-discount price (smallest currency unit)
final_price_centsinteger | nullPost-discount price (smallest currency unit)
discount_percentintegerDiscount percentage 0-100
usd_equivalentnumber | nullComputed USD equivalent using Steam's US price
usd_conversion_ratenumber | nullImplied USD-per-local-unit rate
is_freebooleanTrue when the game is free in that region
is_unavailablebooleanTrue when Steam returns success: false for that pair
formatted_local_pricestring | nullSteam's human-formatted local price string
store_urlstringRegion-specific Steam store URL
scraped_atstringISO 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=True rows with null price fields, never silent drops. Output is informative even when the game is free.
  • Regional unavailability is traceable — is_unavailable=True rows for success: false responses (game not sold in that region or appid removed).
  • Name-to-appid resolution — pass appNames instead of appids and the Actor fetches GetAppList, case-insensitively matches each name to its appid, and logs a WARNING per miss. No extra orchestration required.
  • DLC filtering — includeDlc=false (default) drops app_type=dlc rows when resolving by name; pass includeDlc=true to 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 appids and app_names enforced before any network call, ISO 3166-1 alpha-2 codes validated up-front.
  • Exponential backoff with Retry-After honoured for 408 / 429 / 503 responses; max 5 attempts.
  • curl-cffi with browser TLS impersonation (ADR-0002 house default) — robust to any future Steam fingerprinting changes.
  • Apify Proxy support via the BUYPROXIES94952 group — 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 > 0 rows that hint at upcoming sales or regional promo windows.
  • Catalog availability monitoring — count is_unavailable=true rows per region to track Valve's quiet regional content-policy changes.

⚙️ How to use it

  1. Open the Actor input form on the Apify Console.
  2. Provide either appids (recommended; faster, deterministic) or appNames — not both. If you pass appNames, the Actor fetches the full Steam app catalog (~150k entries) once and resolves names case-insensitively.
  3. Set countryCodes to a list of ISO 3166-1 alpha-2 codes (e.g. ["US", "DE", "AR"]). Leave empty to use the curated 60-region default list.
  4. Toggle includeDlc if you're resolving by name and want DLC entries kept. Ignored when you pass appids directly.
  5. Leave computeUsdEquivalent on (default) unless you want to skip the per-appid US-price prefetch — disabling halves request count when you don't need the USD column.
  6. Leave useProxy on (default) for accurate regional prices. Some regions (RU, CN) are IP-gated and a US datacenter IP will return either US-fallback prices or success: false.
  7. 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

FieldTypeRequiredDefaultDescription
appidsinteger[]XORList of Steam appids (1-500). XOR with appNames.
appNamesstring[]XORList of game names (1-100), resolved via GetAppList. XOR with appids.
countryCodesstring[]no60-region defaultISO 3166-1 alpha-2 codes (2 uppercase letters each).
includeDlcbooleannofalseWhen appNames mode, keep app_type=dlc rows.
computeUsdEquivalentbooleannotrueFetch US price per appid as USD benchmark.
useProxybooleannotrueRoute 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.xlsx via 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:

EventPrice (USD)When
actor-start$0.05Once per run, at boot
result-row$0.001Per (appid × country) price row written

Example costs

RunRowsCost
1 game × 60 regions60$0.11
10 games × 60 regions600$0.65
50 games × 60 regions3,000$3.05
100 games × 60 regions6,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 Proxy BUYPROXIES94952 group 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.

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.