Your overlay is a webpage.
We make it reactive.

Template tags, a reactive expression engine, and pipe formatters wired into the HTML and CSS you already write. Pull live Twitch data with [[[tag]]]. Derive state with c.wins / (c.wins + c.losses) * 100. React to follows, raids, and donations from Ko-fi, Streamlabs, StreamElements, Buy Me A Coffee, FourthWall and Throne. Update anything from your dashboard and watch the overlay catch up in milliseconds.

No drag-and-drop editor. No proprietary file format. No lock-in. Overlabels is the reactive substrate - your overlay is just a webpage it keeps alive.

overlay.html
<div class="stat-bar">
  <span>[[[followers_total]]]</span>
  <small>followers</small>
</div>
[[[if:followers_total >= 1000]]]
  <div class="milestone">
    four digits. let's go.
  </div>
[[[endif]]]
live in OBS
<div class="stat-bar">
  <span>1,342</span>
  <small>followers</small>
</div>
<div class="milestone">
    four digits. let's go.
</div>
Tags

Simple tags. That’s it.

Use a simple tag format to pull in live Twitch data. It works in HTML, in CSS, and inside show/hide rules. Easy to read, easy to scan.

Overlay example — subscriber bar
<div class="sub-bar">
  <span>[[[subscribers_total]]] subs</span>
  <span>Latest: [[[subscribers_latest_user_name]]]</span>
  <span>[[[channel_game]]] | [[[channel_title]]]</span>
</div>

Tags cover your channel, followers, subs, goals, and more. Browse all template tags →

Controls

Typed, mutable overlay state.

Controls are named, typed values you define per template and update from your dashboard while the overlay is live in OBS. Change a value and your overlay re-renders the new data near-instantly. All without page reloads, of course!

Reference any control with [[[c:key]]] — in HTML, in CSS, and in conditional blocks. Full controls reference →

text

Strings up to 1000 chars. HTML stripped on save.

[[[c:myname]]] → JasperDiscovers
number

Numeric values. Safely coerced, defaults to 0.

[[[c:goal_target]]] → 500
counter

Integer counter. Increment or decrement from the dashboard.

[[[c:kill_count]]] → 14
timer

Countup or countdown at 250ms resolution. State broadcast over WebSocket.

[[[c:round_timer]]] → 4:32
datetime

ISO 8601 datetime. For scheduled events, stream start times.

[[[c:next_event]]] → 2026-03-01T20:00:00Z
boolean

Stores "1" or "0". Toggle overlay sections live from your dashboard.

[[[if:c:show_goal]]] → show or hide
Power combo — boolean control + countdown timer + conditional class binding
// "show_timer" → boolean → "1"    "round_timer" → timer → countdown, 300s base
[[[if:c:show_timer]]]
  <div class="timer [[[if:c:round_timer <= 10]]]danger[[[endif]]]">
    [[[c:round_timer]]]
  </div>
[[[endif]]]

The timer ticks at 250ms resolution. The danger class applies automatically when the countdown reaches 10 seconds. Flip the boolean from the dashboard to show or hide the block, with near-live updates.

Conditional Rendering

A comparison engine in your template.

Any tag (Twitch data, control value, or event payload) can drive a conditional block. Evaluated client-side in the overlay with no server round-trips and no eval(). Nesting supported up to 10 levels deep. Full syntax reference →

Syntax

[[[if:variable operator value]]]
  ...
[[[elseif:variable operator value]]]
  ...
[[[else]]]
  ...
[[[endif]]]

Operators

= Equal
!= Not equal
> Greater than
< Less than
>= Greater than or equal
<= Less than or equal

Numeric comparisons are numeric. Truthy check treats "0", "false", and empty string as false.

Language-aware overlay + milestone block
[[[if:channel_language = en]]]
  <p>Welcome to the stream</p>
[[[elseif:channel_language = es]]]
  <p>Bienvenidos al stream</p>
[[[else]]]
  <p>Welcome</p>
