Chat Capabilities in Extensions
Summary
Twitch chat is an important shared attention space on the channel page leveraged by both streamers and viewers to communicate and interact. Extensions facilitate the connection between streamers and their viewers by offering new ways to engage with the streamer and their content. By building new extension capabilities into chat, we can increase the effectiveness and reach of the interactions created by extensions.
Chat Capabilities in Extensions (CCE) will be an ongoing effort for the Extensions team to bridge Twitch chat and Extensions. In this iteration we aim to provide a very simple integration with chat allowing any extension to be able to send messages to chat. Weâre also going to be introducing a new concept of âFeature Flagsâ allowing broadcasters to opt out/in of features within extensions.
Motivation
Channel Page Presence
Extensions have been successful as a way for broadcasters to provide their audience with more information about their stream or what game theyâre playing. However, when we set out to create the Extensions product, one of our major goals was to increase interactivity between the broadcaster and the viewer. While many extensions are already doing this, we will make it much easier with the addition of Chat Capabilities in Extensions.
In order for an Extension to be noticed on the channel page, the user likely needs to be told to look at it by the broadcaster or theyâll stumble upon it by hovering the video player. We will provide developers a new way to communicate with the viewers through a familiar shared context - chat.
Chatbots
Looking a bit longer term, we are working towards expanding the set anchor locations available to extensions beyond just iframes. Chat Capabilities in Extensions sets us up perfectly to start creating features which make Chatbots as Extensions a possibility.
Chatbot developers face the same problems Extension developers face today with regards to scale, cost, and complexity. Weâre aiming to solve all of these problems with Extensions and believe that bringing chatbots directly into the world of Extensions, we can solve this problem for both sets of developers.
Chat Message API Reference
Send Chat Message
Chat messages will appear in the chat as a normal message. The âusernameâ of the chat message will be the name of your extension as specified in the Extension Manifest.
Authentication
Your request is authenticated by way of the extension JWT. The only authorized JWTs are those which are are signed with the external
or broadcaster
role. The channel_id
inside the JWT must also match the channel_id
in the URL of the request.
URL
POST /extensions/<extension_id>/channels/<channel_id>/chat
Example Request
curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDMzNDM5NDcsImNoYW5uZWxfaWQiOiIyNzQxOTAxMSIsInJvbGUiOiJleHRlcm5hbCJ9.iN0uNLWuEq-qGn07NfDEsumB4Eii4arJdf-SX2RXtZsa' \
-H 'Content-Type: application/json' \
-d '{ "text": "This is a normal message." }' \
-X POST https://api.twitch.tv/extensions/<extension_id>/channels/1682620/chat
Example Response
204 No Content
Limits
Rate Limit: Chat messages will be rate limited to four messages per minute, per channel and will use the same rate limiting functionality which already exists for our API today. (Twitch API Concepts | Twitch Developers)
Message Size: The message must not exceed 280 characters.
Errors
Error Code | Reason | Likely Cause |
---|---|---|
401 | Unauthorized | This can happen for a few reasons. Either the broadcaster has disabled chat support in your extension (see Feature Flags below), you have not specified on the devsite that your extension supports chat (see Rollout Considerations below), the JWT you provided is invalid. Or, in the event of a 401 in your EBS, the extension is no longer installed and activated on the channel. |
429 | Rate limit exceeded | Youâve made too many requests to the API. |
Send Pinned Chat Message
Pinned messages will appear at the top of the chat space for ten seconds before automatically being removed. There will also be an option for the user to dismiss the message while itâs pinned to the top of chat. Pinned messages also appear as normal messages in chat but do not count against your normal message rate limit.
Authentication
Your request is authenticated by way of the extension JWT. The only authorized JWTs are those which are are signed with the external
or broadcaster
role. The channel_id
inside the JWT must also match the channel_id
in the URL of the request.
URL
POST /extensions/<extension_id>/channels/<channel_id>/chat/pinned
Example Request
curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDMzNDM5NDcsImNoYW5uZWxfaWQiOiIyNzQxOTAxMSIsInJvbGUiOiJleHRlcm5hbCJ9.iN0uNLWuEq-qGn07NfDEsumB4Eii4arJdf-SX2RXtZsa' \
-H 'Content-Type: application/json' \
-d '{ "text": "This is a pinned message." }' \
-X POST https://api.twitch.tv/extensions/<extension_id>/channels/1682620/chat/pinned
Example Response
204 No Content
Limits
Rate Limit: Pinned chat messages will be rate limited to one message every five minutes and will use the same rate limiting functionality which already exists for our API today. (Twitch API Concepts | Twitch Developers)
Message Size: The message must not exceed 280 characters.
Errors
Error Code | Reason | Likely Cause |
---|---|---|
401 | Unauthorized | This can happen for a few reasons. Either the broadcaster has disabled chat support in your extension (see Feature Flags below), you have not specified on the devsite that your extension supports chat (see Rollout Considerations below), the JWT you provided is invalid. Or, in the event of a 401 in your EBS, the extension is no longer installed and activated on the channel. |
429 | Rate limit exceeded | Youâve made too many requests to the API. |
Feature Flags
With the release of Chat Capabilities in Extensions, weâre introducing the new concept in Extensions of âFeature Flagsâ.
The Extension Helper will now provide a features
object within the Twitch.ext
global. Within this object, we will provide whether or not a feature is allowed in the current context of your extension. For CCE, the key will be chat
and the value will be a boolean
representing whether or not the broadcaster has disabled the ability for your extension to send chat messages.
If the value of Twitch.ext.features.chat
is false
, you should expect any calls to the Chat Message APIs to return 401
.
Helper API
features
: Object
The features object will contain values for all supported feature flags. The object and the onChange
method are guaranteed to exist when your extension loads. However, it is possible, and likely, for the feature flags to not exist because they are loaded asynchronously. Checking these fields before they are actually provided should not cause any runtime errors but you may get a false negative if youâre simply checking for support using if (Twitch.ext.features.flag) {}
since itâs possible for flag
to be undefined
. The onChange
function will be called once the features have been loaded into the global object which should happen before the first call to onAuthorized
.
Properties:
Feature Flag | Type | Description |
---|---|---|
chat |
boolean |
Represents whether the ability to send chat messages is allowed in the current context. This may be false if the broadcaster has disabled chat for your extension in their channel or because you have not specified your extension supports chat through the devsite. |
onChange |
function |
A listener function you can subscribe to to receive real-time updates to changes of the features object. If this callback is invoked, you should re-check the Twitch.ext.features object for a change to any of the feature flags your extension cares about. The callback will be called with an array of feature flags which were updated. |
User Experience Considerations
Keep in mind, normal viewers do not have the ability to send a chat message from their front end using the Twitch JWT. This is because users are provided tokens which have role: "viewer"
. It is however, possible to make a call to your EBS which would invoke a message to be sent to the Twitch API with role: "external"
. In this case and in the case where youâd like the broadcaster to have an interface allowing them to send a message you should make sure the feature flag in Twitch.ext.features.chat
is set to true
rather than sending additional, unnecessary load to your EBS or the Twitch API.
As described above, weâve provided an onChange
listener to the features
object which will notify you when any option inside the features object has changed. If you provide different user experiences based on the value of a feature flag, it is highly recommended that you subscribe to this callback.
Rollout Considerations
Adding CCE to Your Extension
The Developer Rig will be updated alongside the release of CCE to allow testing against these new APIs immediately upon release.
In order to use these new APIs in production, a new version of your extension must be created in the devsite with chat selected in the âExtension Capabilitiesâ section. Once youâve released your CCE-enabled extension, the chat feature flag will be default-enabled for new and existing installations.
Screenshots
Example pinned and normal messages:
Details about your extension are shown when a user clicks the extension name in chat.
Example Code
// Closure to make sure none of my functionality is exposed to the Window
(function () {
const CLIENT_ID = 'YOUR_CLIENT_ID';
// Toast to show on success/failure of showing a message
const toast = document.createElement('div');
toast.style.display = 'none';
document.body.appendChild(toast);
// Button to invoke a message to chat which alerts viewers a poll has started. Default
// the state of the button to disabled because we don't know if chat is actually supported
// until we've received our first call to `Twitch.ext.features.onChange`.
const startPollButton = document.createElement('button');
startPollButton.innerText = 'Start Poll';
startPollButton.disabled = true;
document.body.appendChild(startPollButton);
// Helper method to check the value of chat feature flag
function isChatSupported() {
return Twitch.ext.features.chat === true;
}
// Helper to show our test with a message
function showToast(message) {
toast.innerText = message;
toast.style.display = 'block';
}
// Helper to clear out the text and hide our toast
function clearTost() {
toast.innerText = '';
toast.style.display = 'none';
}
// If we get an update to features and the flag for chat has changed
// we should update our button state
Twitch.ext.features.onChange(() => {
if (!isChatSupported()) {
startPollButton.disabled = true;
} else {
startPollButton.disabled = false;
}
});
// We'll want to be sure we're always using the latest version of the auth object
Twitch.ext.onAuthorized((auth) => {
currentAuth = auth;
});
// Chat functionality of our extension: send a message to chat to alert viewers a poll
// has started
startPollButton.onclick = (event) => {
event.preventDefault();
// If we don't have auth, just return out
if (!currentAuth) {
console.error('Auth has not been received');
return;
}
// If chat isn't supported, our call to the chat endpoint will just 401, no reason to make the call
if (isChatSupported()) {
fetch({
method: 'POST',
url: `https://api.twitch.tv/extensions/${CLIENT_ID}/channels/${currentAuth.channelId}/chat/pinned`,
body: {
text: 'A poll has started! Scroll down to the panel section to participate!'
}
}).then(() => {
showToast('Message sent!');
setTimeout(clearToast, 3000);
}).catch(() => {
showToast('Message failed!');
setTimeout(clearToast, 3000);
});
// Instead, we'll just alert the user that chat has been disabled and that this functionality
// of our extension is not available
} else {
showToast('Chat not supported in context!');
setTimeout(clearToast, 3000);
}
}
}());