Webhook
Twitch can POST
notifications to your server via EventSub.
Your server must accept public traffic on port 443, and have a valid SSL certificate (consider using ZeroSSL or Let's Encrypt to obtain a free SSL certificate).
For development purposes, you can utilize ngrok or a Cloudflare Tunnel (among other options) to generate a HTTPS URL that serves as a reverse proxy to your localhost webhook server.
If your server's firewall prevents incoming webhook requests, consider using a Conduit backed by websockets instead.
EventSub Subscription Management
With webhooks, you utilize an app access token to create and delete EventSub subscriptions.
Since certain subscription types require user authorization, these users must authenticate with your Client ID to generate a user access token (but you do not need to maintain this user token to utilize webhooks).
If the subscription does not have a scope requirement, you do not need user authorization, but the subscription will have a cost
of 1.
When your Client ID has user authorization, the subscription has a cost
of 0.
By default, every Client ID has a max_total_cost
of 10,000 for webhooks.
When your webhooks server start, you should call TwitchHelix#getEventSubSubscriptions
to check whether your EventSub subscriptions are already healthy (so you don't create duplicate subscriptions).
Twitch imposes a limit of three (3) subscriptions with the same type
and condition
values.
To create EventSub subscriptions, you would call TwitchHelix#createEventSubSubscription
.
The first argument must be an app access token (or null
if withDefaultAuthToken
is an app access token OR withClientId
/withClientSecret
is specified while withDefaultAuthToken
is not specified).
The second argument is an EventSubSubscription
that includes type
, version
, condition
, and transport
(with callback
and secret
specified, while method
is set to "webhook"
).
It is easiest to create EventSubSubscription
instances through our SubscriptionTypes
utility class:
- Java
- Kotlin
- Groovy
EventSubSubscription sub = SubscriptionTypes.STREAM_ONLINE.prepareSubscription(
builder -> builder.broadcasterUserId("channel-id-goes-here").build(),
EventSubTransport.builder()
.callback("your-webhook-url")
.secret("your-eventsub-secret")
.method(EventSubTransportMethod.WEBHOOK)
.build()
);
helix.createEventSubSubscription(null, sub).execute();
val sub = SubscriptionTypes.STREAM_ONLINE.prepareSubscription(
{ builder -> builder.broadcasterUserId("channel-id-goes-here").build() },
EventSubTransport.builder()
.callback("your-webhook-url")
.secret("your-eventsub-secret")
.method(EventSubTransportMethod.WEBHOOK)
.build()
)
helix.createEventSubSubscription(null, sub).execute()
def sub = SubscriptionTypes.STREAM_ONLINE.prepareSubscription(
{ builder -> builder.broadcasterUserId("channel-id-goes-here").build() },
EventSubTransport.builder()
.callback("your-webhook-url")
.secret("your-eventsub-secret")
.method(EventSubTransportMethod.WEBHOOK)
.build()
)
helix.createEventSubSubscription(null, sub).execute()
EventSub Webhook subscriptions require a shared secret to generate the Twitch-Eventsub-Message-Signature
header.
This secret must be between 10 and 100 ASCII characters.
Avoid reusing your client secret for the EventSub secret.
It is best practice to utilize a cryptographically-secure random generator to create this secret.
It is acceptable to utilize the same secret across multiple EventSub subscriptions.
While Twitch does not officially document their specific retry policy, it has been observed that they employ exponential backoff to retry failed notifications up to 5 times over a couple minutes. If all retries are exhausted without the webserver responding with a 2xx code, the EventSub subscription would be disabled.
Web Server Logic
You can use any framework you desire to implement the webhook server.
For example, this gist utilizes Javalin to handle incoming webhooks.
This example highlights a few important notes:
- To deserialize incoming notification bodies, you can utilize our
TypeConvert
helper. Under the hood,NotificationDeserializer
is used to createEventSubNotification
instances. - You should validate the request headers to ensure authenticity and avoid replay attacks. The example above shows how to utilize
EventSubVerifier
to easily perform these verification checks. - Upon receiving a valid notification challenge, you should set the response body to the same challenge string (and yield a 200 status).
For debugging, you can utilize the Twitch CLI to verify subscriptions and trigger notifications.
For any further clarification, please refer to Twitch's official documentation on handling webhook events.