Get started
This is a way to run your own Twitch API "gate-way" service that only requires the user name/channel name to pull data. It acts as a public gateway to Twitch's API. This is useful when creating your own Twitch tools/apps and just want to get data from Twitch without passing in your client id and auth token into your code and manually refreshing your auth token every 3 months. Auth token automatically refreshes on the server every day. All requests use GET to pull data. Nothing is posted back to Twitch and nothing is stored on the server. Once set up, getting data from Twitch is as simple as going to a URL and parsing the returned JSON string.
Requirements
- PHP 7.4 or higher
- Composer
- nginx or Apache web server
Installation
- Clone the repository to your server.
- Install php composer. Installation instructions.
- Run `composer install` in the root directory of the cloned repository.
- Set up a virtual host for your domain/subdomain. Review the nginx.conf file as an example.
- Rename `sample.env` to `.env`
- Edit the `.env` file with your Twitch client id and auth token.
- Create file `.auth` inside the `config` directory. Example: `config/.auth`. Make sure that the `.auth` file has write permissions.
(Optional) Install Using Docker
- Install docker and docker-compose
- Clone the repository to your server or local machine.
- Rename `sample.env` to `.env`
- Edit the `.env` file with your Twitch client id and auth token.
- Create file `.auth` inside the `config` directory. Example: `config/.auth`. Make sure that the `.auth` file has write permissions.
- docker-compose build
- docker-compose up -d
- The `docker-compose.yml` will create 3 containers (php-fpm, composer, nginx)
- You should now be able to access the application by visiting http://localhost:8080 in your web browser.
Get User Clips
# Here is a curl example
curl -X GET 'http://localhost:8080/getuserclips.php?channel=twitch&limit=2&start_date=2023-02-15T00:00:00Z&end_date=2024-02-15T00:00:00Z&prefer_featured=false'
Make a GET call to the following url :
http://localhost:8080/getuserclips.php
Result example :
{
"data": [
{
"item": 1,
"id": "CrispyJollyGullHassaanChop-nPlLKGxGRcBj37e4",
"url": "https://clips.twitch.tv/CrispyJollyGullHassaanChop-nPlLKGxGRcBj37e4",
"embed_url": "https://clips.twitch.tv/embed?clip=CrispyJollyGullHassaanChop-nPlLKGxGRcBj37e4",
"broadcaster_id": "12826",
"broadcaster_name": "Twitch",
"creator_id": "932351392",
"creator_name": "power_tester",
"video_id": "152089018",
"game_id": "",
"language": "en",
"title": "F1 2017 E3 Gameplay!",
"view_count": 2828001,
"created_at": "2023-07-12T01:07:36Z",
"thumbnail_url": "https://static-cdn.jtvnw.net/twitch-clips/ErNyUZz5SyhsRkXAY9-3uA/AT-cm%7CErNyUZz5SyhsRkXAY9-3uA-preview-480x272.jpg",
"duration": 59.9,
"vod_offset": 228,
"is_featured": false,
"clip_url": "https://production.assets.clips.twitchcdn.net/ErNyUZz5SyhsRkXAY9-3uA/AT-cm%7CErNyUZz5SyhsRkXAY9-3uA.mp4?sig=2a30ffed3c2dad4306781cdae33e2c552614d5f6&token=%7B%22authorization%22%3A%7B%22forbidden%22%3Afalse%2C%22reason%22%3A%22%22%7D%2C%22clip_uri%22%3A%22https%3A%2F%2Fproduction.assets.clips.twitchcdn.net%2FErNyUZz5SyhsRkXAY9-3uA%2FAT-cm%257CErNyUZz5SyhsRkXAY9-3uA.mp4%22%2C%22clip_slug%22%3A%22CrispyJollyGullHassaanChop-nPlLKGxGRcBj37e4%22%2C%22device_id%22%3Anull%2C%22expires%22%3A1743460717%2C%22user_id%22%3A%22%22%2C%22version%22%3A2%7D"
},
{
"item": 2,
"id": "VastOutstandingMinkNononoCat-hjFbXj-a8-WvyN0z",
"url": "https://clips.twitch.tv/VastOutstandingMinkNononoCat-hjFbXj-a8-WvyN0z",
"embed_url": "https://clips.twitch.tv/embed?clip=VastOutstandingMinkNononoCat-hjFbXj-a8-WvyN0z",
"broadcaster_id": "12826",
"broadcaster_name": "Twitch",
"creator_id": "47622498",
"creator_name": "Zekronz",
"video_id": "1996381424",
"game_id": "509658",
"language": "en",
"title": "CEO anwsers the real question.",
"view_count": 105624,
"created_at": "2023-12-06T02:28:09Z",
"thumbnail_url": "https://static-cdn.jtvnw.net/twitch-clips/92BS8IYxW14_mvPlr8jdMw/AT-cm%7C92BS8IYxW14_mvPlr8jdMw-preview-480x272.jpg",
"duration": 12.8,
"vod_offset": 2202,
"is_featured": false,
"clip_url": "https://production.assets.clips.twitchcdn.net/92BS8IYxW14_mvPlr8jdMw/AT-cm%7C92BS8IYxW14_mvPlr8jdMw.mp4?sig=90622ecfcefc1b65585b776691b547d22badfda8&token=%7B%22authorization%22%3A%7B%22forbidden%22%3Afalse%2C%22reason%22%3A%22%22%7D%2C%22clip_uri%22%3A%22https%3A%2F%2Fproduction.assets.clips.twitchcdn.net%2F92BS8IYxW14_mvPlr8jdMw%2FAT-cm%257C92BS8IYxW14_mvPlr8jdMw.mp4%22%2C%22clip_slug%22%3A%22VastOutstandingMinkNononoCat-hjFbXj-a8-WvyN0z%22%2C%22device_id%22%3Anull%2C%22expires%22%3A1743460717%2C%22user_id%22%3A%22%22%2C%22version%22%3A2%7D"
}
]
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| channel | String | (required) Twitch channel name |
| start_date | String | (optional) date formatted as YYYY-MM-DDTHH:MM:SSZ |
| end_date | String | (optional) date formatted as YYYY-MM-DDTHH:MM:SSZ |
| prefer_featured | Boolean | (optional - default: false) |
| limit | Integer | (optional - default: 100) A limit on the number of objects to be returned, between 1 and 100. |
| id | String | (example) ?id=VictoriousAwkwardPheasantKevinTurtle-xT8tH7fW0oU0vZ8gT4 |
| shuffle | Boolean | (example) Shuffle the returned objects. IE: ?channel=twitch&shuffle=true |
| random | Boolean | (example) Pull a single random clip. IE: ?channel=twitch&random=true |
| count | Integer | (example) Used with `random`. IE: ?channel=twitch&random=true&count=4 |
Get Stream
# Here is a curl example
curl -X GET 'http://localhost:8080/getstream.php?channel=gogcom'
Make a GET call to the following url :
http://localhost:8080/getstream.php
Result example :
{
"data": [
{
"id": "318797173500",
"user_id": "43255859",
"user_login": "gogcom",
"user_name": "GOGcom",
"game_id": "4120",
"game_name": "Vampire: The Masquerade - Redemption",
"type": "live",
"title": "@ashsaidhi indulges vampiric activities in Vampire: The Masquerade - Redemption 50% off!",
"viewer_count": 88,
"started_at": "2025-03-31T18:02:26Z",
"language": "en",
"thumbnail_url": "https://static-cdn.jtvnw.net/previews-ttv/live_user_gogcom-{width}x{height}.jpg",
"tag_ids": [
],
"tags": [
"GOG",
"English",
"DRMfree"
],
"is_mature": false
}
],
"pagination": {
"cursor": "eyJiIjp7IkN1cnNvciI6ImV5SnpJam80T0M0Mk5qRXdOekk1TlRBME9UZzBOU3dpWkNJNlptRnNjMlVzSW5RaU9uUnlkV1Y5In0sImEiOnsiQ3Vyc29yIjoiIn19"
}
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| channel | String | (required) Twitch channel name |
| id | Integer | (optional) Twitch channel id |
Get User Info
# Here is a curl example
curl -X GET 'http://localhost:8080/getuserinfo.php?channel=twitch'
Make a GET call to the following url :
http://localhost:8080/getuserinfo.php
Result example :
{
"data": [
{
"id": "12826",
"login": "twitch",
"display_name": "Twitch",
"type": "",
"broadcaster_type": "partner",
"description": "Twitch is where thousands of communities come together for whatever, every day. ",
"profile_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/d5e6ebb4-a245-4ebf-bea6-2183e2f39600-profile_image-300x300.png",
"offline_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/3f5f72bf-ae59-4470-8f8a-730d9ef87500-channel_offline_image-1920x1080.png",
"view_count": 0,
"created_at": "2007-05-22T10:39:54Z"
}
]
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| channel | String | (required) Twitch channel name |
| id | Integer | (optional) Twitch channel id |
Get Game
# Here is a curl example
curl -X GET 'http://localhost:8080/getgame.php?id=1299144050'
Make a GET call to the following url :
http://localhost:8080/getgame.php
* Use only one of these parameters
Result example :
{
"data": [
{
"id": "1299144050",
"name": "Disney Speedstorm",
"box_art_url": "https://static-cdn.jtvnw.net/ttv-boxart/1299144050_IGDB-{width}x{height}.jpg",
"igdb_id": "191402",
"box_art_url_scaled": "https://static-cdn.jtvnw.net/ttv-boxart/1299144050_IGDB-285x380.jpg"
}
]
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| id | Integer | (optional) Game id: `1299144050` |
| name | String | (optional) Game name: `Disney Speedstorm` |
Get User Status
# Here is a curl example
curl -X GET 'http://localhost:8080/getuserstatus.php?channel=twitch'
Make a GET call to the following url :
http://localhost:8080/getuserstatus.php
Result example :
{
"data": [
{
"broadcaster_id": "12826",
"broadcaster_login": "twitch",
"broadcaster_name": "Twitch",
"broadcaster_language": "en",
"game_id": "509658",
"game_name": "Just Chatting",
"title": "Twitch Public Access (March 2025) | w/ @merrykish @friskk @grayovercastart @pleasantlytwstd",
"delay": 0,
"tags": [
"twıtch",
"2025",
"justchatting",
"English",
"twitchpublicaccess"
],
"content_classification_labels": [
],
"is_branded_content": false
}
]
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| channel | String | (required) Twitch channel name |
| id | Integer | (optional) Twitch channel id |
Get User Emotes
# Here is a curl example
curl -X GET 'http://localhost:8080/getuseremotes.php?channel=twitch'
Make a GET call to the following url :
http://localhost:8080/getuseremotes.php
Result example :
{
"data": [
{
"id": "emotesv2_90ae588b6ca34c11b8778367d4c08290",
"name": "twitchLOVE",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_90ae588b6ca34c11b8778367d4c08290/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_90ae588b6ca34c11b8778367d4c08290/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_90ae588b6ca34c11b8778367d4c08290/static/light/3.0"
},
"tier": "",
"emote_type": "subscriptions",
"emote_set_id": "374814395",
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_7d7473ef8ba54ce2b2f8e29d078f90bf",
"name": "twitchAsk",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_7d7473ef8ba54ce2b2f8e29d078f90bf/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_7d7473ef8ba54ce2b2f8e29d078f90bf/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_7d7473ef8ba54ce2b2f8e29d078f90bf/static/light/3.0"
},
"tier": "",
"emote_type": "follower",
"emote_set_id": "e105cd06-6f1c-4276-8fb8-da32fb664835",
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_a3555e43b9594ca6835dbe15d52415c6",
"name": "twitchLincLegend",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_a3555e43b9594ca6835dbe15d52415c6/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_a3555e43b9594ca6835dbe15d52415c6/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_a3555e43b9594ca6835dbe15d52415c6/static/light/3.0"
},
"tier": "",
"emote_type": "follower",
"emote_set_id": "e105cd06-6f1c-4276-8fb8-da32fb664835",
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_9c38e116e5e84f51b338ca0779ba7c2c",
"name": "twitchDino",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_9c38e116e5e84f51b338ca0779ba7c2c/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_9c38e116e5e84f51b338ca0779ba7c2c/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_9c38e116e5e84f51b338ca0779ba7c2c/static/light/3.0"
},
"tier": "",
"emote_type": "follower",
"emote_set_id": "e105cd06-6f1c-4276-8fb8-da32fb664835",
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_91290c954bae4c53849c2b9d540e96c9",
"name": "twitchSmart",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_91290c954bae4c53849c2b9d540e96c9/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_91290c954bae4c53849c2b9d540e96c9/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_91290c954bae4c53849c2b9d540e96c9/static/light/3.0"
},
"tier": "",
"emote_type": "follower",
"emote_set_id": "e105cd06-6f1c-4276-8fb8-da32fb664835",
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_196f36b3cc1b496585121be2826fb8e1",
"name": "twitchFollow",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_196f36b3cc1b496585121be2826fb8e1/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_196f36b3cc1b496585121be2826fb8e1/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_196f36b3cc1b496585121be2826fb8e1/static/light/3.0"
},
"tier": "",
"emote_type": "follower",
"emote_set_id": "e105cd06-6f1c-4276-8fb8-da32fb664835",
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
}
],
"template": "https://static-cdn.jtvnw.net/emoticons/v2/{{id}}/{{format}}/{{theme_mode}}/{{scale}}"
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| channel | String | (required) Twitch channel name |
Get User Global Emotes
# Here is a curl example
curl -X GET 'http://localhost:8080/getglobalemotes.php'
Make a GET call to the following url :
http://localhost:8080/getglobalemotes.php
Result example :
{
"data": [
{
"id": "emotesv2_2babf8f02c9e480dad8ced0e6e266d4a",
"name": "INZOIPsyCat",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_2babf8f02c9e480dad8ced0e6e266d4a/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_2babf8f02c9e480dad8ced0e6e266d4a/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_2babf8f02c9e480dad8ced0e6e266d4a/static/light/3.0"
},
"format": [
"static",
"animated"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_634d9f10a8bf4776ad46df1bb2c9a7ca",
"name": "ClixHuh",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_634d9f10a8bf4776ad46df1bb2c9a7ca/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_634d9f10a8bf4776ad46df1bb2c9a7ca/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_634d9f10a8bf4776ad46df1bb2c9a7ca/static/light/3.0"
},
"format": [
"static"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
},
{
"id": "emotesv2_a7ab2c184e334d4a9784e6e5d51947f7",
"name": "WeDidThat",
"images": {
"url_1x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_a7ab2c184e334d4a9784e6e5d51947f7/static/light/1.0",
"url_2x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_a7ab2c184e334d4a9784e6e5d51947f7/static/light/2.0",
"url_4x": "https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_a7ab2c184e334d4a9784e6e5d51947f7/static/light/3.0"
},
"format": [
"static",
"animated"
],
"scale": [
"1.0",
"2.0",
"3.0"
],
"theme_mode": [
"light",
"dark"
]
}
],
"template": "https://static-cdn.jtvnw.net/emoticons/v2/{{id}}/{{format}}/{{theme_mode}}/{{scale}}"
}
QUERY PARAMETERS
| Field | Type | Description |
|---|
Get User Follows
# Here is a curl example
curl -X GET 'http://localhost:8080/getuserfollows.php?channel=teklynk&limit=5&ref=cGZ2dGl8NzVwW5E7YWJsNDB9aXQwYTMwZWlwc3py&clientId=Y8VxbDF7b9Q0wWVhYmpyM1NuYzZhZGpuJSnDB0'
Make a GET call to the following url :
http://localhost:8080/getuserfollows.php
* Requires your Twitch access token with a scope of moderator:read:followers and your Twitch client id.
Result example :
{
"total": 188,
"data": [
{
"user_id": "28845797",
"user_login": "zarstrum",
"user_name": "Zarstrum",
"followed_at": "2025-02-27T13:58:04Z"
},
{
"user_id": "472548624",
"user_login": "drunkula",
"user_name": "Drunkula",
"followed_at": "2025-01-05T20:59:38Z"
},
{
"user_id": "654301306",
"user_login": "nahumshalman",
"user_name": "NahumShalman",
"followed_at": "2024-12-20T15:34:08Z"
},
{
"user_id": "48806156",
"user_login": "snoozaya_",
"user_name": "Snoozaya_",
"followed_at": "2024-12-13T20:21:52Z"
},
{
"user_id": "588952005",
"user_login": "exlipse7",
"user_name": "exlipse7",
"followed_at": "2024-12-13T20:21:35Z"
}
],
"pagination": {
"cursor": "eyJiIjpudWxsLCJhIjp7IkN1cnNvciI6ImV5SjBjQ0k2SW5WelpYSTZOVGc0T1RVeU1EQTFPbVp2Ykd4dmQzTWlMQ0owY3lJNkluVnpaWEk2TmpVeE5qWTVOVFlpTENKcGNDSTZJblZ6WlhJNk5qVXhOalk1TlRZNlptOXNiRzkzWldSZllua2lMQ0pwY3lJNklqRTNNelF4TWpFeU9UVTNOakF4TVRVM09UUWlmUT09In19"
}
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| clientId | String | (required) Twitch client id (base64 encoded) |
| ref | String | (required) Twitch auth token (base64 encoded) |
| channel | String | (required) Twitch channel name |
| limit | Integer | (optional - default: 100) A limit on the number of objects to be returned, between 1 and 100. |
| before | String | pagination: cursor |
| after | String | pagination: cursor |
Get User Follows
# Here is a curl example
curl -X GET 'http://localhost:8080/getuserfollowing.php?channel=teklynk&limit=5&ref=cGZ2dGl8NzVwW5E7YWJsNDB9aXQwYTMwZWlwc3py&clientId=Y8VxbDF7b9Q0wWVhYmpyM1NuYzZhZGpuJSnDB0'
Make a GET call to the following url :
http://localhost:8080/getuserfollowing.php
* Requires your Twitch access token with a scope of user:read:follows and your Twitch client id.
Result example :
{
"total": 564,
"data": [
{
"broadcaster_id": "1273402269",
"broadcaster_login": "retromaggie",
"broadcaster_name": "retromaggie",
"followed_at": "2025-03-07T19:26:13Z"
},
{
"broadcaster_id": "64914688",
"broadcaster_login": "liquessen",
"broadcaster_name": "Liquessen",
"followed_at": "2025-02-24T16:10:17Z"
},
{
"broadcaster_id": "406887039",
"broadcaster_login": "toastiibear",
"broadcaster_name": "ToastiiBear",
"followed_at": "2025-02-24T09:08:47Z"
},
{
"broadcaster_id": "119614545",
"broadcaster_login": "mrbowlerhatlive",
"broadcaster_name": "MrBowlerHatLive",
"followed_at": "2025-02-24T05:50:28Z"
},
{
"broadcaster_id": "412782875",
"broadcaster_login": "ilija_supertzar",
"broadcaster_name": "ilija_supertzar",
"followed_at": "2025-02-23T03:54:31Z"
}
],
"pagination": {
"cursor": "eyJiIjpudWxsLCJhIjp7IkN1cnNvciI6ImV5SjBjQ0k2SW5WelpYSTZOalV4TmpZNU5UWTZabTlzYkc5M2N5SXNJblJ6SWpvaWRYTmxjam8wTVRJM09ESTROelVpTENKcGNDSTZJblZ6WlhJNk5qVXhOalk1TlRZNlptOXNiRzkzY3lJc0ltbHpJam9pTVRjME1ESTRNamczTVRjNU1qUXdNakU0TVNKOSJ9fQ"
}
}
QUERY PARAMETERS
| Field | Type | Description |
|---|---|---|
| clientId | String | (required) Twitch client id (base64 encoded) |
| ref | String | (required) Twitch auth token (base64 encoded) |
| channel | String | (required) Twitch channel name |
| limit | Integer | (optional - default: 100) A limit on the number of objects to be returned, between 1 and 100. |
| before | String | pagination: cursor |
| after | String | pagination: cursor |