# itch.io Game, Review, Creator and Jam Scraper (`abotapi/itch-io-scraper`) Actor

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.

- **URL**: https://apify.com/abotapi/itch-io-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## itch.io Game, Review, Creator and Jam Scraper

Pull structured records out of itch.io (itch.io), the indie game marketplace. 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: every public comment, who wrote it, when, and whether the reply came from the game's own creator.

### 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. That is the difference between "4.9 stars" and knowing what players actually said and how the studio answered.
- **The pay-what-you-want floor, not just the sticker price.** A huge 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 $15.99 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.

### Data You Get

> Sample shape, values are illustrative placeholders, not from a live listing.

| Field | Example |
|---|---|
| `recordType` | `"game"` |
| `recordId` | `"game-00000001"` |
| `gameId` | `00000001` |
| `title` | `"Sample Game Title"` |
| `url` | `"https://sample-studio.itch.io/sample-game"` |
| `developerName` | `"Sample Studio"` |
| `developerUrl` | `"https://sample-studio.itch.io"` |
| `shortText` | `"A one line tagline for the game."` |
| `coverImageUrl` | `"https://img.itch.zone/000000000/315x250/cover.png"` |
| `genre` | `"Puzzle"` |
| `tags` | `["atmospheric", "pixel art", "singleplayer"]` |
| `platforms` | `["Windows", "macOS", "Linux"]` |
| `priceUsd` | `4.99` |
| `minimumPriceUsd` | `0` |
| `pricingModel` | `"name-your-own-price"` |
| `isOnSale` | `true` |
| `salePercent` | `40` |
| `rating` | `4.6` |
| `ratingCount` | `1234` |
| `status` | `"Released"` |
| `publishedAt` | `"2026-01-01T00:00:00Z"` |
| `updatedAt` | `"2026-01-01T00:00:00Z"` |
| `madeWith` | `["Godot"]` |
| `languages` | `["English"]` |
| `inputs` | `["Keyboard", "Mouse"]` |
| `accessibility` | `["Subtitles"]` |
| `averageSession` | `"About an hour"` |
| `files` | `[{"name": "sample-game-win.zip", "sizeText": "120 MB", "platforms": ["Windows"]}]` |
| `isBrowserPlayable` | `false` |
| `jamName` | `"Sample Game Jam 2026"` |
| `jamUrl` | `"https://itch.io/jam/sample-game-jam"` |
| `reviewCount` | `210` |
| `reviewsReturned` | `20` |
| `reviews` | `[{"authorName": "player-one", "body": "Loved the ending.", "isDeveloperReply": false}]` |
| `followers` | `12345` |
| `gameCount` | `18` |
| `topEntries` | `[{"jamRank": 1, "jamScore": 4.689, "jamCriteria": [{"criterion": "Style", "rank": 2}]}]` |
| `changeType` | `"NEW"` |
| `scrapedAt` | `"2026-01-01T00:00:00Z"` |

### How to Use

Browse the index, no extra requests per game:

```json
{
  "mode": "browse",
  "genres": ["Puzzle"],
  "sortBy": "top-rated",
  "maxItems": 100
}
```

Browse with the full detail lookup and the review thread:

```json
{
  "mode": "browse",
  "tags": ["horror"],
  "price": "free",
  "fetchDetails": true,
  "maxReviewsPerGame": 50,
  "maxItems": 25
}
```

A creator's whole catalogue plus their follower count:

```json
{
  "mode": "developer",
  "creators": ["sample-studio", "another-studio"],
  "fetchDetails": true
}
```

A ranked jam with its full result table:

```json
{
  "mode": "jam",
  "jams": ["sample-game-jam-2026"],
  "fetchDetails": true,
  "maxJamEntries": 100
}
```

Paste links of any kind:

```json
{
  "mode": "url",
  "urls": [
    "https://sample-studio.itch.io/sample-game",
    "https://itch.io/games/top-rated/genre-puzzle",
    "https://itch.io/jam/sample-game-jam"
  ],
  "fetchDetails": true
}
```

### 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 above | 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. `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. |

#### Three things 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 it is a smaller filter surface.** The site serves a single page of results per keyword and publishes no second page. Use browse mode when you need a large set. Search also publishes a much shorter filter vocabulary than the browse index: a platform option, a free or paid split and a demo flag, and nothing else. There is 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 are not available in creator or jam mode.

Which filter works where:

| | browse | search | url | creator | jam |
|---|---|---|---|---|---|
| `genres`, `tags`, `jamEntries`, `sortBy` | yes | no | no | no | no |
| `platform`, `hasDemo`, `price: free` | yes | yes | yes | no | no |
| `price: on-sale / under-5 / under-15` | yes | no | no | no | no |
| `minRating`, `minRatingCount` | yes | yes | yes | no | no |

In url mode the filters above apply to a pasted search address. A pasted browse address is walked with the filter segments already in it, and the run says so by name when both are set at once.

A browse scope also stops at the site's own depth limit of 200 pages, which is 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.

### Output Example

