Skip to main content

Event bindings

A binding subscribes your widget to a live stream event. Bindings are how a widget reacts to your stream — flashing on a follow, counting up your bit total, scrolling chat, tracking a goal.

Using an event takes two steps:

  1. Declare it on the Bindings surface (toggle the event on). This tells Community to deliver that event to your widget.
  2. Consume it in your code or template.
The cross-check

The editor keeps these two in sync for you. Use an event in code that you didn't declare and the console warns you (and the event won't arrive live). Declare an event nothing consumes and it warns too. Watch the console.

Two kinds of event​

  • Moment events happen at a point in time — a follow, a sub, a cheer. Your handler runs each time one occurs.
  • Live values are always-current readings — the viewer count, the current goal, the stream title. They carry a value at all times and update as it changes.

Consuming a moment event​

In your core code, register a handler:

import { onLoad, registerBinding, Event, showTemplate, Template } from '@widget';

onLoad(() => {
showTemplate(Template.Main);

registerBinding(Event.Follow, (payload) => {
console.log(`${payload.user.displayName} just followed!`);
// trigger an animation, play a sound, etc.
});
});

Or react to it inside a template with a hook:

import { useLatestEvent, Event } from '@widget';

export default function Main() {
const last = useLatestEvent(Event.Follow); // the most recent follow, or undefined
return <div>Latest follower: {last?.user.displayName ?? '—'}</div>;
}

Consuming a live value​

Read it with a hook and your template re-renders when it changes:

import { useLatestEvent, Event } from '@widget';

export default function Main() {
const stats = useLatestEvent(Event.Stats);
return <div>{stats?.viewers ?? 0} watching</div>;
}

Live values are also published as CSS variables, so simple displays need no code at all.

Moment events​

EventEvent. keyPayload highlights
FollowFollowuser
SubscriptionSubuser, tier (1–3), months, message?, isGift
Gift SubGiftSubgifter, recipient, tier, quantity, isAnonymous
CheerCheeruser, bits, message, isAnonymous
RaidRaiduser, viewers
Shoutout SentShoutoutCreatetoBroadcaster, moderator, viewerCount
Shoutout ReceivedShoutoutReceivefromBroadcaster, viewerCount
Channel PointsChannelPointsuser, rewardId, rewardTitle, rewardCost, userInput?
Hype TrainHypeTrainphase, level, total, goal?, progress?
Ad BreakAdBreakdurationSeconds, isAutomated
Stream StatusStreamStatusonline
PollPollphase, title, choices[]
Chat MessageChatauthor, text, fragments, emotes, badges, color, and gif when the sender attached one
Chat RemovedChatRemovedscope (message/user/all), messageId?, user?
Super CheerSuperCheeruser, bits, message, imageUrl?
Power-UpPowerUpuser, id, title, bits, prompt
Storage UpdateKvUpdatekey, value — fires when your widget's stored data changes
The Alert event

There's also an Event.Alert used by the built-in Alert primitive — a fully-resolved alert payload. It's specialised for that container, so most widgets use the individual events (Follow, Sub, Cheer…) instead.

Live values​

Live valueEvent. keyCarries
Channel StatsStatsfollowers, subscribers, viewers, bitsThisStream, and …ThisStream counts
Stream InfoStreamInfoonline, title, category, startedAt
Ad ScheduleAdSchedulenextAdAt, snoozesRemaining
GoalsGoalevery running goal with current, target, progress (0–1, by the leading option for first-to-post races), milestones, timer
Stream CreditsCreditssession followers, subs, gift-subs, cheers and raids — for end-of-stream rolls
Streamer VariablesStreamerVariablesyour custom channel variables as a { name: value } map, plus endsAt, a { name: ISO time } map of when each running degrading-number variable reaches its resting value
Alerts PausedSuperCheersPausedpaused — whether the channel's alerts are currently paused (the member name is historical)
Channel EmotesChannelEmotesthe channel's Twitch + 7TV + BTTV + FFZ emotes, kept current

The runtime ships helpers for the richer live values — parseChatMessage, useChannelEmotes, the ChatMessage component for chat, and useCountdown for ad/goal timers. See The @widget runtime.

A note on identity​

Person-bearing payloads carry public Twitch identity only — a display name, and sometimes a login, public Twitch id, avatar and chat flair. Widgets never receive private account data. Build with what's in the payload.

Viewer flair​

When a viewer has a chat flair on your channel, their user (the chat author, a gift's gifter) carries flair with everything needed to draw it the way chat does. Anonymous cheers and gifts never carry one.

FieldMeaning
textThe flair, e.g. Warrior
shortTextIts abbreviation, e.g. WAR, or null
color#rrggbb, or null for an uncoloured flair
stylefill (a coloured pill) or text (coloured text)
foregroundBlack or white, whichever reads on color: the text colour for fill
idStable when the flair is renamed, null for custom text. Match flairs on this, never on the text
function Flair({ flair }) {
if (!flair) return null;
if (!flair.color) return <span>{flair.text}</span>;
if (flair.style === 'text') return <span style={{ color: flair.color }}>{flair.text}</span>;
return (
<span style={{ background: flair.color, color: flair.foreground, padding: '0.15em 0.4em', borderRadius: '0.3em' }}>
{flair.text}
</span>
);
}

// e.g. inside a Follow handler: <Flair flair={payload.user.flair} />

The Simulate panel's sample viewer has a flair, so you can style it before a real viewer with one shows up.

Viewer achievements​

A chat author also carries achievementIds: the ids of the achievements that chatter has earned on your channel. It is absent when they have earned none. It is on chat messages only, not on alerts such as cheers and gifts.

const earned = payload.author.achievementIds ?? [];
const isFounder = earned.includes(42); // an id from your achievements list

The Simulate panel's sample viewer has achievements, so you can try a check before a real viewer earns one.

Next​