[[[endif]]]
[[[if:followers_total >= 10000]]]
  <div class="tenk-badge">10K club</div>
[[[endif]]]
Event Alerts

Every Twitch event. One syntax.

Assign an alert template to any EventSub event. When the event fires, Overlabels renders the template with the payload merged into the tag context, broadcasts the compiled alert to your overlay over WebSocket, and displays it with a configured transition and duration — all without any interaction from you.

New Follower
channel.follow
[[[event.user_name]]]
New Subscription
channel.subscribe
[[[event.tier]]]
Gift Subscriptions
channel.subscription.gift
[[[event.total]]]
Resubscription
channel.subscription.message
[[[event.message.text]]]
Bits Cheer
channel.cheer
[[[event.bits]]]
Incoming Raid
channel.raid
[[[event.viewers]]]
Channel Points
channel.channel_[...]_redemption.add
[[[event.reward.title]]]
Stream Online
stream.online
[[[event.type]]]
Stream Offline
stream.offline
no payload
What happens when a raid fires
01 Twitch sends a webhook POST to /api/twitch/webhook
02 HMAC-SHA256 signature validated against your per-user webhook secret
03 Mapping lookup finds the template assigned to the event type for your account
04 Current overlay data merged with the event payload (event.viewers, event.user_name, etc.)
05 Compiled alert broadcast to Pusher channel alerts.{twitch_id}
06 Overlay receives the payload, renders into the alert DOM node, plays transition
07 Auto-dismisses after configured duration. Static overlay continues uninterrupted.
Integrations

Show donations from different sources.

Connect your Ko-fi, Fourthwall, Buy Me a Coffee, StreamElements, Streamlabs or NEW: Throne account and Overlabels automatically tracks every donation in real time. Counters update, alerts fire, and your overlay stays current - all without touching a single line of code after setup.

Ko-fi

Donations, subscriptions, shop orders

Paste your Ko-fi verification token, set your webhook URL, done. Every Ko-fi event flows through the same alert pipeline as Twitch events.

Six auto-provisioned controls, identical shape across every service:

[[[c:kofi:total_received]]]
[[[c:kofi:latest_donor_name]]]
[[[c:kofi:donations_received]]]
[[[c:kofi:latest_donation_amount]]]
[[[c:kofi:latest_donation_message]]]
[[[c:kofi:latest_donation_currency]]]
One alert template works for all connected external donation services
<div class="donation-alert">
  <h2>[[[event.from_name]]] donated [[[event.formatted_amount]]]</h2>
  [[[if:event.message]]]
    <p>[[[event.message]]]</p>
  [[[endif]]]
  <small>via [[[event.source]]]</small>
</div>

Ko-fi, Fourthwall, Buy Me a Coffee, StreamElements, Streamlabs and Throne expose the same normalized event tags. Write your donation alert once and it works for all of them - [[[event.source]]] tells your overlay which platform it came from.

No vendor lock-in

Six donation services plus Twitch bits. One latest().

Every other overlay tool on the market is owned by a donation platform. Streamlabs' overlays show Streamlabs donations. StreamElements' overlays show StreamElements donations. Ko-fi's overlays show Ko-fi donations. That's not a bug, it's the business model.

Overlabels doesn't sell donation ingest, so we don't care which service the money came through. Pass all six donation services plus Twitch bits into a single latest() function and you get the actual most-recent supporter across any of your connected revenue streams. One name, one amount, six pipes.