> Sample shape, values are illustrative placeholders, not from a live listing.

```json
{
  "recordType": "game",
  "recordId": "game-00000001",
  "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"
}
```

### Reviews, and what is not in them

A review row is exactly what the public comment thread shows to any visitor: the commenter's display name, their public handle, their profile address, their numeric user id, the exact time, the body text, where the comment sits in the reply tree, and whether the person answering is the game's own creator. The commenter's avatar image is deliberately not returned.

`reviewCount` is the total the page itself declares, which is usually far larger than `reviewsReturned`. Raise `maxReviewsPerGame` to walk further down the thread.

### Incremental mode, and what counts as a change

In incremental mode each record carries `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt`. Two kinds of field are deliberately left out of the comparison, because including them would mark every record changed on every run:

- The review thread itself. A busy thread is entirely new rows within hours. Real movement is still detected, because `reviewCount`, `rating` and `ratingCount` are all compared, so a game whose thread grew is still reported as UPDATED and still names those fields in `changedFields`. `reviews` will never appear there.
- A jam entry's rank and score, which move with whichever ordering the run happened to read.

`EXPIRED` rows are only produced once a run has fully scanned the tracked search, so never after a capped run, a resumed run, or a scope that hit the site's 200-page depth limit.

### Send results into your apps (MCP connectors)

Results can optionally be piped into the apps you already use, through Model Context Protocol connectors, without changing the dataset at all.

1. Authorize a connector under Apify, Settings, API & Integrations.
2. Select it in the **Export to your apps (MCP connectors, optional)** section of the input (`mcpConnectors`).
3. For Notion, set `notionParentPageUrl` to the page under which item pages should be created.
4. `maxNotifyListings` caps how many items are written to each connector per run.

Supported out of the box: Notion, Linear, Airtable and Apify. What gets written is a condensed, human readable summary per item, a title plus the key fields flattened to plain text, not the full JSON: nested objects collapse to their main value and arrays trim to a few names. The complete record always stays in the Apify dataset. If a connector fails, the run still succeeds and the dataset is unaffected.

### Plan Requirement

Runs on any Apify account. Enable Apify Proxy in the Connection section for the most reliable results.

# Actor input Schema

## `mode` (type: `string`):

Choose 'browse' to walk the site's game index with the filters below, 'search' to search by keyword, 'developer' to pull named creators with their catalogue, 'jam' to read game jams and their ranked results, or 'url' to scrape pasted game, creator, jam, browse and search links.

## `queries` (type: `array`):

Only used when mode = search, ignored in the other modes. One or more keywords, for example 'horror', 'pixel art platformer' or a studio name. The site returns one page of matches per keyword.

## `creators` (type: `array`):

Only used when mode = developer, ignored in the other modes. Creator handles such as 'gbpatch', full creator page links, or a link to any game they made.

## `jams` (type: `array`):

Only used when mode = jam, ignored in the other modes. Jam handles such as 'gmtk-2024' or full jam links. Leave empty to read a whole listing instead.

## `jamScope` (type: `string`):

Only used when mode = jam and Jams is empty. Which of the site's own jam listings to read.

## `urls` (type: `array`):

Only used when mode = url, ignored in the other modes. Mix freely: game pages such as https://studio.itch.io/game-name, creator pages, jam pages, browse addresses such as https://itch.io/games/genre-puzzle and search addresses.

## `genres` (type: `array`):

Browse mode only. Optional, one filter slot each. Genres written the way the site writes them, for example 'Puzzle', 'Visual Novel' or 'Role Playing'. Capitals, spaces and punctuation do not matter. Checked against the site's OWN published genre list every run; a genre the site does not publish is reported with close matches, and if none of your genres exist the run stops rather than quietly returning the unfiltered index. Note the site's own behaviour: its genre listing returns games in that genre AND closely related ones, so roughly half of a page carries that genre as its own primary genre.

## `tags` (type: `array`):

Browse mode only. Optional, one filter slot each. Tags written the way they appear under a game, for example 'horror', 'pixel art' or 'multiplayer'. A tag the site does not publish stops the run with a message naming it, rather than returning the unfiltered index.

## `jamEntries` (type: `string`):

Browse mode only. Optional, one filter slot. Keep only games that were submitted to a game jam, or only games that were not. The site's keyword search publishes no jam-entry option, so choosing one outside browse mode stops the run instead of being ignored.

## `sortBy` (type: `string`):

Browse mode only. The order the site returns results in. Every value is one of the site's OWN orderings, applied at the source. Popularity is the site default and is the only value that does NOT use one of the two filter slots, so leaving it alone frees a slot for a second filter. The site's keyword search returns results in its own relevance order and offers no ordering option, so choosing anything other than the default outside browse mode stops the run instead of being ignored.

## `platform` (type: `string`):

Browse, search and url modes. Optional. Keep only games released for this platform. Applied by the site itself either way, so it narrows at the source: as one browse filter slot, or as the search facet of the same name. A pasted browse address in url mode keeps its own platform segment instead.

