Skip to content

omniplay/itch

Omniplay's itch.io, under any PHP host: a game page's record from its public data.json with no key, and with a server-side API key whether a player owns one of your games (download keys) and the library of the key's own account.

Floor
Provider · Omniplay
Version
1.x
Conformance suite
not wired
Verified for real
Verified in part
Licence
MIT
composer require omniplay/itch:1.x-dev

itch.io for omnisense/omniplay: a game page's record with no key, and - with a server-side API key - whether a player owns one of your games and the library of the key's own account. The provider calls:

Operation Endpoint Key
a record GET https://{creator}.itch.io/{game}/data.json (the page's public data) none
ownership GET https://api.itch.io/games/{id}/download_keys?user_id=... (or email=, download_key=) server-side key
library GET https://api.itch.io/profile/owned-keys?page=...&per_page=500 server-side key

The key is sent as Authorization: Bearer. itch.io has no search API: no search here (its server-side API).

Installation

composer require omniplay/itch

Requires PHP 8.2, omnisense/omniplay (1.x) and symfony/http-client (6.4, 7 or 8).

Credentials

  • None for pages.
  • A server-side API key (the account's settings, API keys; or one from OAuth, scoped) for ownership and the library. Ownership is asked about your own games.

Options

Option Type Default Required
key string null no the server-side API key
user_agent string omniplay/1.0 (+https://github.com/glitchr-omnisense/omniplay) no
api string https://api.itch.io no the server-side API

Capabilities

Contract
SearchInterface no
CatalogueInterface by page, creator/game (GameRef::itch('leafo/x-moon') for https://leafo.itch.io/x-moon)
OwnershipInterface with key: a player is an itch.io user id, a verified e-mail address or a download key
LibraryInterface with key: me only, the key's own account
prices yes; keyless catalogue

attribution: Data from itch.io.

Without key, capabilities() says no library and no ownership, and the registry's library('itch') and ownership('itch') refuse them (NotSupportedException, the core's Registry); owns() and library() called directly are an InvalidConfigException.

Behaviour

A record. A page that is not creator/game (letters, digits, -, _) is null without a call; a data.json without a title is null.

Field Read from
title title
identifiers the page, lower-cased
url links.self, else https://{creator}.itch.io/{game}
developers authors[].name
tags tags
price price and original_price as shown ($2.00, €4,99, $1,000.00, ¥500): the currency from the symbol ($ USD, € EUR, £ GBP, ¥ JPY; USD when none), in ISO 4217 minor units (none for JPY, two for the others); the last . or , followed by one or two digits is the decimal separator, any other a thousands one; the discount computed when the original is higher
images cover_image (Cover), screenshots (Screenshot)

Ownership. A page ref is turned into the game's number from its data.json (an unknown page: false); a numeric ref is used as the number. The player decides the query: digits a user_id, an @ an email, anything else a download_key. A download_key.id in the answer is true; itch.io's "no download key found" or "invalid download key" error is false, whatever its status; any other error a ProviderException. Look up by e-mail only an address the application verified: anyone could type another's.

Library. me only (anything else: InvalidConfigException): the key's owned keys, pages of 500, 20 pages at most, each the game's page (from game.url, else its number) and title; no playtime.

Example

Run live on 2026-10-27 (06:18 UTC), through the core's installation script - one call:

$itch = (new ItchFactory(HttpClient::create()))->create(['key' => getenv('ITCH_API_KEY')]);
$xMoon = $itch->game(GameRef::itch('leafo/x-moon'));
$owns = $itch->owns('12345', GameRef::itch('my-studio/my-game'));      // needs the key
X-Moon [{"itch":"leafo\/x-moon"}] -, 0.00 USD,
  by leafo; https://leafo.itch.io/x-moon

In Symfony:

services:
    Omniplay\Itch\ItchFactory:
        arguments: ['@http_client']
    Omniplay\Registry:
        arguments:
            $factories: ['@Omniplay\Itch\ItchFactory']
            $config:
                itch: { factory: itch, options: { key: '%env(default::ITCH_API_KEY)%' } }

Errors

  • unknown page: null; a ref of another scheme: NotSupportedException; search: NotSupportedException from the registry (The "i" provider (Omniplay\Itch\ItchProvider) does not search.);
  • no key for ownership or the library, a library of anyone but me: InvalidConfigException;
  • a status of 400 or more but 404 (other than "no download key"): ProviderException; a network error: UnreachableException (the key travels in a header, not in the URL).

Verified, and not

Tested offline (Tests/ItchProviderTest.php, in the core's harness, PHP 8.4): X-Moon's page recorded on 2026-10-24, an unknown page, prices in minor units (yen, thousands separators, a sale, composed); ownership by user id and by e-mail, the key's library, a refused key - answers shaped after the documentation. Tests/BareTest.php loads every class with the package's requirements alone. Verified live: X-Moon's page (Tests/LiveTest.php, 2026-10-24; and on 2026-10-27). Not verified: ownership and the library (no key); how itch.io answers "no download key found" (its status) is not documented.

Responsibility

An independent, unofficial client, affiliated with itch.io in no way. Whoever runs it keeps the server-side API's rules (scopes, verified e-mails) and itch.io's terms: see the README.

Propose a change docs/index.md