How to get Steam reviews as JSON (appreviews API)
Steam serves every game's user reviews from a public JSON endpoint. No key, no login: here is how to page through all of them.
1. Find the app ID
It is the number in the store URL: store.steampowered.com/app/730/CounterStrike_2/. Or search by name:
curl "https://store.steampowered.com/api/storesearch/?term=counter%20strike&cc=us&l=en"
Each item has id and name. Check the name: soundtracks and DLC show up as separate apps.
2. Request reviews
curl "https://store.steampowered.com/appreviews/730?json=1&filter=recent&language=english&num_per_page=100&purchase_type=all&cursor=*"
query_summaryon the first page givesreview_score_desc("Very Positive"),total_positive,total_negativeandtotal_reviewsfor the language you asked for.language=allgives the overall totals.reviewsholds up to 100 reviews (num_per_pagemax 100):review(text),voted_up(recommended or not),votes_up,votes_funny,timestamp_created(Unix seconds),language,steam_purchase,received_for_free,written_during_early_access, andauthor.playtime_forever/playtime_at_reviewin minutes.filter:recent(newest first, best for paging through everything),updated, orall(helpfulness order).review_type=positiveornegativenarrows by verdict.
3. Page with the cursor
Each response returns a cursor. Send it back as cursor= to get the next page, until a page comes back with no reviews. The cursor contains +, / and =, so URL-encode it: a raw + turns into a space and Steam answers {"success": 8, "error": "Invalid cursor …"} with no reviews key, so a careless loop crashes or stops after page one.
import json, urllib.parse, urllib.request
cursor, reviews = "*", []
while True:
url = ("https://store.steampowered.com/appreviews/730?json=1&filter=recent&language=english"
"&num_per_page=100&purchase_type=all&cursor=" + urllib.parse.quote(cursor, safe=""))
data = json.load(urllib.request.urlopen(url))
if not data["reviews"]:
break
reviews += data["reviews"]
cursor = data["cursor"]
if len(reviews) >= 1000: # remove to fetch everything; big games have millions
break
print(len(reviews))
Pause between requests for long runs: Steam rate-limits heavy use of the store endpoints.
Many games, as CSV
Our Steam Reviews Scraper on Apify takes app IDs, store links or names and returns one flat row per review (text, thumbs up/down, playtime, votes, language, dates) plus game details (price, genres, developers, review score), as CSV, Excel or JSON. Billed per review.
Frequently asked questions
Do I need a Steam Web API key for reviews?
No. The appreviews endpoint is public. A key is only needed for the separate Steam Web API (player data and similar).
Can I get all reviews of a game?
Yes, with filter=recent and cursor paging until a page is empty. For games with millions of reviews this takes many thousands of requests, so filter by language or stop at the date you need.
Why does my paging loop stop after the first page?
The cursor was probably not URL-encoded: Steam then returns an 'Invalid cursor' error with no reviews. Encode it (urllib.parse.quote with safe='' or encodeURIComponent) before sending it back.
Are playtimes in hours?
No, minutes. Divide playtime_forever and playtime_at_review by 60.
Written with AI assistance. The search, review and paging calls were run for Counter-Strike 2 (app 730) on 2026-10-01. The Apify tool is ours; the APIs are free to call directly.