## `price` (type: `string`):

Keep only games in this price band, applied by the site itself. The browse index publishes all five bands and each uses one filter slot. The keyword search publishes only the free or paid split, so 'Currently discounted', '$5 or less' and '$15 or less' are BROWSE ONLY: choosing one in search or url mode stops the run with a message rather than quietly returning every price.

## `hasDemo` (type: `boolean`):

Browse, search and url modes. Keep only games that publish a playable demo. One browse filter slot, or the search facet of the same name. A pasted browse address in url mode keeps its own segments instead.

## `minRating` (type: `integer`):

Browse, search and url modes. Optional. Keep only games rated at or above this score on the site's own 0 to 5 scale. No listing publishes a rating, so this reads each game's own page and requires Fetch details and reviews. Use 0 for no minimum.

## `minRatingCount` (type: `integer`):

Browse, search and url modes. Optional. Keep only games rated at least this many times, which is the usual way to drop games whose average rests on a handful of votes. Reads each game's own page and requires Fetch details and reviews. Use 0 for no minimum.

## `fetchDetails` (type: `boolean`):

Read each record's own page. For a game that adds the description, the full tag, language, input and accessibility lists, the publish and update stamps, the exact price and pay-what-you-want floor, the file list, the jam it was submitted to, the rating and rating count, and the REVIEW THREAD: every public comment with its author, the exact time, the body, the reply nesting, and whether the reply came from the game's own creator. For a creator it adds the public follower, post and topic counters. For a jam it adds the ranked result table. One extra request per record, billed as one Detail enrichment event per record returned.

## `maxReviewsPerGame` (type: `integer`):

Cap on how many comments from a game's review thread are returned. Use 0 to return the game without its thread. The game's own page already carries about 40 recent comments at no extra cost; a higher cap walks the thread further, which costs extra requests but is never charged more than the single Detail enrichment event for that game.

## `includeJamEntries` (type: `boolean`):

Used in jam mode and for a jam link pasted in url mode, together with Fetch details and reviews. On by default: the jam row is returned with its ranked entry table, each entry carrying its overall rank, its number of ratings, its adjusted score, and its rank and score under every criterion the jam scored on. Switch off to return the jam row alone.

## `maxJamEntries` (type: `integer`):

Cap on how many ranked entries are returned per jam. Use 0 for every entry the results page publishes.

## `maxItems` (type: `integer`):

Maximum number of records to return across the whole run. This is the run's cap. Use 0 for unlimited. Note the site's own limit underneath it: one browse scope stops at page 200, which is 7,200 games; narrow the filters or change the ordering to reach past that.

## `maxPages` (type: `integer`):

Maximum number of result pages read per keyword, creator, jam or browse address. 0 means no limit, which is the default: the run then stops only at Max results, at the end of the results, or at the site's own 200-page browse limit.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large pull without returning or charging for records already collected there. Use this after an interrupted run. For recurring daily monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns every matching record as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED records. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each mode, target and filter setup; use State key to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the mode, targets and filters, so different searches never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, so never when Max results capped it, when Resume was used, or when a scope hit the site's own 200-page browse limit. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.

## `proxy` (type: `object`):

Apify Proxy is recommended. The standard pool is the default and is sufficient for this site.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "browse",
  "queries": [
    "horror"
  ],
  "creators": [
    "gbpatch"
  ],
  "jams": [
    "gmtk-2024"
  ],
  "jamScope": "in-progress",
  "urls": [
    "https://itch.io/games/top-rated/genre-puzzle",
    "https://gbpatch.itch.io/our-life"
  ],
  "jamEntries": "any",
  "sortBy": "popular",
  "platform": "any",
  "price": "any",
  "hasDemo": false,
  "minRating": 0,
  "minRatingCount": 0,
  "fetchDetails": false,
  "maxReviewsPerGame": 20,
  "includeJamEntries": true,
  "maxJamEntries": 20,
  "maxItems": 20,
  "maxPages": 0,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "browse",
    "queries": [
        "horror"
    ],
    "creators": [
        "gbpatch"
    ],
    "jams": [
        "gmtk-2024"
    ],
    "urls": [
        "https://itch.io/games/top-rated/genre-puzzle",
        "https://gbpatch.itch.io/our-life"
    ],
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/itch-io-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "browse",
    "queries": ["horror"],
    "creators": ["gbpatch"],
    "jams": ["gmtk-2024"],
    "urls": [
        "https://itch.io/games/top-rated/genre-puzzle",
        "https://gbpatch.itch.io/our-life",
    ],
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/itch-io-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "browse",
  "queries": [
    "horror"
  ],
  "creators": [
    "gbpatch"
  ],
  "jams": [
    "gmtk-2024"
  ],
  "urls": [
    "https://itch.io/games/top-rated/genre-puzzle",
    "https://gbpatch.itch.io/our-life"
  ],
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/itch-io-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/itch-io-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/p6p1d78J7gznsyVbJ/builds/QdBdGLlfIVZdKny4b/openapi.json
