itch.io Game, Review, Creator and Jam Scraper
Pricing
from $1.00 / 1,000 results
itch.io Game, Review, Creator and Jam Scraper
Scrape itch.io games by genre, tag, platform, price band or keyword, plus creator catalogues and game jam results. Returns price and pay-what-you-want floor, rating, tags, platforms, files and the full review thread with creator replies. Incremental mode tracks changes.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
itch.io Game, Review, Creator and Jam Scraper turns itch.io into structured game, review, creator and jam data. Browse the site's own game index with its own filters, search by keyword, follow a creator's whole catalogue, or read a game jam and its ranked results. Every game comes back with its price and its pay-what-you-want floor, its rating and rating count, its tags, platforms, file list and the jam it was submitted to; turn on the detail lookup and each game also brings its full review thread, including which replies came from the game's own creator. Export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- The review thread, with creator replies. Other itch.io datasets stop at the star average. This one returns the individual comments, nested replies included, and flags every reply written by the game's own creator, so you can see not just the rating but how the studio actually answered.
- The pay-what-you-want floor, not just the sticker price. A large share of the catalogue is "name your own price". Both numbers come back separately, read from the page's own payload rather than from button text, so a free game, a donation game and a fixed-price game are never confused.
- Five modes, one output contract. Browse, keyword search, creator, jam and pasted links all produce the same flat record shape, so a mixed pull needs no branching downstream.
- Jam results in full. A ranked jam returns every entry's overall rank, its number of ratings, its adjusted score, and its rank and score under each individual criterion the jam scored on.
- Creator profiles with public follower counts. A creator record carries their catalogue, their outbound links, and the follower, post and topic counters, read exactly rather than from the abbreviated text the page shows.
- Recurring monitoring built in. Incremental mode returns only what changed since the last run of the same search, and Resume continues one interrupted pull without paying for rows you already have.
Use Cases
- Indie game researchers and journalists: build genre or tag datasets with price, rating and platform coverage for market reports.
- Community managers and developers: pull a game's full review thread, creator replies included, to audit community sentiment over time.
- Game jam organizers and analysts: turn a jam's ranked result table into a leaderboard, or a breakdown by individual judging criterion.
- Price and sales trackers: watch a genre or tag for pay-what-you-want floors, discounts and price-band changes.
- Talent scouts and publishers: read a creator's whole catalogue plus their public follower count to gauge an indie studio's reach.
- Curation and newsletter teams: schedule incremental runs over a tag or genre to surface new releases automatically.
Data You Get
Sample shape, values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
recordType | "game" (also "developer", "jam") |
recordId | "game-1" |
gameId | 1 |
title | "Sample Game Title" |
url | "https://sample-studio.itch.io/sample-game" |
developerName / developerUrl | "Sample Studio" / "https://sample-studio.itch.io" |
genre | "Puzzle" |
tags | ["atmospheric", "pixel art", "singleplayer"] |
platforms | ["Windows", "macOS", "Linux"] |
priceUsd | 4.99 |
minimumPriceUsd | 0 |
pricingModel | "name-your-own-price" |
isOnSale / salePercent | true / 40 |
rating | 4.6 |
ratingCount | 1234 |
status | "Released" |
files | [{"name": "sample-game-win.zip", "sizeText": "120 MB", "platforms": ["Windows"]}] |
jamName | "Sample Game Jam 2026" |
reviewCount / reviewsReturned | 210 / 20 |
reviews | [{"authorName": "player-one", "body": "Loved the ending.", "isDeveloperReply": false}] |
changeType | "NEW" (incremental mode only) |
scrapedAt | "2026-01-01T00:00:00Z" |
Creator records (recordType: "developer") carry the creator's name, page links, outbound links, catalogue count and the public follower, post and topic counters. Jam records (recordType: "jam") carry the jam's host, dates, joined and submission counts and, when the jam is ranked, the full topEntries result table with each entry's rank, number of ratings, adjusted score, and rank and score under every criterion the jam scored on.
How to Use
- Pick a mode: browse the game index with filters, search by keyword, pull named creators, read game jams, or paste site links.
- Narrow it: for browse mode choose up to two filter slots (genre, tag, platform, price, jam entry, or an ordering other than the default); for the other modes fill in the keywords, creators, jams or links.
- Turn on Fetch details and reviews if you want the full description, file list, exact price and the review thread; set Max results and Max result pages to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Browse a genre, top rated first:
{"mode": "browse","genres": ["Puzzle"],"sortBy": "top-rated","maxItems": 100}
Browse with the full detail lookup and the review thread:
{"mode": "browse","tags": ["horror"],"price": "free","fetchDetails": true,"maxReviewsPerGame": 50,"maxItems": 25}
A creator's whole catalogue plus their follower count:
{"mode": "developer","creators": ["sample-studio", "another-studio"],"fetchDetails": true}
A ranked jam with its full result table:
{"mode": "jam","jams": ["sample-game-jam-2026"],"fetchDetails": true,"maxJamEntries": 100}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/itch-io-scraper").call(run_input={"mode": "browse", "genres": ["Puzzle"], "maxItems": 50})for game in client.dataset(run["defaultDatasetId"]).iterate_items():print(game["title"], game["priceUsd"], game["rating"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/itch-io-scraper').call({ mode: 'browse', genres: ['Puzzle'], maxItems: 50 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
What the site itself limits
- At most two filter slots per browse address. Genres, tags, platform, price, jam entries and demo each use one slot, and any ordering other than the site default uses one as well. Asking for a third stops the run immediately with a message naming what to drop, rather than spending requests on an address the site will not serve.
- Keyword search is one page, and a smaller filter surface. The site serves a single page of results per keyword and publishes no second page; use browse mode for a large set. Search also carries only a platform option, a free-or-paid split and a demo flag, with no genre, tag, jam-entry or ordering option and no discount or price band. A filter the chosen mode cannot apply stops the run with a message naming it, so a run never comes back looking filtered when it is not.
- A creator page and a jam page are single documents. They publish no filter surface at all, so the listing filters above are not available in creator or jam mode. A browse scope also stops at the site's own depth limit of 200 pages (7,200 games); when that happens the run says so and, in incremental mode, will not mark anything expired from a scan it knows was incomplete.
Max results, per-scope budgets and a shared-scan gap to know about
Max results is one budget shared across every target in a run: several search keywords, several creators, several jams, or a mixed list of pasted links each get a fair share, so the first target does not spend the whole cap by itself. When a results list has to be cut short to stay inside that per-target share, the actor still reads every game on the page to decide what is new, and it remembers all of them as already scanned for the rest of the run, not only the handful that were actually returned.
Who is affected: only a run with Max results above 0 that reads two or more game lists: search mode with more than one keyword, or url mode with more than one pasted search or browse link. Browse mode (one address per run), a single keyword, creator mode and jam mode are not affected, because a creator or jam target returns one record and has no cut-off tail.
What happens: a game that fell in the cut-off tail of an earlier list, and that genuinely appears on a later list too, is skipped by the later list as well, so it is never returned by anyone. Worked example: two search keywords with Max results set to 6, so each keyword's share is 3. The first keyword's page lists 36 games; 3 are returned, but all 36 are now marked as scanned. The second keyword's page lists 2 games: one of the first keyword's 33 unreturned games, and one game nobody has seen. Only the new one is returned, and the run ends with 4 records instead of 6, while the skipped game appears nowhere in the output. When the later page has plenty of other new games, the count still fills up, but that specific game is still missing.
A restart does not clear it. If the platform restarts the run part-way (for example, when a run is moved to another server), the actor's saved progress holds that same "already scanned" list, including the games that were never returned, so the restarted run skips them too. Resume (resumeFromRunId) is not affected: it reads ids from the earlier run's actual dataset, so only rows that were really returned are skipped.
Workaround: run one keyword or one link per call when you need every overlapping game, or set Max results to 0 (no cap), or high enough that no target's share is smaller than everything that target returns.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips everything already collected there, so you don't pay twice. It reads the ids straight from that run's own dataset, so it is unaffected by the scanned-versus-returned gap above. - Incremental mode (
incrementalMode) is for scheduled runs over the same search. Each record is classifiedNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEAREDorEXPIRED(only after a run that scanned the whole tracked search, and only withemitExpired). A game's review thread and a jam entry's rank and score are deliberately excluded from change detection (a busy thread is entirely new rows within hours, and a rank moves with whichever ordering the run happened to read), but real movement still counts:reviewCount,ratingandratingCountare compared, so a game whose thread grew is still reportedUPDATEDwith those fields named inchangedFields.stateKeynames or shares the stored state. With incremental mode off, output is exactly as before.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, API & Integrations.
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. If a connector fails, the run still succeeds and the dataset is unaffected. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | select | browse | browse, search, developer, jam or url. |
queries | array | ["horror"] | Search mode keywords. One page of results per keyword. |
creators | array | ["gbpatch"] | Creator mode: handles, creator page links, or a link to one of their games. |
jams | array | ["gmtk-2024"] | Jam mode: jam handles or jam links. Leave empty to read a whole listing. |
jamScope | select | in-progress | Which jam listing to read when no jams are named. |
urls | array | see input form | URL mode: game, creator, jam, browse or search links, mixed freely. |
genres | array | (none) | Browse mode only. Genres written the way the site writes them. One filter slot each. |
tags | array | (none) | Browse mode only. Tags written the way they appear under a game. One filter slot each. |
jamEntries | select | any | Browse mode only. Only jam entries, or only games outside a jam. One slot. |
sortBy | select | popular | Browse mode only. The site's own orderings. Every value except the default uses one slot. |
platform | select | any | Browse, search and url. Windows, macOS, Linux, Android, iOS, or playable in the browser. One browse slot. |
price | select | any | Free is browse and search. Currently discounted, $5 or less and $15 or less are browse mode only. One browse slot. |
hasDemo | boolean | false | Browse, search and url. Only games that publish a playable demo. One browse slot. |
minRating | integer | 0 | Browse, search and url. Minimum rating, 0 to 5. Needs fetchDetails. |
minRatingCount | integer | 0 | Browse, search and url. Minimum number of ratings. Needs fetchDetails. |
fetchDetails | boolean | false | Read each record's own page. Adds one request per record and one Detail enrichment event. |
maxReviewsPerGame | integer | 20 | Cap on comments returned per game. 0 returns the game without its thread. |
includeJamEntries | boolean | true | Also return each jam's ranked entry table. |
maxJamEntries | integer | 20 | Cap on ranked entries per jam. 0 for every entry published. |
maxItems | integer | 20 | The run's cap, shared across every target. 0 for unlimited. |
maxPages | integer | 0 | Result pages per scope. 0 means no limit. |
resumeFromRunId | string | (none) | Continue one interrupted run from its run or dataset id. |
incrementalMode | boolean | false | Return only what changed since the last run of the same search. |
stateKey | string | (none) | Name a monitoring campaign, or deliberately share state. |
emitUnchanged | boolean | false | Also return unchanged rows. These are billed. |
emitExpired | boolean | false | Also return rows that disappeared. These are billed. |
proxy | object | Apify Proxy | Connection configuration. |
mcpConnectors | array | (none) | Optional MCP connectors to pipe results into. |
notionParentPageUrl | string | (none) | Notion parent page id, for the Notion connector. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run, 1 to 1000. |
Output Example
Sample shape, values are illustrative placeholders, not from a live listing.
{"recordType": "game","recordId": "game-1","gameId": 1,"title": "Sample Game Title","url": "https://sample-studio.itch.io/sample-game","slug": "sample-game","developerName": "Sample Studio","developerUrl": "https://sample-studio.itch.io","developerSlug": "sample-studio","shortText": "A one line tagline for the game.","coverImageUrl": "https://img.itch.zone/000000000/315x250/cover.png","description": "The full page description appears here when fetchDetails is on.","genre": "Puzzle","tags": ["atmospheric", "pixel art"],"platforms": ["Windows", "macOS"],"madeWith": ["Godot"],"languages": ["English"],"inputs": ["Keyboard", "Mouse"],"accessibility": ["Subtitles"],"averageSession": "About an hour","status": "Released","publishedAt": "2026-01-01T00:00:00Z","updatedAt": "2026-01-01T00:00:00Z","priceUsd": 4.99,"minimumPriceUsd": 0,"pricingModel": "name-your-own-price","isOnSale": false,"salePercent": null,"rating": 4.6,"ratingCount": 1234,"isBrowserPlayable": false,"hasDevlog": true,"files": [{ "name": "sample-game-win.zip", "sizeText": "120 MB", "platforms": ["Windows"] }],"jamName": "Sample Game Jam 2026","jamSlug": "sample-game-jam","jamUrl": "https://itch.io/jam/sample-game-jam","jamEntryId": 1,"reviewCount": 210,"reviewsReturned": 2,"reviews": [{"reviewId": 1,"url": "https://itch.io/post/1","authorName": "player-one","authorUrl": "https://itch.io/profile/player-one","authorSlug": "player-one","authorId": 1,"postedAt": "2026-01-01T00:00:00Z","postedAgo": "3 days ago","body": "Loved the ending.","isReply": false,"replyDepth": 0,"parentReviewId": null,"isDeveloperReply": false},{"reviewId": 2,"url": "https://itch.io/post/2","authorName": "Sample Studio","authorUrl": "https://itch.io/profile/sample-studio","authorSlug": "sample-studio","authorId": 2,"postedAt": "2026-01-01T00:00:00Z","postedAgo": "3 days ago","body": "Thank you, a sequel is in the works.","isReply": true,"replyDepth": 1,"parentReviewId": 1,"isDeveloperReply": true}],"scrapedAt": "2026-01-01T00:00:00Z","sourceUrl": "https://itch.io/games/genre-puzzle"}
Plan Requirement
The default connection setting works out of the box, and the actor waits and rotates to a new connection automatically when one is refused. A residential pool is available if you specifically want one, but this site answers reliably over the default pool and does not need it.
FAQ
How much does it cost?
You pay per record returned, plus one Detail enrichment event for each record where Fetch details and reviews actually ran and the record was returned rather than suppressed. Actor start is charged once per run. The Pricing tab shows the current rates. Use Max results to cap the cost of any run.
Is it legal to scrape itch.io?
This actor collects only publicly available game, review, creator and jam data. You are responsible for how you use it: follow itch.io's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Game descriptions, reviews and jam entries are the creators' and commenters' own words, not facts, and carry their own rights.
Can I get only new or changed games on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only NEW, UPDATED and REAPPEARED records for the same search, and unchanged ones are not billed unless Emit unchanged is on. EXPIRED rows for games that disappeared are produced only once a run has fully scanned the tracked search, never after a capped run, a resumed run, or a browse scope that hit the site's own 200-page depth limit.
What's the most common point of confusion?
The site itself serves at most two filter slots on a browse address, and a chosen ordering other than Popularity uses one of them. Asking for genre, tag, platform, price, jam entry and a non-default ordering all at once needs more slots than the site will serve, so the run stops before spending any requests and names exactly which filters to drop.
Why is a game missing, or the count short, when I searched several keywords or pasted several links?
Max results is split across targets, and when a list is cut short to fit a target's share, the actor still marks every game it read on that page as already scanned, not only the ones it returned. A later keyword or pasted search or browse link that lists one of those unreturned games skips it too, so it is never returned at all. Example: two keywords, Max results 6 (3 each). The first keyword's page has 36 games and returns 3. The second keyword's page has 2 games: one of the first keyword's 33 unreturned games, and one new game. The run returns 4 records instead of 6, and the skipped game is missing from the output. A platform restart part-way through the run carries the same "already scanned" list forward, so it does not bring those games back; Resume from a previous run is not affected. Browse mode, a single keyword, creator mode and jam mode are not affected. Run one keyword or one link per call, or set Max results to 0 (or high enough that every target's share covers everything it returns).
Why did my run fail instead of returning an empty dataset?
If the site refuses every request, the run stops with a clear message so "no games matched" is never confused with "nothing could be read". Run it again in a few minutes. If only some pages could be read, you still get what was found, and the run's status message says how many requests were rejected.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
๐ Want more e-commerce data?
Pair this actor with these related scrapers from the same team:
| ๐งฉ Roblox Scraper Scrape Roblox experiences, marketplace items, users and communities. Player counts... | ๐งฉ CrazyGames Scraper Scrape CrazyGames games with ratings, upvotes and downvotes, total plays and likes... |
| ๐ฑ Wattpad Scraper Scrape Wattpad stories by keyword, tag, category, language or URL. Extract authors... | ๐ Nitori Japan Furniture & Home Goods Scraper Scrape Nitori Japan (nitori-net.jp) furniture and home goods by keyword, category or... |
| ๐ฑ Mastodon From $1/1K. Scrape trending Mastodon profiles and related posts from any Mastodon... | ๐ MUJI Scraper Scrape MUJI products from the United States, Canada and Australia storefronts. Search by... |
๐ Browse all abotapi scrapers
๐ฌ Support & custom scrapers
- ๐ Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- ๐ ๏ธ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- โญ Enjoying it? A quick review on the actor page helps other users find it.