Two expression controls. The whole cross-service story.
// c:latest_donator
latest(
  c.kofi.latest_donor_name_at, c.kofi.latest_donor_name,
  c.fourthwall.latest_donor_name_at, c.fourthwall.latest_donor_name,
  c.bmac.latest_donor_name_at, c.bmac.latest_donor_name,
  c.streamelements.latest_donor_name_at, c.streamelements.latest_donor_name,
  c.streamlabs.latest_donor_name_at, c.streamlabs.latest_donor_name,
  c.throne.latest_donor_name_at, c.throne.latest_donor_name,
  c.twitch.latest_cheerer_name_at, c.twitch.latest_cheerer_name
)
// c:last_donation_amount
latest(
  c.kofi.latest_donation_amount_at, c.kofi.latest_donation_amount,
  c.fourthwall.latest_donation_amount_at, c.fourthwall.latest_donation_amount,
  c.bmac.latest_donation_amount_at, c.bmac.latest_donation_amount,
  c.streamelements.latest_donation_amount_at, c.streamelements.latest_donation_amount,
  c.streamlabs.latest_donation_amount_at, c.streamlabs.latest_donation_amount,
  c.throne.latest_donation_amount_at, c.throne.latest_donation_amount,
  c.twitch.latest_cheer_amount_at, c.twitch.latest_cheer_amount
)

latest() takes pairs of (timestamp, label) arguments, picks the highest timestamp, and returns its paired label. Every control in Overlabels automatically exposes an _at companion holding its last-update time in seconds - every timestamp on the platform is normalized that way - so the same pattern works for totals, counters, or anything else you want to rank by recency. Reactive, so your overlay catches up the instant a new donation lands on any pipe.

Case study

Here's how to do a reverse subathon.

A reverse subathon is the evil twin of the classic. The clock starts at some big number and every donation subtracts time. When it hits zero, the stream ends. It is the chaos engine of audience-participation streaming, and it's three controls and one expression in Overlabels.

Create three number controls: c.donathon_timer (starting seconds), c.deduction_per_donation (seconds to strip per donation), and c.total_donations (a counter your alert template increments on every donation across every service). Then a single expression control does the rest:

One expression. The whole show.
// c:time_remaining
clamp(
  c.donathon_timer - (c.deduction_per_donation * c.total_donations),
  0,
  c.donathon_timer
)

clamp() keeps the result between zero and the original timer so the clock can't go negative or somehow inflate. Pipe it through |duration:hh:mm:ss and you have a broadcast-ready countdown that reacts the instant any donation lands on any service.

Btw: if you want a classic subathon that adds time on every donation, just swap the - for a +. That's it. You're welcome <3

Kits & Copying

Good design compounds.

Any public template or kit can be copied. One click, one copy, fully yours to modify, extend, or break. An Overlay Kit is a collection of templates - a static overlay, a follower alert, a subscription alert, a raid alert - designed as a cohesive visual system. Copy the kit, get everything at once - including all Controls and their values.

Copy anything public

Every public template is a starting point. Copy it, own it, ship it. The original is always untouched.

Overlay Kits

Collections of templates sharing a visual language. Copy the kit, get the whole system. No assembly required.

Controls carry over

Copying a template with controls opens the Import Wizard. Pick which controls come with the copy.

Getting started

The Onboarding Wizard

After signing up, the system will trigger an onboarding wizard which will set you up with the defaults you need to make Overlabels work for you: One overlay, a bunch of alerts and your secret token is generated and applied to the URL you need to add to your OBS. We also generate your personal template tags that match the level of your Twitch account. This so you don't end up with affiliate level capabilities if you're a Twitch partner and vice versa.

Automated on signup

  • 01 Secure webhook connection configured
  • 02 Starter kit copied into your account
  • 03 Alerts mapped to events automatically
  • 04 Tag set generated from your Twitch data

Personalised testing page

The /testing page generates ready-to-run Twitch CLI commands for your account. Trigger events locally and verify your overlay without going live.

Example: simulate a new follower event

$ twitch event trigger channel.follow \
  --transport=webhook \
  -F https://overlabels.com/api/twitch/webhook \
  -s your_webhook_secret \
  --to-user your_twitch_id
  --from-user another_twitch_id

You'll need to have Twitch CLI installed for this to work.

Ship your overlay.
Free. Forever.

No paywalls. No tiers. No artificial limits. Everything you create is yours. The whole thing is open source.

Connect

Connect with Twitch to log in to Overlabels. Revoke access anytime from your Twitch settings.