This is a guest post by Matt Condon (Thanks, Matt! 👋), one half of the two-person team at dot that builds the Stickers Extension.
The Stickers Extension turns any stream into a canvas for viewers where viewers receive rare digital stickers that they place on-stream for everyone to see in real-time. Each time a viewer places a sticker on-stream, every viewer sees it for a few seconds and the Extension gives the placer a shout-out in chat. Subscribers can claim a free sticker ticket every week, and since each sticker is a scarce, unique item, stickers placed on a stream are now owned by the streamer, who can spread the love to other channels.
Recently, as part of the Stickers website and Discord, we added a live feed of channels that are streaming with the Stickers Extension enabled. With live channels on the Stickers website, prospective streamers can easily see Stickers live on an active streamer’s channel, helping them understand how it will look on their own channel and affect their viewers. Plus, with the live feed in Discord, chatters see when a new streamer goes live, as social proof that the Stickers Extension is being used across Twitch.
We have so many live streamer notifications that I’m tempted to mute the channel, but I love knowing when a new streamer joins the Sticker fam.
We’ll show you how to build a feed of live channels for your own Extension and how to integrate it into your own Discord channel and website. We’ll assume basic knowledge of Lambda and basic understanding of how to use databases like DynamoDB, but you can use the technique here with any technology stack you choose.
The live channel feed consists of two separate outputs:
A list of all of the currently active channels in order to display them on the website.
A feed of new channels going live in order to post messages in the Discord.
The Twitch Extension API provides the useful endpoint
live_activated_channels which returns a paginated list of channels that are live with your Extension activated. We’ll periodically ask Twitch for a list of live activated channels and then do our own processing to create a list of channels and a feed of newly live channels. Note that streamers will take a few minutes to show up in the list provided by this endpoint, so if you’re looking for by-the-second updates on when streamers go live, read the Twitch documentation–specifically the Webhook support via stream_changed.
At dot we rely heavily on AWS, among others, for our backend infrastructure — Stickers is a real-time serverless application that has run with 100 percent uptime over the last two months.
We leverage AWS’s serverless-friendly products like Lambda, DynamoDB, AppSync, and CloudWatch in particular to drive the live feed.
Every 10 minutes, a CloudWatch Rule invokes a
sync_live_channels Lambda function which queries the Twitch Extension API for live activated channels — paging through the returned pages — and stores the results in a DynamoDB table called
live-channels table has an item TTL of 15 minutes, so stale items are removed 15 minutes after insertion. This keeps the list of live channels fresh — streams that go offline will be removed within 15 minutes.
To get a list of channels, the
get_live_channels Lambda function runs a DynamoDB query against the
by_view_count`` index — sorted by a streamer’s view_count — and returns that list to the caller.
To produce a list of newly live channels, the DynamoDB Stream from
live-channels is forwarded to a Lambda consumer called
notify_live_channels which then posts a message to Discord using their webhooks API.
sync_live_channels Lambda function is responsible for pulling the list of live channels from Twitch and storing them in our DynamoDB table.
Here we can see some pseudocode for querying the Twitch API and storing the results in our
live-channels DynamoDB table. At the moment, there’s a bug in the API response: occasionally, you’ll receive a response with an empty list of channels but still receive a cursor for the next page. Once you query that cursor again, Twitch will return the next page of live activated channels to you, so your code must be able to handle the case where no channels are returned in the response, but a cursor still provides another page. The TwitchAPI team is aware of this minor issue, though it’s always advisable to check your data!
This Lambda function is subscribed to DynamoDB Stream events from our
live-channel table, so it gets invoked when items are added. This Lambda’s job is to take the new stream, combine it with other information we know about the streamer — using the Twitch API — and publish that information to our Discord channel.
Notice how we use the Twitch brand purple — encoded in decimal — as the color for our Discord embed; that’s what gives us the pretty purple border to the left of Discord messages! Also notice that we restrict Discord notifications to streamers with at least 5,000 total views on their channel; this helps us avoid spam from accounts with low view counts that may install the Extension.
To get a Discord Webhook, set up a webhook in the channel you’d like messages to appear.
And then enjoy the result!
This Lambda function is in charge of querying the currently live channels and returning that to the caller. In a production application, you would expose this with an API Gateway route or an AppSync resolver and cache the result.
This Lambda function queries the DynamoDB index for the top 20 live channels ordered by their
view_count, merges that data with extra information about the streamer we know, like their
login, and returns the bundle of data to the caller.
On the frontend, we can build our UI with the following elements:
a recent frame from their stream, which is provided via
thumbnail_url in the
/helix/streams endpoint, and adding our dimensions of
a link to their Twitch channel like