IGDB, Twitch's games database, for omnisense/omniplay: search and a game's record through Apicalypse queries, a game found by its IGDB number or by its Steam or GOG number, its studios, platforms, genres, themes, cover and screenshots, its score, and its identifiers on Steam, GOG, Epic and itch.io. The provider calls:
| Operation | Request |
|---|---|
| token | POST https://id.twitch.tv/oauth2/token, form-encoded body client_id=...&client_secret=...&grant_type=client_credentials (Twitch's client credentials grant) |
| search | POST https://api.igdb.com/v4/games, body search "..."; fields ...; limit n; |
| a record | POST /v4/games, body fields ...; where id = n; |
| by a store's number | POST /v4/external_games, body fields game; where uid = "620" & external_game_source = 1; limit 1; |
Every query sends Client-ID, Authorization: Bearer <token>, Content-Type: text/plain.
Pictures come from https://images.igdb.com/igdb/image/upload.
Installation
composer require omniplay/igdb
Requires PHP 8.2, omnisense/omniplay (1.x) and symfony/http-client (6.4, 7 or 8).
Credentials
A Twitch application (dev.twitch.tv, an application with client credentials): its client id and client secret. The token is the application's (no user), asked on the first query and asked again a minute before it expires.
Options
| Option | Type | Default | Required | |
|---|---|---|---|---|
client_id |
string | - | yes | |
client_secret |
string | - | yes | |
api |
string | https://api.igdb.com/v4 |
no | |
token_url |
string | https://id.twitch.tv/oauth2/token |
no | |
images |
string | https://images.igdb.com/igdb/image/upload |
no |
Capabilities
| Contract | |
|---|---|
SearchInterface |
yes |
CatalogueInterface |
by igdb, steam, gog |
LibraryInterface, OwnershipInterface |
no |
| prices | no; a key is needed |
attribution: Data from IGDB.com.
Behaviour
The fields asked: name, slug, summary, first_release_date, url, status, cover.image_id, screenshots.image_id, genres.name, themes.name, platforms.name, involved_companies.developer, involved_companies.publisher, involved_companies.company.name, external_games.category, external_games.external_game_source, external_games.uid, total_rating, total_rating_count.
Search escapes quotes and backslashes; language and country are not used (IGDB has neither).
| Field | Read from |
|---|---|
title, url, summary |
name, url, summary |
identifiers |
the IGDB number, and each external game whose source (external_game_source, else the former category) is 1 (steam), 5 (gog), 26 (epic) or 30 (itch): its uid |
released |
first_release_date (a UNIX time), at midnight UTC |
comingSoon |
that date in the future |
developers, publishers |
involved_companies with developer / publisher true |
genres, tags |
genres[].name, themes[].name |
platforms |
platforms[].name folded (PC (Microsoft Windows) -> windows, PlayStation 3 -> playstation) |
images |
the cover at t_cover_big (264 x 374), screenshots at t_screenshot_big (889 x 500) |
ratings |
igdb, total_rating rounded to 1, out of 100, with total_rating_count, when rated |
No price. A Steam or GOG number not found in external_games is null.
Example
<?php
require __DIR__.'/vendor/autoload.php';
use Omniplay\Igdb\IgdbFactory;
use Omniplay\Model\GameRef;
use Omniplay\Model\Scheme;
use Symfony\Component\HttpClient\HttpClient;
$igdb = (new IgdbFactory(HttpClient::create()))->create(['client_id' => getenv('TWITCH_CLIENT_ID'), 'client_secret' => getenv('TWITCH_CLIENT_SECRET')]);
$portal = $igdb->game(GameRef::steam(620)); // found through external_games
echo $portal->title, ' - GOG ', $portal->identifiers->get(Scheme::Gog), "\n";
The record read from the package's test answers (written after IGDB's documentation; no Twitch application was used), in the core's harness on 2026-10-27 - each field, then the calls:
Portal 2 | 2011-04-18 | no price
ids {"gog":"1207658924","igdb":"72","steam":"620"} platforms ["windows","mac","linux","playstation","xbox"]
dev ["Valve"] pub ["Electronic Arts","Valve"] genres ["Puzzle","Platform"] tags ["Science fiction"]
summary Sequel to the acclaimed Portal.
cover https://images.igdb.com/igdb/image/upload/t_cover_big/co1rs4.jpg
screenshot https://images.igdb.com/igdb/image/upload/t_screenshot_big/sc0001.jpg
rating igdb 92.3/100 (1200)
https://www.igdb.com/games/portal-2
> POST https://id.twitch.tv/oauth2/token {"client_id":"example-id","client_secret":"example-secret","grant_type":"client_credentials"} (the query then; the body since 2026-10-29)
> POST https://api.igdb.com/v4/external_games body: fields game; where uid = "620" & external_game_source = 1; limit 1;
> POST https://api.igdb.com/v4/games body: fields name,slug,summary,first_release_date,url,status,cover.image_id,screenshots.image_id,genres.name,themes.name,platforms.name,involved_companies.developer,involved_companies.publisher,involved_companies.company.name,external_games.category,external_games.external_game_source,external_games.uid,total_rating,total_rating_count; where id = 72;
In Symfony:
services:
Omniplay\Igdb\IgdbFactory:
arguments: ['@http_client']
Omniplay\Registry:
arguments:
$factories: ['@Omniplay\Igdb\IgdbFactory']
$config:
igdb: { factory: igdb, options: { client_id: '%env(TWITCH_CLIENT_ID)%', client_secret: '%env(TWITCH_CLIENT_SECRET)%' } }
Errors
- a token refused:
ProviderException(IGDB answered 400 for POST /oauth2/token. {"status":400,"message":"invalid client secret"}); an answer without a token:ProviderExceptionnaming Twitch; - unknown:
null; a ref of another scheme (itch, rawg, epic):NotSupportedException; - a status of 400 or more but 404 (a 429 above 4 requests a second):
ProviderException; a network error:UnreachableException; - a missing
client_idorclient_secret:InvalidConfigException.
The token is asked with the client id and secret in a form-encoded body, as Twitch's documentation
sends them, never in the URL; and a network error's message names the method and the path only,
with the HTTP client's reason without the URL (IGDB could not be reached for POST /oauth2/token: Could not resolve host: id.twitch.tv.). Form-encoded credentials follow Twitch's documentation;
no Twitch application was used to check them live.
Verified, and not
Tested offline (Tests/IgdbProviderTest.php, in the core's harness, PHP 8.4): the token got once, its
credentials in the body and not in the query, the secret out of an unreachable Twitch's message, a
search by Apicalypse (quotes escaped), a game by its Steam number, unknown, only IGDB, Steam and GOG
numbers known. The answers are shaped after IGDB's documentation and written by hand.
Tests/BareTest.php loads every class with the package's requirements alone.
Not verified: no Twitch application was used. IGDB moved external games from category to
external_game_source: both are read, the lookup asks the latter - not seen live.
Responsibility
An independent, unofficial client, affiliated with IGDB or Twitch in no way. Whoever runs it complies with Twitch's developer agreement and IGDB's terms (api-docs.igdb.com): 4 requests a second, credit to IGDB.com. See the README.