[{"category":"template-tags","categoryLabel":"Template Tags","slug":"all-overlabels-static-template-tags","title":"All Overlabels Static Template Tags","body":"To use any of these tags, you'll have to wrap them with 3 `[[[brackets]]]` like so.\n[[user_id]]\n[[user_login]]\n[[user_name]]\n[[user_type]]\n[[user_broadcaster_type]]\n[[user_description]]\n[[user_avatar]]\n[[user_offline_banner]]\n[[user_view_count]]\n[[user_email]]\n[[user_created]]\n[[channel_id]]\n[[channel_login]]\n[[channel_name]]\n[[channel_language]]\n[[channel_game_id]]\n[[channel_game]]\n[[channel_title]]\n[[channel_delay]]\n[[channel_tags_0]]\n[[channel_tags_1]]\n[[channel_tags_2]]\n[[channel_tags_3]]\n[[channel_tags_4]]\n[[channel_tags_5]]\n[[channel_tags_6]]\n[[channel_tags_7]]\n[[channel_tags_8]]\n[[channel_tags_9]]\n[[channel_is_branded]]\n[[channel_followers]]\n[[channel_followers_count]]\n[[channel_followers_pagination_cursor]]\n[[followers_total]]\n[[followers_latest_user_id]]\n[[followers_latest_user_login]]\n[[followers_latest_user_name]]\n[[followers_latest_date]]\n[[followed_channels]]\n[[followed_channels_count]]\n[[followed_total]]\n[[followed_latest_id]]\n[[followed_latest_login]]\n[[followed_latest_name]]\n[[followed_latest_date]]\n[[followed_channels_pagination_cursor]]\n[[subscribers_latest_gifter_login]]\n[[subscribers_latest_gifter_name]]\n[[subscribers_latest_is_gift]]\n[[subscribers_latest_broadcaster_id]]\n[[subscribers_latest_broadcaster_login]]\n[[subscribers_latest_broadcaster_name]]\n[[subscribers_latest_gifter_id]]\n[[subscribers_latest_plan_name]]\n[[subscribers_latest_tier]]\n[[subscribers_latest_tier_display]]\n[[subscribers_latest_user_id]]\n[[subscribers_latest_user_name]]\n[[subscribers_latest_user_login]]\n[[subscribers_pagination_cursor]]\n[[subscribers_points]]\n[[subscribers_total]]"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_delay","title":"Channel Delay","body":"the stream delay of the channel in seconds, as configured by the broadcaster (partners/affiliates only)."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_followers","title":"Channel Followers","body":"the list of followers returned by the Get Channel Followers endpoint (the data array, newest first)."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_followers_count","title":"Channel Followers Count","body":"the number of follower entries returned in the current page from the Get Channel Followers endpoint.\nnote: this is the page size, not the all-time total. For the absolute total, use [[followers_total]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_followers_pagination_cursor","title":"Channel Followers Pagination Cursor","body":"the pagination cursor used to fetch the next page of followers from the Get Channel Followers endpoint."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_game","title":"Channel Game","body":"the stylized name of the game (category) where the channel has last streamed in\nexample:\nJust Chatting\nsource: https://www.igdb.com"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_game_id","title":"Channel Game Id","body":"the id of the game (category) where the channel has last streamed in\nexample:\n12345678\nsource: https://www.igdb.com"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_id","title":"Channel Id","body":"channel id of the streamer's own channel"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_is_branded","title":"Channel Is Branded","body":"boolean indicating whether the stream is flagged as branded content by the broadcaster."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_language","title":"Channel Language","body":"the language setting of the channel\nexample:\nen"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_login","title":"Channel Login","body":"channel login name of the streamer's own channel\nnote:\nthis is a lowercase version of the name, used for computations and comparison.\nexample:\njohnstreamer46"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_name","title":"Channel Name","body":"Capitalised, stylized name of the streamer's own channel\nexample:\nJohnStreamer46"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_0","title":"Channel Tags 0","body":"the 1st stream tag set on the channel (index 0 of the channel's tag list).\nnote: empty if the channel has fewer than 1 tag."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_1","title":"Channel Tags 1","body":"the 2nd stream tag set on the channel (index 1 of the channel's tag list).\nnote: empty if the channel has fewer than 2 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_2","title":"Channel Tags 2","body":"the 3rd stream tag set on the channel (index 2 of the channel's tag list).\nnote: empty if the channel has fewer than 3 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_3","title":"Channel Tags 3","body":"the 4th stream tag set on the channel (index 3 of the channel's tag list).\nnote: empty if the channel has fewer than 4 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_4","title":"Channel Tags 4","body":"the 5th stream tag set on the channel (index 4 of the channel's tag list).\nnote: empty if the channel has fewer than 5 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_5","title":"Channel Tags 5","body":"the 6th stream tag set on the channel (index 5 of the channel's tag list).\nnote: empty if the channel has fewer than 6 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_6","title":"Channel Tags 6","body":"the 7th stream tag set on the channel (index 6 of the channel's tag list).\nnote: empty if the channel has fewer than 7 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_7","title":"Channel Tags 7","body":"the 8th stream tag set on the channel (index 7 of the channel's tag list).\nnote: empty if the channel has fewer than 8 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_8","title":"Channel Tags 8","body":"the 9th stream tag set on the channel (index 8 of the channel's tag list).\nnote: empty if the channel has fewer than 9 tags."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_tags_9","title":"Channel Tags 9","body":"the 10th and last stream tag set on the channel (index 9 of the channel's tag list).\nnote: empty if the channel has fewer than 10 tags. Twitch allows a maximum of 10 tags per channel."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"channel_title","title":"Channel Title","body":"the title of the current or most recent stream as set by the broadcaster.\nexample:\n!drops enabled - speedrunning until I die"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_channels","title":"Followed Channels","body":"the list of channels the user follows, as returned by the Get Followed Channels endpoint (the data array, newest first)."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_channels_count","title":"Followed Channels Count","body":"the number of followed-channel entries returned in the current page from the Get Followed Channels endpoint.\nnote: this is the page size, not the all-time total. For the absolute total, use [[followed_total]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_channels_pagination_cursor","title":"Followed Channels Pagination Cursor","body":"the pagination cursor used to fetch the next page of followed channels from the Get Followed Channels endpoint."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_latest_date","title":"Followed Latest Date","body":"the timestamp at which the user followed the most recently followed channel ([Unix epoch time](https://www.epochconverter.com/clock)).\nexample:\n1777575274"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_latest_id","title":"Followed Latest Id","body":"the broadcaster id of the most recently followed channel."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_latest_login","title":"Followed Latest Login","body":"the broadcaster login name of the most recently followed channel.\nnote: this is a lowercase name not meant for display. To display, use [[followed_latest_name]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_latest_name","title":"Followed Latest Name","body":"the Capitalised display name of the most recently followed channel.\nnote: for code/comparison use [[followed_latest_login]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followed_total","title":"Followed Total","body":"the absolute total number of channels the user is following, as returned by the Get Followed Channels endpoint."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followers_latest_date","title":"Followers Latest Date","body":"the timestamp at which the most recent follower followed the channel ([Unix epoch time](https://www.epochconverter.com/clock)).\nexample:\n1777575224"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followers_latest_user_id","title":"Followers Latest User Id","body":"the twitch user id of the most recent follower of the channel."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followers_latest_user_login","title":"Followers Latest User Login","body":"the twitch login name of the most recent follower of the channel.\nnote: this is a lowercase name not meant for display. To display, use [[followers_latest_user_name]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followers_latest_user_name","title":"Followers Latest User Name","body":"the Capitalised display name of the most recent follower of the channel.\nnote: for code/comparison use [[followers_latest_user_login]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"followers_total","title":"Followers Total","body":"the absolute total number of followers the channel has, as returned by the Get Channel Followers endpoint."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_broadcaster_id","title":"Subscribers Latest Broadcaster Id","body":"the broadcaster (channel) id the most recent subscription was made to."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_broadcaster_login","title":"Subscribers Latest Broadcaster Login","body":"the broadcaster (channel) login name the most recent subscription was made to.\nnote: this is a lowercase name not meant for display. To display, use [[subscribers_latest_broadcaster_name]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_broadcaster_name","title":"Subscribers Latest Broadcaster Name","body":"the Capitalised broadcaster (channel) display name the most recent subscription was made to.\nnote: for code/comparison use [[subscribers_latest_broadcaster_login]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_gifter_id","title":"Subscribers Latest Gifter Id","body":"the twitch user id of the user who gifted the most recent subscription, if it was a gift.\nnote: empty when [[subscribers_latest_is_gift]] is false."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_gifter_login","title":"Subscribers Latest Gifter Login","body":"the twitch login name of the user who gifted the most recent subscription, if it was a gift.\nnote: lowercase, not for display. For display use [[subscribers_latest_gifter_name]]. Empty when [[subscribers_latest_is_gift]] is false."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_gifter_name","title":"Subscribers Latest Gifter Name","body":"the Capitalised display name of the user who gifted the most recent subscription, if it was a gift.\nnote: for code/comparison use [[subscribers_latest_gifter_login]]. Empty when [[subscribers_latest_is_gift]] is false."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_is_gift","title":"Subscribers Latest Is Gift","body":"boolean indicating whether the most recent subscription was gifted by another user."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_plan_name","title":"Subscribers Latest Plan Name","body":"the human-readable plan name of the most recent subscription, as configured by the broadcaster.\nexample:\nChannel Subscription (johnstreamer46)"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_tier","title":"Subscribers Latest Tier","body":"the raw tier code of the most recent subscription as returned by the Helix API.\nvalues: 1000 (Tier 1), 2000 (Tier 2), 3000 (Tier 3).\nnote: for a human-readable version use [[subscribers_latest_tier_display]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_tier_display","title":"Subscribers Latest Tier Display","body":"the human-readable tier of the most recent subscription.\nexample:\n`1`\nnote: for the raw API value use [[subscribers_latest_tier]].\nnote: this literally outputs 1, 2 or 3. Preface it with \"Tier: \" in your templates."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_user_id","title":"Subscribers Latest User Id","body":"the twitch user id of the most recent subscriber of the channel."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_user_login","title":"Subscribers Latest User Login","body":"the twitch login name of the most recent subscriber of the channel.\nnote: this is a lowercase name not meant for display. To display, use [[subscribers_latest_user_name]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_latest_user_name","title":"Subscribers Latest User Name","body":"the Capitalised display name of the most recent subscriber of the channel.\nnote: for code/comparison use [[subscribers_latest_user_login]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_pagination_cursor","title":"Subscribers Pagination Cursor","body":"the pagination cursor used to fetch the next page of subscribers from the Get Broadcaster Subscriptions endpoint."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_points","title":"Subscribers Points","body":"the total subscriber points of the channel, as returned by the Get Broadcaster Subscriptions endpoint.\nnote: each Tier 1 sub = 1 point, Tier 2 = 2, Tier 3 = 6. Used by Twitch to unlock broadcaster perks (emote slots, etc.)."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"subscribers_total","title":"Subscribers Total","body":"the absolute total number of active subscribers on the channel, as returned by the Get Broadcaster Subscriptions endpoint."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_avatar","title":"User Avatar","body":"Direct link the 300x300px avatar file for the user.\nexample:\nhttps://static-cdn.jtvnw.net/jtv_user_pictures/7db44749-286f-4db0-9c99-574b16170d44-profile_image-300x300.png"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_broadcaster_type","title":"User Broadcaster Type","body":"partner, affiliate, or none"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_created","title":"User Created","body":"the creation date of the user's account"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_description","title":"User Description","body":"the description in the biography of the user, if they have added one."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_email","title":"User Email","body":"the email address the user used to sign up for twitch"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_id","title":"User Id","body":"the twitch user id of the last user who performed an action on the stream, eg. latest follower, latest subscriber."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_login","title":"User Login","body":"the twitch user login name of the last user who performed an action on the stream, eg. latest follower, latest subscriber.\nnote: this is a lowercase name not meant for display. To display a user's name, use [[user_name]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_name","title":"User Name","body":"the twitch user name of the last user who performed an action on the stream, eg. latest follower, latest subscriber.\nnote: this is a Capitalised version of name meant for display. To use a user's name in code, use [[user_login]]."},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_offline_banner","title":"User Offline Banner","body":"The graphical banner that shows behind the video player on the chat page of the channel, should the user have set this up.\nExample:\nhttps://static-cdn.jtvnw.net/jtv_user_pictures/3f5f72bf-ae59-4470-8f8a-730d9ef87500-channel_offline_image-1920x1080.png"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_type","title":"User Type","body":"partner, affiliate, none"},{"category":"template-tags","categoryLabel":"Template Tags","slug":"user_view_count","title":"User View Count","body":"the viewer count of the user, should they currently be streaming"},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"all-buy-me-a-coffee-events","title":"All Buy Me A Coffee Events","body":"available on every Buy Me a Coffee event type (donation, commission, extra, membership, recurring, wishlist).\n\n### Common Tags\n- `[[[event.from_name]]]` :: Name of the supporter\n- `[[[event.source]]]` :: Name of the platform (\"Buy Me a Coffee\") :: useful for reusing templates across donation services\n- `[[[event.type]]]` :: Normalized type: donation, commission, extra, membership, recurring, or wishlist\n- `[[[event.support_type]]]` :: Human-facing label for the type: Supporter, Commission, Extra, Membership, Subscription, or Wishlist\n- `[[[event.transaction_id]]]` :: Unique Buy Me a Coffee transaction ID (falls back to the payment-provider ID)\n- `[[[event.amount]]]` :: Amount as a string (e.g. \"5\")\n- `[[[event.currency]]]` :: Currency code (e.g. \"USD\")\n- `[[[event.coffee_count]]]` :: Number of coffees bought (e.g. \"1\")\n- `[[[event.live_mode]]]` :: \"1\" for a real event, \"0\" for a test fired from the Buy Me a Coffee dashboard\n- `[[[event.url]]]` :: Always empty :: Buy Me a Coffee does not send a supporter page URL, unlike Ko-fi\n\n### Message Tags\nBuy Me a Coffee sends two different pieces of text and they are easy to mix up.\n\n- `[[[event.message]]]` :: Buy Me a Coffee's own generated description, e.g. \"John bought you a coffee\" :: this is boilerplate, **not** what the supporter wrote\n- `[[[event.support_note]]]` :: The note the supporter actually typed :: this is what fills `[[[c:bmac:latest_donation_message]]]`\n\nReach for `event.support_note` when you want to show what someone said. It is empty when the supporter left no note, and also when they marked the note private - Buy Me a Coffee sends `note_hidden` for that, and Overlabels honours it by returning nothing.\n\n### Flags\n- `[[[event.is_recurring]]]` :: \"1\" on recurring and membership events, otherwise \"0\"\n- `[[[event.is_membership]]]` :: \"1\" on membership events, otherwise \"0\"\n\nBoth are strings, and `\"0\"` is falsy under the conditional rules, so they work directly in a truthiness check: `[[[if:event.is_membership]]]`.\n\n### Type-specific Tags\nEach of these is filled only on its own event type and is an empty string on every other one.\n\n- `[[[event.commission_name]]]` :: Name of the commission (commission events)\n- `[[[event.wishlist_title]]]` :: Title of the wishlist item (wishlist events)\n- `[[[event.extras_title]]]` :: Title of the first extra purchased (extra events)\n\nexample:\n```\n<div class=\"bmac-alert\">\n  [[[event.from_name]]] sent [[[event.amount]]] [[[event.currency]]]\n\n  [[[if:event.is_membership]]]\n    <span class=\"badge\">New member</span>\n  [[[elseif:event.type = commission]]]\n    <span class=\"badge\">Commission: [[[event.commission_name]]]</span>\n  [[[elseif:event.type = wishlist]]]\n    <span class=\"badge\">Wishlist: [[[event.wishlist_title]]]</span>\n  [[[endif]]]\n\n  [[[if:event.support_note]]]\n    <p class=\"note\">[[[event.support_note]]]</p>\n  [[[endif]]]\n</div>\n```\n\nnote: Buy Me a Coffee is an Overlabels integration (not Twitch EventSub). Alerts fire through Buy Me a Coffee's webhook and are routed by `event.type`. Supporter email and shipping address are stripped before the event is stored, so there are no tags for them."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"all-ko-fi-events","title":"All Ko Fi Events","body":"available on every Ko-fi event type (donation, subscription, shop_order, commission).\n\n### Common Tags\n- `[[[event.from_name]]]` :: Name of the supporter\n- `[[[event.source]]]` :: Name of the platform (\"Ko-fi\") :: useful for reusing templates across donation services\n- `[[[event.type]]]` :: Normalized type: donation, subscription, shop_order, or commission\n- `[[[event.is_shop_order]]]` :: \"1\" on shop order events, otherwise \"0\"\n- `[[[event.transaction_id]]]` :: Unique Ko-fi transaction ID\n- `[[[event.url]]]` :: Supporter's Ko-fi page URL\n\nnote: Ko-fi is an Overlabels integration (not Twitch EventSub). Alerts fire through Ko-fi's own webhook and are routed by `event.type`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"all-overlabels-gps-events","title":"All Overlabels Gps Events","body":"available on events sent by the Overlabels GPS mobile app (location_update, session_start, session_end, settings_sync).\n\n> [!WARNING]\n> The Overlabels GPS Android app is still in active development and is **not available in the Play Store**. These tags are documented so the overlay side is ready, but you cannot install the app yet.\n\n> [!CAUTION]\n> `event.latitude` and `event.longitude` are precise device coordinates. Anything you render from them goes on stream, and a viewer reading them off your overlay knows where you physically are. If you stream from home, that is your home address. Decide deliberately what reaches the screen - rounding to a city, showing speed without position, or gating the whole block behind a boolean control you can flip.\n\n### Location Tags\nSent on `location_update`, which is the event the app fires while tracking.\n\n- `[[[event.latitude]]]` :: Latitude in decimal degrees\n- `[[[event.longitude]]]` :: Longitude in decimal degrees\n- `[[[event.speed]]]` :: Speed in metres per second :: divide by 1000 and multiply by 3600 for km/h\n- `[[[event.bearing]]]` :: Heading in degrees, 0-360\n- `[[[event.altitude]]]` :: Altitude as reported by the device\n- `[[[event.accuracy]]]` :: Position accuracy in metres :: lower is better\n- `[[[event.battery]]]` :: Phone battery percentage\n- `[[[event.charging]]]` :: \"1\" when the phone is charging, otherwise \"0\"\n- `[[[event.session_id]]]` :: ID of the tracking session this reading belongs to\n- `[[[event.source]]]` :: Name of the platform (\"Overlabels GPS\")\n\nEvery value arrives as a string and is empty when the device did not report it, which is normal for `altitude` and `bearing` indoors or when stationary. Use `??` to supply a fallback: `[[[event.speed ?? 0]]]`.\n\n### Session Tags\nSent on `session_start` and `session_end`. These carry no position at all - only the session being opened or closed.\n\n- `[[[event.session_id]]]` :: ID of the session that started or ended\n- `[[[event.source]]]` :: Name of the platform (\"Overlabels GPS\")\n\n`settings_sync` is currently normalised through the same path as `location_update`, so it arrives with the location tag set rather than a shape of its own. Expect most fields on it to be empty.\n\n### There is no `event.type` for GPS\nEvery other integration sets `[[[event.type]]]`; the GPS driver does not. Route on the mapping you assigned in the Alerts Builder rather than branching on the tag, because `[[[if:event.type = location_update]]]` will never match.\n\n### Tags and controls use different names\nThe event tags above are not the same vocabulary as the `c:gps:` controls, and the two disagree on the position keys specifically:\n\n| Event tag | Control |\n|---|---|\n| `[[[event.latitude]]]` | `[[[c:gps:lat]]]` |\n| `[[[event.longitude]]]` | `[[[c:gps:lng]]]` |\n\nThe controls also carry values that never appear as event tags, because Overlabels derives them across readings rather than receiving them: `c:gps:distance`, `c:gps:session_distance`, `c:gps:session_duration`, `c:gps:session_max_speed`, `c:gps:session_avg_speed` and `c:gps:tracking`. Reach for the controls when you want running totals, and for the event tags when you want the single reading that just arrived.\n\nexample:\n```\n<div class=\"gps\">\n  [[[if:c:show_location]]]\n    <span class=\"speed\">[[[event.speed ?? 0]]] m/s</span>\n    <span class=\"battery\">[[[event.battery ?? 0]]]%</span>\n    [[[if:event.charging]]]<span class=\"charging\">charging</span>[[[endif]]]\n  [[[endif]]]\n</div>\n```\n\nnote: Overlabels GPS is an Overlabels integration (not Twitch EventSub). Events arrive from the mobile app over the GPS webhook and are authenticated with a per-user token in the `X-GPSLogger-Token` header. The example above deliberately gates the whole block behind a boolean control so you can cut the feed from your dashboard mid-stream without editing the overlay."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"all-throne-events","title":"All Throne Events","body":"available on every Throne event type (gift_purchased, contribution_purchased, gift_crowdfunded). All three normalize to event.type \"donation\".\n\n### Common Tags\n- `[[[event.from_name]]]` :: Name of the gifter (empty on crowdfunded gifts, which have no single gifter)\n- `[[[event.source]]]` :: Name of the platform (\"Throne\") :: useful for reusing templates across donation services\n- `[[[event.type]]]` :: Normalized type: always \"donation\" for Throne\n- `[[[event.throne_event_type]]]` :: Raw Throne type: gift_purchased, contribution_purchased, or gift_crowdfunded\n- `[[[event.transaction_id]]]` :: Unique Throne event ID (used for deduplication)\n- `[[[event.amount]]]` :: Amount in whole currency units (Throne sends integer minor units; Overlabels divides by 100)\n- `[[[event.currency]]]` :: Currency code (e.g. USD)\n- `[[[event.message]]]` :: The gifter's message (empty on crowdfunded gifts)\n- `[[[event.item_name]]]` :: Name of the gifted item (e.g. \"AirPods Max\")\n- `[[[event.item_thumbnail_url]]]` :: Product image URL - drop straight into an `<img src>`\n- `[[[event.is_surprise_gift]]]` :: \"1\" if sent as a surprise gift, otherwise \"0\"\n\nnote: Throne is an Overlabels integration (not Twitch EventSub). Alerts fire through Throne's signed webhook and are routed by `event.type`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-cheer","title":"Channel Cheer","body":"when someone cheers bits.\n\n### User Information\n- `[[[event.user_id]]]` :: Cheerer's Twitch ID\n- `[[[event.user_login]]]` :: Cheerer's username\n- `[[[event.user_name]]]` :: Cheerer's display name\n- `[[[event.user_avatar]]]` :: Cheerer's profile image URL (blank when anonymous)\n\n### Cheer Data\n- `[[[event.bits]]]` :: Number of bits cheered\n- `[[[event.message]]]` :: Cheer message\n- `[[[event.is_anonymous]]]` :: true/false if anonymous\n\nexample:\n`[[[if:event.bits >= 1000]]]HUGE CHEER![[[endif]]] [[[event.user_name]]] cheered [[[event.bits]]] bits!`\n\nnote: maps to the Twitch EventSub event `channel.cheer`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-follow","title":"Channel Follow","body":"The template tags available in your alerts when you get a new follower.\n\n### User Information\n- `[[[event.user_id]]]` :: Follower's Twitch ID\n- `[[[event.user_login]]]` :: Follower's username\n- `[[[event.user_name]]]` :: Follower's display name\n- `[[[event.user_avatar]]]` :: Follower's profile image URL\n\n### Event Data\n- `[[[event.followed_at]]]` :: Timestamp when followed\n- `[[[event.broadcaster_user_name]]]` :: Your display name\n- `[[[event.broadcaster_user_avatar]]]` :: Your profile image URL\n\nnote: maps to the Twitch EventSub event `channel.follow`.\n### tags\n#channel #follower #follow #template-tags"},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-goal-ended","title":"Channel Goal Ended","body":"goal completed or expired :: `is_achieved` tells you which.\n\n### Goal\n- `[[[event.type]]]` :: Goal type\n- `[[[event.description]]]` :: Goal description\n- `[[[event.is_achieved]]]` :: true if goal was hit, false if it expired\n- `[[[event.current_amount]]]` :: Final value\n- `[[[event.target_amount]]]` :: Target value\n- `[[[event.started_at]]]` :: When the goal started\n- `[[[event.ended_at]]]` :: When the goal ended\n\nexample:\n```\n[[[if:event.is_achieved]]]\n  <div class=\"goal-hit\">[[[event.description]]] - HIT!</div>\n[[[else]]]\n  <div class=\"goal-miss\">[[[event.description]]] ended at [[[event.current_amount]]] / [[[event.target_amount]]]</div>\n[[[endif]]]\n```\n\nnote: maps to the Twitch EventSub event `channel.goal.end`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-goal-progress","title":"Channel Goal Progress","body":"current amount updated :: fires on every contribution, budget for spam.\n\n### Goal\n- `[[[event.type]]]` :: Goal type (\"follower\", \"subscription\", etc.)\n- `[[[event.description]]]` :: Goal description\n- `[[[event.current_amount]]]` :: Current value\n- `[[[event.target_amount]]]` :: Target value\n\nexample:\n```\n<div class=\"goal-bar\">\n  [[[event.description]]]: [[[event.current_amount]]] / [[[event.target_amount]]]\n</div>\n```\n\nnote: maps to the Twitch EventSub event `channel.goal.progress`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-goal-started","title":"Channel Goal Started","body":"a follower, sub, or bits goal begins.\n\n### Goal\n- `[[[event.type]]]` :: \"follower\", \"subscription\", \"subscription_count\", \"new_subscription\", or \"new_subscription_count\"\n- `[[[event.description]]]` :: Goal description (your custom text)\n- `[[[event.current_amount]]]` :: Starting amount (where the goal begins from)\n- `[[[event.target_amount]]]` :: Target to hit\n- `[[[event.started_at]]]` :: When the goal started\n\nnote: maps to the Twitch EventSub event `channel.goal.begin`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-points-redemption","title":"Channel Points Redemption","body":"when someone redeems a channel points reward.\n\n### User Information\n- `[[[event.user_id]]]` :: Redeemer's Twitch ID\n- `[[[event.user_login]]]` :: Redeemer's username\n- `[[[event.user_name]]]` :: Redeemer's display name\n- `[[[event.user_avatar]]]` :: Redeemer's profile image URL\n- `[[[event.user_input]]]` :: User's input text\n\n### Reward Data\n- `[[[event.reward.title]]]` :: Reward name\n- `[[[event.reward.cost]]]` :: Point cost\n- `[[[event.reward.prompt]]]` :: Reward description\n- `[[[event.status]]]` :: Fulfillment status\n- `[[[event.redeemed_at]]]` :: Timestamp\n\nnote: maps to the Twitch EventSub event `channel.channel_points_custom_reward_redemption.add`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-raid","title":"Channel Raid","body":"when another streamer raids your channel.\n\n### Raider Information\n- `[[[event.from_broadcaster_user_id]]]` :: Raider's ID\n- `[[[event.from_broadcaster_user_login]]]` :: Raider's username\n- `[[[event.from_broadcaster_user_name]]]` :: Raider's name\n- `[[[event.from_broadcaster_user_avatar]]]` :: Raider's profile image URL\n\n### Raid Data\n- `[[[event.viewers]]]` :: Number of viewers in raid\n- `[[[event.to_broadcaster_user_name]]]` :: Your name\n- `[[[event.to_broadcaster_user_avatar]]]` :: Your profile image URL\n\nnote: maps to the Twitch EventSub event `channel.raid` (filtered to incoming raids)."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"channel-subscribe","title":"Channel Subscribe","body":"when someone subscribes to your channel.\n\n### User Information\n- `[[[event.user_id]]]` :: Subscriber's Twitch ID\n- `[[[event.user_login]]]` :: Subscriber's username\n- `[[[event.user_name]]]` :: Subscriber's display name\n- `[[[event.user_avatar]]]` :: Subscriber's profile image URL\n\n### Subscription Data\n- `[[[event.tier]]]` :: Sub tier (1000, 2000, 3000) :: DON'T USE\n- `[[[event.tier_display]]]` :: Sub display (1, 2, 3) :: USE THIS\n- `[[[event.is_gift]]]` :: true/false if gifted\n\nnote: maps to the Twitch EventSub event `channel.subscribe`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"charity-campaign-ended","title":"Charity Campaign Ended","body":"the campaign wrapped up :: use the final totals for a thank-you alert.\n\n### Campaign\n- `[[[event.charity_name]]]` :: Charity name\n- `[[[event.charity_description]]]` :: Charity description\n- `[[[event.charity_logo]]]` :: Charity logo URL\n- `[[[event.stopped_at]]]` :: When the campaign ended\n\n### Final Totals\n- `[[[event.current_amount.formatted]]]` :: Final amount raised (formatted) :: USE THIS\n- `[[[event.current_amount.value]]]` :: Final amount in minor units\n- `[[[event.target_amount.formatted]]]` :: Target (formatted)\n\nnote: maps to the Twitch EventSub event `channel.charity_campaign.stop`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"charity-campaign-progress","title":"Charity Campaign Progress","body":"current vs. target update :: fires on every donation, budget for spam.\n\n### Campaign\n- `[[[event.charity_name]]]` :: Charity name\n- `[[[event.charity_logo]]]` :: Charity logo URL\n\n### Progress\n- `[[[event.current_amount.formatted]]]` :: Raised so far (formatted) :: USE THIS\n- `[[[event.current_amount.value]]]` :: Raised in minor units\n- `[[[event.target_amount.formatted]]]` :: Target (formatted)\n- `[[[event.target_amount.value]]]` :: Target in minor units\n- `[[[event.target_amount.currency]]]` :: Currency code\n\nexample:\n```\n<div class=\"charity-progress\">\n  [[[event.current_amount.formatted]]] raised of [[[event.target_amount.formatted]]]\n</div>\n```\n\nnote: maps to the Twitch EventSub event `channel.charity_campaign.progress`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"charity-campaign-started","title":"Charity Campaign Started","body":"a charity campaign begins on your channel.\n\n### Campaign\n- `[[[event.charity_name]]]` :: Charity being raised for\n- `[[[event.charity_description]]]` :: Charity description\n- `[[[event.charity_logo]]]` :: Charity logo URL\n- `[[[event.charity_website]]]` :: Charity website URL\n- `[[[event.started_at]]]` :: When the campaign began\n\n### Goal\n- `[[[event.target_amount.formatted]]]` :: Fundraising target (formatted) :: USE THIS\n- `[[[event.target_amount.value]]]` :: Target in minor units\n- `[[[event.target_amount.currency]]]` :: Currency code\n- `[[[event.current_amount.formatted]]]` :: Raised so far (formatted)\n\nnote: maps to the Twitch EventSub event `channel.charity_campaign.start`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"charity-donation","title":"Charity Donation","body":"a viewer donated to the active charity campaign.\n\n### Donor & Campaign\n- `[[[event.user_name]]]` :: Donor's display name\n- `[[[event.user_login]]]` :: Donor's username\n- `[[[event.user_avatar]]]` :: Donor's profile image URL\n- `[[[event.charity_name]]]` :: Charity being donated to\n- `[[[event.charity_description]]]` :: Charity description\n- `[[[event.charity_logo]]]` :: Charity logo URL\n- `[[[event.charity_website]]]` :: Charity website URL\n\n### Amount\n- `[[[event.amount.formatted]]]` :: Ready-to-display string (e.g. \"$15.23\") :: USE THIS\n- `[[[event.amount.value]]]` :: Raw minor units (1523 = $15.23)\n- `[[[event.amount.decimal_places]]]` :: Decimal places (usually 2)\n- `[[[event.amount.currency]]]` :: Currency code (\"USD\", \"EUR\", etc.)\n\nexample:\n```\n<div class=\"charity-donation\">\n  [[[event.user_name]]] donated [[[event.amount.formatted]]] to [[[event.charity_name]]]!\n</div>\n```\n\nnote: maps to the Twitch EventSub event `channel.charity_campaign.donate`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"fourthwall-donation-event-tags","title":"Fourthwall Donation Event Tags","body":"available in alert templates triggered by Fourthwall donations.\n\n### Event Tags\n- `[[[event.from_name]]]` :: Name of the donor\n- `[[[event.message]]]` :: Donor's message\n- `[[[event.amount]]]` :: Donation amount (e.g. \"10\")\n- `[[[event.currency]]]` :: Currency code (e.g. \"USD\")\n- `[[[event.type]]]` :: Always \"donation\"\n- `[[[event.source]]]` :: Always \"Fourthwall\" :: useful for reusing alert templates across donation services\n- `[[[event.status]]]` :: Donation lifecycle state (e.g. \"OPEN\") :: Fourthwall-specific\n- `[[[event.transaction_id]]]` :: Unique donation identifier (e.g. `don_...`)\n\nexample:\n```\n<div class=\"donation\">\n  [[[event.from_name]]] donated [[[event.amount]]] [[[event.currency]]]!\n  [[[if:event.message]]]\n    <p class=\"message\">[[[event.message]]]</p>\n  [[[endif]]]\n</div>\n```\n\nnote: Fourthwall is an Overlabels integration (not Twitch EventSub). Overlabels auto-registers the webhook on your Fourthwall shop on connect."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"hype-train-ended","title":"Hype Train Ended","body":"the train finished :: use the final level + top contributors for the \"thanks\" beat.\n\n### Final State\n- `[[[event.level]]]` :: Final level reached\n- `[[[event.total]]]` :: Final total contributed\n- `[[[event.started_at]]]` :: When the train started\n- `[[[event.ended_at]]]` :: When it ended\n- `[[[event.cooldown_ends_at]]]` :: When the next train can start\n\n### Top Contributors\n- `[[[event.top_contributions.count]]]` :: How many contributors are listed\n- `[[[event.top_contributions.0.user_name]]]` :: #1 contributor name\n- `[[[event.top_contributions.0.user_avatar]]]` :: #1 contributor's profile image URL\n- `[[[event.top_contributions.0.type]]]` :: #1 contribution type\n- `[[[event.top_contributions.0.total]]]` :: #1 contribution total\n- `[[[event.top_contributions.1.user_name]]]` :: #2 contributor\n- `[[[event.top_contributions.1.user_avatar]]]` :: #2 contributor's profile image URL\n- `[[[event.top_contributions.2.user_name]]]` :: #3 contributor\n- `[[[event.top_contributions.2.user_avatar]]]` :: #3 contributor's profile image URL\n\nnote: maps to the Twitch EventSub event `channel.hype_train.end`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"hype-train-progress","title":"Hype Train Progress","body":"a new contribution lands during an active train :: fires frequently, budget for spam.\n\n### Train State\n- `[[[event.level]]]` :: Current level\n- `[[[event.total]]]` :: Total points contributed so far\n- `[[[event.progress]]]` :: Progress toward next level\n- `[[[event.goal]]]` :: Points needed for next level\n- `[[[event.expires_at]]]` :: When the train expires\n\n### Top & Last Contributor\n- `[[[event.last_contribution.user_name]]]` :: Who just contributed\n- `[[[event.last_contribution.user_avatar]]]` :: Their profile image URL\n- `[[[event.last_contribution.type]]]` :: \"bits\", \"subscription\", or \"other\"\n- `[[[event.last_contribution.total]]]` :: Their contribution amount\n- `[[[event.top_contributions.0.user_name]]]` :: #1 contributor (also .1 and .2)\n- `[[[event.top_contributions.0.user_avatar]]]` :: #1 contributor's profile image URL\n- `[[[event.top_contributions.0.total]]]` :: #1 contribution total\n\nexample:\n```\n<div class=\"hype-progress\">\n  Level [[[event.level]]] - [[[event.progress]]] / [[[event.goal]]]\n  [[[if:event.last_contribution.user_name]]]\n    <small>Last: [[[event.last_contribution.user_name]]]</small>\n  [[[endif]]]\n</div>\n```\n\nnote: maps to the Twitch EventSub event `channel.hype_train.progress`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"hype-train-started","title":"Hype Train Started","body":"a hype train kicks off on your channel.\n\n### Train State\n- `[[[event.level]]]` :: Starting level (usually 1)\n- `[[[event.total]]]` :: Total points contributed so far\n- `[[[event.progress]]]` :: Progress toward next level\n- `[[[event.goal]]]` :: Points needed for next level\n- `[[[event.started_at]]]` :: When the train started\n- `[[[event.expires_at]]]` :: When the train expires unless contributed to\n\n### Top & Last Contributor\n- `[[[event.last_contribution.user_name]]]` :: Most recent contributor\n- `[[[event.last_contribution.user_avatar]]]` :: Most recent contributor's profile image URL\n- `[[[event.last_contribution.type]]]` :: \"bits\", \"subscription\", or \"other\"\n- `[[[event.last_contribution.total]]]` :: Their contribution amount\n- `[[[event.top_contributions.count]]]` :: How many top contributors are listed\n- `[[[event.top_contributions.0.user_name]]]` :: #1 contributor name\n- `[[[event.top_contributions.0.user_avatar]]]` :: #1 contributor's profile image URL\n- `[[[event.top_contributions.0.type]]]` :: #1 contribution type\n- `[[[event.top_contributions.0.total]]]` :: #1 contribution total\n\nnote: maps to the Twitch EventSub event `channel.hype_train.begin`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"ko-fi-donation-and-subscription-events","title":"Ko Fi Donation And Subscription Events","body":"additional tags available for Ko-fi donation and subscription events.\n\n### Payment Tags\n- `[[[event.message]]]` :: Supporter's message\n- `[[[event.amount]]]` :: Amount as a string (e.g. \"5.00\")\n- `[[[event.currency]]]` :: Currency code (e.g. \"USD\")\n\nexample:\n```\n<div class=\"donor\">[[[event.from_name]]] donated [[[event.amount]]] [[[event.currency]]]!</div>\n<div class=\"message\">[[[if:event.message]]][[[event.message]]][[[endif]]]</div>\n```\n\nnote: these tags stack on top of the [[all-ko-fi-events|All Ko-fi Events]] common tags."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"ko-fi-subscription-only-tags","title":"Ko Fi Subscription Only Tags","body":"extra tags exclusive to Ko-fi subscription events.\n\n### Subscription Tags\n- `[[[event.tier_name]]]` :: Subscription tier name\n- `[[[event.is_first_sub]]]` :: \"1\" if first payment, \"0\" otherwise\n- `[[[event.is_subscription]]]` :: Always \"1\" for subscription events\n\nnote: these tags stack on top of [[all-ko-fi-events|All Ko-fi Events]] + [[ko-fi-donation-and-subscription-events|Ko-fi Donation & Subscription Events]] and only appear on Ko-fi subscription-type events."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"poll-ended","title":"Poll Ended","body":"final results :: `status` tells you if it completed naturally or was cut short.\n\n### Poll\n- `[[[event.title]]]` :: Poll question\n- `[[[event.status]]]` :: \"completed\", \"terminated\", or \"archived\"\n- `[[[event.started_at]]]` :: When the poll opened\n- `[[[event.ended_at]]]` :: When the poll ended\n\n### Final Choices\n- `[[[event.choices.count]]]` :: How many choices\n- `[[[event.choices.total_votes]]]` :: Final total votes across all choices\n- `[[[event.choices.0.title]]]` :: First choice title\n- `[[[event.choices.0.votes]]]` :: First choice final vote count\n- `[[[event.choices.1.title]]]` :: Second choice title (also .2 to .4)\n- `[[[event.choices.1.votes]]]` :: Second choice final votes\n\n### Winner(s)\n- `[[[event.winners.count]]]` - How many winners (1, or N for ties)\n- `[[[event.winners.0.title]]]` - Winning choice title\n- `[[[event.winners.0.votes]]]` - Winning vote count\n- `[[[event.winners.total_votes]]]` - Sum of votes across all winners (useful for tie copy)\n- Loop with `[[[foreach:event.winners as winner]]]...[[[endforeach]]]`\n\n`event.winners` is computed from `votes` only - bits and channel-points votes are ignored. Ties are always represented in full: every choice tied at the max vote count appears in the array.\n\nexample:\n```\n[[[if:event.status = completed]]]\n  <div class=\"poll-done\">Poll ended: [[[event.title]]]</div>\n[[[elseif:event.status = terminated]]]\n  <div class=\"poll-cut\">Poll cut short: [[[event.title]]]</div>\n[[[endif]]]\n```\n\nnote: maps to the Twitch EventSub event `channel.poll.end`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"poll-progress","title":"Poll Progress","body":"mid-poll vote count update :: fires frequently as votes come in.\n\n### Poll\n- `[[[event.title]]]` :: Poll question\n- `[::[event.ends_at]]]` :: When the poll closes\n\n### Choices\n- `[[[event.choices.count]]]` :: How many choices\n- `[[[event.choices.total_votes]]]` :: Total votes across all choices (use as denominator for progress bars)\n- `[[[event.choices.total_channel_points_votes]]]` :: Total channel-points votes across all choices\n- `[[[event.choices.0.title]]]` :: First choice title\n- `[[[event.choices.0.votes]]]` :: First choice total votes\n- `[[[event.choices.0.channel_points_votes]]]` :: Channel-points votes for #0\n- `[[[event.choices.1.title]]]` :: Second choice title (also .2 to .4)\n- `[[[event.choices.1.votes]]]` :: Second choice votes\n\n### Currently Leading\n- `[[[event.winners.count]]]` - How many choices are tied for the lead\n- `[[[event.winners.0.title]]]` - Leading choice title\n- `[[[event.winners.0.votes]]]` - Leading vote count\n- Loop with `[[[foreach:event.winners as winner]]]...[[[endforeach]]]`\n\n`event.winners` is computed from `votes` only (bits and channel-points votes are ignored). On a fresh poll where everyone is tied at 0, all choices come through as winners.\n\nnote: maps to the Twitch EventSub event `channel.poll.progress`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"poll-started","title":"Poll Started","body":"a poll opens with up to 5 choices.\n\n### Poll\n- `[[[event.title]]]` :: Poll question\n- `[[[event.started_at]]]` :: When the poll opened\n- `[[[event.ends_at]]]` :: When the poll closes\n\n### Choices & Voting\n- `[[[event.choices.count]]]` :: How many choices (max 5)\n- `[[[event.choices.0.title]]]` :: First choice title (also .1 to .4)\n- `[[[event.channel_points_voting.is_enabled]]]` :: true if channel points can vote\n- `[[[event.channel_points_voting.amount_per_vote]]]` :: Points per channel-points vote\n- `[[[event.bits_voting.is_enabled]]]` :: true if bits can vote (legacy)\n\n### Winners\n- `[[[event.winners.count]]]` - How many choices are currently winning (1, or N for ties)\n- `[[[event.winners.0.title]]]` - First winner's title\n- `[[[event.winners.0.votes]]]` - First winner's vote count\n- Loop with `[[[foreach:event.winners as winner]]]...[[[endforeach]]]`\n\nOn `channel.poll.begin` everyone is tied at 0 votes, so all choices come through as winners. This is intentional - it lets the same template handle begin, progress, and end interchangeably.\n\nnote: maps to the Twitch EventSub event `channel.poll.begin`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"prediction-ended","title":"Prediction Ended","body":"winning outcome + payouts :: or canceled if refunded.\n\n### Prediction\n- `[[[event.title]]]` :: Prediction question\n- `[[[event.status]]]` :: \"resolved\" or \"canceled\"\n- `[[[event.winning_outcome_id]]]` :: ID of the winning outcome (resolved only)\n- `[[[event.started_at]]]` :: When it opened\n- `[[[event.ended_at]]]` :: When it ended\n\n### Final Outcomes\n- `[[[event.outcomes.count]]]` :: How many outcomes\n- `[[[event.outcomes.total_users]]]` :: Final total predictors across all outcomes\n- `[[[event.outcomes.total_channel_points]]]` :: Final total channel points wagered\n- `[[[event.outcomes.0.title]]]` :: First outcome title\n- `[[[event.outcomes.0.users]]]` :: Final predictor count on #0\n- `[[[event.outcomes.0.channel_points]]]` :: Final channel points on #0\n- `[[[event.outcomes.1.title]]]` :: Second outcome title (also .2 to .9)\n\nexample:\n```\n[[[if:event.status = resolved]]]\n  <div class=\"prediction-resolved\">Winner: [[[event.outcomes.0.title]]]</div>\n[[[elseif:event.status = canceled]]]\n  <div class=\"prediction-canceled\">Prediction canceled - refunded</div>\n[[[endif]]]\n```\n\nnote: maps to the Twitch EventSub event `channel.prediction.end`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"prediction-locked","title":"Prediction Locked","body":"predictions close :: waiting for the streamer to resolve.\n\n### Prediction\n- `[[[event.title]]]` :: Prediction question\n- `[[[event.locked_at]]]` :: When it locked\n\n### Final Outcomes\n- `[[[event.outcomes.count]]]` :: How many outcomes\n- `[[[event.outcomes.total_users]]]` :: Total predictors across all outcomes\n- `[[[event.outcomes.total_channel_points]]]` :: Total channel points wagered across all outcomes\n- `[[[event.outcomes.0.title]]]` :: First outcome title\n- `[[[event.outcomes.0.users]]]` :: Final predictor count on #0\n- `[[[event.outcomes.0.channel_points]]]` :: Final channel points on #0\n- `[[[event.outcomes.1.title]]]` :: Second outcome title (also .2 to .9)\n\nnote: maps to the Twitch EventSub event `channel.prediction.lock`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"prediction-progress","title":"Prediction Progress","body":"update with current predictor counts :: fires frequently.\n\n### Prediction\n- `[[[event.title]]]` :: Prediction question\n- `[[[event.locks_at]]]` :: When predictions close\n\n### Outcomes\n- `[[[event.outcomes.count]]]` :: How many outcomes\n- `[[[event.outcomes.total_users]]]` :: Total predictors across all outcomes\n- `[[[event.outcomes.total_channel_points]]]` :: Total channel points wagered across all outcomes\n- `[[[event.outcomes.0.title]]]` :: First outcome title\n- `[[[event.outcomes.0.color]]]` :: \"blue\" or \"pink\"\n- `[[[event.outcomes.0.users]]]` :: Number of predictors on #0\n- `[[[event.outcomes.0.channel_points]]]` :: Total channel points on #0\n- `[[[event.outcomes.1.title]]]` :: Second outcome title (also .2 to .9)\n- `[[[event.outcomes.1.users]]]` :: Predictors on #1\n\nnote: maps to the Twitch EventSub event `channel.prediction.progress`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"prediction-started","title":"Prediction Started","body":"a prediction opens with up to 10 outcomes.\n\n### Prediction\n- `[[[event.title]]]` :: Prediction question\n- `[[[event.started_at]]]` :: When it opened\n- `[[[event.locks_at]]]` :: When predictions close\n\n### Outcomes\n- `[[[event.outcomes.count]]]` :: How many outcomes (max 10)\n- `[[[event.outcomes.0.title]]]` :: First outcome title (also .1 to .9)\n- `[[[event.outcomes.0.color]]]` :: \"blue\" or \"pink\"\n\nnote: maps to the Twitch EventSub event `channel.prediction.begin`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"stream-info-updated","title":"Stream Info Updated","body":"when the title, category, or content labels change mid-stream.\n\n### Channel Information\n- `[[[event.broadcaster_user_id]]]` :: Your Twitch ID\n- `[[[event.broadcaster_user_login]]]` :: Your username\n- `[[[event.broadcaster_user_name]]]` :: Your display name\n- `[[[event.broadcaster_user_avatar]]]` :: Your profile image URL\n\n### Updated Fields\n- `[[[event.title]]]` :: New stream title\n- `[[[event.language]]]` :: Language code (e.g. \"en\")\n- `[[[event.category_id]]]` :: New category/game ID\n- `[[[event.category_name]]]` :: New category/game name\n\nexample:\n```\n[[[if:event.category_name]]]\n  <div class=\"now-playing\">Now playing: [[[event.category_name]]]</div>\n[[[endif]]]\n```\n\nnote: maps to the Twitch EventSub event `channel.update`."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"stream-offline","title":"Stream Offline","body":"when your stream goes offline.\n\n### Stream Information\n- `[[[event.broadcaster_user_id]]]` :: Your Twitch ID\n- `[[[event.broadcaster_user_login]]]` :: Your username\n- `[[[event.broadcaster_user_name]]]` :: Your display name\n- `[[[event.broadcaster_user_avatar]]]` :: Your profile image URL\n\nnote: maps to the Twitch EventSub event `stream.offline`. Useful for logging, but viewers won't see alerts since the stream went offline."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"stream-online","title":"Stream Online","body":"when your stream goes live.\n\n### Stream Information\n- `[[[event.id]]]` :: Stream ID\n- `[[[event.type]]]` :: Stream type (usually \"live\")\n- `[[[event.started_at]]]` :: Stream start timestamp\n\nnote: maps to the Twitch EventSub event `stream.online`. Useful for logging, but viewers probably won't see live alerts since the stream just started."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"streamlabs-donation-event-tags","title":"Streamlabs Donation Event Tags","body":"available in alert templates triggered by StreamLabs donations.\n\n### Event Tags\n- `[[[event.from_name]]]` :: Name of the donor\n- `[[[event.message]]]` :: Donor's message\n- `[[[event.amount]]]` :: Donation amount (e.g. \"5.00\")\n- `[[[event.currency]]]` :: Currency code (e.g. \"USD\")\n- `[[[event.formatted_amount]]]` :: Formatted amount (e.g. \"$5.00\")\n- `[[[event.type]]]` :: Always \"donation\"\n- `[[[event.source]]]` :: Always \"StreamLabs\" :: useful for reusing alert templates across donation services\n- `[[[event.transaction_id]]]` :: Unique event identifier\n\nexample:\n```\n<div class=\"donation\">\n  [[[event.from_name]]] donated [[[event.formatted_amount]]]!\n  [[[if:event.message]]]\n    <p class=\"message\">[[[event.message]]]</p>\n  [[[endif]]]\n</div>\n```\n\nnote: StreamLabs is an Overlabels integration (not Twitch EventSub). Donation events are delivered via StreamLabs OAuth."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"subscription-gifts","title":"Subscription Gifts","body":"when someone gifts subscriptions.\n\n### User Information\n- `[[[event.user_id]]]` :: Gifter's Twitch ID\n- `[[[event.user_login]]]` :: Gifter's username\n- `[[[event.user_name]]]` :: Gifter's display name\n- `[[[event.user_avatar]]]` :: Gifter's profile image URL\n\n### Gift Data\n- `[[[event.total]]]` :: Number of subs gifted\n- `[[[event.tier]]]` :: Sub tier (1000, 2000, 3000) :: DON'T USE\n- `[[[event.tier_display]]]` :: Sub display (1, 2, 3) :: USE THIS\n- `[[[event.cumulative_total]]]` :: Total gifts ever\n- `[[[event.is_anonymous]]]` :: true/false if anonymous\n\nnote: maps to the Twitch EventSub event `channel.subscription.gift`. Overlabels collapses gift bombs (multiple gifts from the same user within an 8-second window) into a single alert; use `[[[event.total]]]` for the combined count."},{"category":"eventsub-tags","categoryLabel":"EventSub Tags","slug":"subscription-messages","title":"Subscription Messages","body":"when someone resubscribes with a message.\n\n### User Information\n- `[[[event.user_name]]]` :: Subscriber's display name\n- `[[[event.user_avatar]]]` :: Subscriber's profile image URL\n- `[[[event.tier]]]` :: Sub tier (1000, 2000, 3000) :: DON'T USE\n- `[[[event.tier_display]]]` :: Sub display (1, 2, 3) :: USE THIS\n\n### Subscription Data\n- `[[[event.cumulative_months]]]` :: Total months subbed\n- `[[[event.streak_months]]]` :: Current streak\n- `[[[event.duration_months]]]` :: Months in this sub\n- `[[[event.message.text]]]` :: The resub message\n\nnote: maps to the Twitch EventSub event `channel.subscription.message`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"channel-goal-ended","title":"Channel Goal Ended","body":"fires when a creator goal ends (reached, cancelled, or timed out), carrying whether it was achieved.\nnote: maps to the Twitch EventSub event `channel.goal.end`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"channel-goal-progress","title":"Channel Goal Progress","body":"fires when progress is made toward an active creator goal.\nnote: maps to the Twitch EventSub event `channel.goal.progress`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"channel-goal-started","title":"Channel Goal Started","body":"fires when the broadcaster starts a creator goal (follower, sub, sub points, etc.).\nnote: maps to the Twitch EventSub event `channel.goal.begin`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"channel-points-redeemed","title":"Channel Points Redeemed","body":"fires when a viewer redeems a custom channel-points reward.\nnote: maps to the Twitch EventSub event `channel.channel_points_custom_reward_redemption.add`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"channel-points-redemption-updated","title":"Channel Points Redemption Updated","body":"fires when a channel-points redemption's status changes (fulfilled or cancelled/refunded by the broadcaster or a mod).\nnote: maps to the Twitch EventSub event `channel.channel_points_custom_reward_redemption.update`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"charity-campaign-ended","title":"Charity Campaign Ended","body":"fires when the active charity campaign ends, carrying the final amount raised.\nnote: maps to the Twitch EventSub event `channel.charity_campaign.stop`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"charity-campaign-progress","title":"Charity Campaign Progress","body":"fires when the current and/or target amount of the active charity campaign changes.\nnote: maps to the Twitch EventSub event `channel.charity_campaign.progress`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"charity-campaign-started","title":"Charity Campaign Started","body":"fires when the broadcaster starts a charity campaign on the channel.\nnote: maps to the Twitch EventSub event `channel.charity_campaign.start`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"charity-donation-received","title":"Charity Donation Received","body":"fires when a viewer donates to the active charity campaign on the channel.\nnote: maps to the Twitch EventSub event `channel.charity_campaign.donate`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"gifted-subscription","title":"Gifted Subscription","body":"fires when a user gifts one or more subscriptions to the channel (the gifter's event, carries the gift count).\nnote: maps to the Twitch EventSub event `channel.subscription.gift`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"hype-train-ended","title":"Hype Train Ended","body":"fires when a hype train ends, carrying the final level and cooldown end time.\nnote: maps to the Twitch EventSub event `channel.hype_train.end`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"hype-train-progress","title":"Hype Train Progress","body":"fires each time a hype train gains progress (new contribution, level up, etc.).\nnote: maps to the Twitch EventSub event `channel.hype_train.progress`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"hype-train-started","title":"Hype Train Started","body":"fires when a hype train begins on the channel.\nnote: maps to the Twitch EventSub event `channel.hype_train.begin`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"new-follower","title":"New Follower","body":"fires when a user follows the channel.\nnote: maps to the Twitch EventSub event `channel.follow` (v2)."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"poll-ended","title":"Poll Ended","body":"fires when a poll ends (completed, archived, or terminated), carrying the final results.\nnote: maps to the Twitch EventSub event `channel.poll.end`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"poll-progress","title":"Poll Progress","body":"fires periodically while a poll is active with updated vote counts per choice.\nnote: maps to the Twitch EventSub event `channel.poll.progress`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"poll-started","title":"Poll Started","body":"fires when the broadcaster starts a poll, carrying the choices and duration.\nnote: maps to the Twitch EventSub event `channel.poll.begin`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"prediction-ended","title":"Prediction Ended","body":"fires when a prediction is resolved or cancelled, carrying the winning outcome (or refund status).\nnote: maps to the Twitch EventSub event `channel.prediction.end`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"prediction-locked","title":"Prediction Locked","body":"fires when a prediction's submission window closes; no more points can be wagered but the outcome isn't resolved yet.\nnote: maps to the Twitch EventSub event `channel.prediction.lock`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"prediction-progress","title":"Prediction Progress","body":"fires while a prediction is open with updated channel-points totals and top predictors per outcome.\nnote: maps to the Twitch EventSub event `channel.prediction.progress`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"prediction-started","title":"Prediction Started","body":"fires when the broadcaster starts a prediction, carrying the outcomes and lock-in window.\nnote: maps to the Twitch EventSub event `channel.prediction.begin`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"raid-received","title":"Raid Received","body":"fires when another broadcaster raids the channel, carrying the incoming viewer count.\nnote: maps to the Twitch EventSub event `channel.raid` (filtered to incoming raids)."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"resubscription-message","title":"Resubscription Message","body":"fires when a user shares their resub in chat, including their custom message and cumulative/streak months.\nnote: maps to the Twitch EventSub event `channel.subscription.message`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"stream-goes-live","title":"Stream Goes Live","body":"fires when the channel starts streaming.\nnote: maps to the Twitch EventSub event `stream.online`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"stream-goes-offline","title":"Stream Goes Offline","body":"fires when the channel stops streaming.\nnote: maps to the Twitch EventSub event `stream.offline`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"stream-info-updated","title":"Stream Info Updated","body":"fires when the broadcaster updates the stream's title, category (game), language, or content classification labels.\nnote: maps to the Twitch EventSub event `channel.update`."},{"category":"eventsub-events","categoryLabel":"EventSub Events","slug":"subscription","title":"Subscription","body":"fires when a user subscribes to the channel (paid or gifted, on the moment of subscription — not resubs).\nnote: maps to the Twitch EventSub event `channel.subscribe`."},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"channel_followers","title":"Channel Followers","body":"someone who follows you.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `user_id`, `user_login`, `user_name` :: the follower\n- `followed_at` :: ISO-8601 timestamp of when they followed\n- `user_profile_image_url` :: the follower's avatar (enriched from Helix)"},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"event.choices","title":"Event.choices","body":"poll choice.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `id` :: stable choice id (good for `data-key`)\n- `title` :: choice label shown to voters\n- `votes` :: total votes on this choice\n- `channel_points_votes` :: votes cast with channel points\n- `bits_votes` :: votes cast with bits (deprecated by Twitch, still in payload)\n\nAggregates on the iterable itself: `event.choices.total_votes`, `event.choices.total_channel_points_votes`, `event.choices.total_bits_votes`."},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"event.outcomes","title":"Event.outcomes","body":"prediction outcome.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `id` :: stable outcome id\n- `title` :: outcome label\n- `color` :: \"blue\" or \"pink\" (Twitch's own colouring)\n- `users` :: number of predictors on this outcome\n- `channel_points` :: total channel points wagered on this outcome\n\nAggregates: `event.outcomes.total_users`, `event.outcomes.total_channel_points`. The winning outcome id is `event.winning_outcome_id` on lock/end events."},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"event.top_contributions","title":"Event.top Contributions","body":"hype train contributor.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `user_id`, `user_login`, `user_name` :: the contributor\n- `type` :: \"bits\", \"subscription\", or \"other\"\n- `total` :: amount contributed in the unit implied by `type`\n\nCapped at 3 items (fixed). For just the single latest contributor use `event.last_contribution.user_name`, `event.last_contribution.type`, `event.last_contribution.total`."},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"followed_channels","title":"Followed Channels","body":"a channel you follow.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `broadcaster_id`, `broadcaster_login`, `broadcaster_name` :: the channel\n- `followed_at` :: ISO-8601 timestamp of when you followed\n- `broadcaster_profile_image_url` :: the channel's avatar (enriched from Helix)"},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"goals","title":"Goals","body":"a channel goal.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `id` :: stable goal id\n- `broadcaster_id`, `broadcaster_login`, `broadcaster_name` :: your channel\n- `type` :: one of `follower`, `subscription`, `subscription_count`, `new_subscription`, `new_subscription_count`\n- `description` :: the free-text label you set on Twitch\n- `current_amount` :: progress toward the goal\n- `target_amount` :: goal target\n- `created_at` :: ISO-8601 timestamp of when the goal was created"},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"raw","title":"Raw","body":"dump the current iteration item as pretty-printed JSON :: a debugging helper for inspecting the shape of an iterable while authoring a template.\n\n### Usage\n\nInside a `foreach` loop body, use `[[[raw]]]`. It outputs `JSON.stringify(item, null, 2)` of whatever the current alias resolves to. Pipe formatters (e.g. `| upper`, `| number`) are ignored.\n\n```\n[[[foreach:event.choices as choice]]]\n  <pre>[[[raw]]]</pre>\n[[[endforeach]]]\n```\n\n### Notes\n\n- Only valid inside a `foreach` body :: outside a loop, `[[[raw]]]` is left untouched.\n- Any `[` / `]` in the JSON output are escaped to `&#91;` / `&#93;` so a stray `[[[...]]]` in the data can't re-enter the outer tag substitution pass. Browsers still render them as literal brackets.\n- Intended for template authoring / debugging; remove before shipping an overlay.\n\n### Example payload\n```\n{\n  \"user_name\": \"user1\",\n  \"user_profile_image_url\": \"https://static-cdn.jtvnw.net/jtv_user_pictures/uuid-profile_image-300x300.png\"\n}\n\n{\n  \"user_name\": \"user2\",\n  \"user_profile_image_url\": \"https://static-cdn.jtvnw.net/jtv_user_pictures/uuid-profile_image-300x300.png\"\n}\n\n{\n  \"user_name\": \"user3\",\n  \"user_profile_image_url\": \"https://static-cdn.jtvnw.net/jtv_user_pictures/uuid-profile_image-300x300.png\"\n}\n```"},{"category":"foreach-loops","categoryLabel":"Foreach Loops","slug":"subscribers","title":"Subscribers","body":"channel subscriber.\n\nFields available on each iteration item\n\nInside the loop body, reference any of these fields as `[[[alias.field]]]`, where alias is the name you picked after `as`. Missing fields render as an empty string.\n\n- `user_id`, `user_login`, `user_name` :: the subscriber\n- `user_profile_image_url` :: the subscriber's avatar (enriched from Helix)\n- `broadcaster_id`, `broadcaster_login`, `broadcaster_name` :: your channel\n- `is_gift` :: true if the sub was gifted\n- `gifter_id`, `gifter_login`, `gifter_name` :: empty string when `is_gift` is false\n- `gifter_profile_image_url` :: the gifter's avatar (enriched)\n- `tier` :: \"1000\", \"2000\", \"3000\", or \"Prime\"\n- `plan_name` :: human-readable tier label (e.g. \"Tier 1\")"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"all-integration-controls","title":"All integration controls","body":"# All integration controls\n\nEvery control that an external integration provisions and keeps up to date, across all 6 services.\n\n## The shared donation schema\n\nEvery donation integration provisions the same six keys, so a template written against one service ports to another by changing the prefix alone.\n\n| Key | Type |\n|---|---|\n| `donations_received` | counter |\n| `latest_donor_name` | text |\n| `latest_donation_amount` | number |\n| `latest_donation_message` | text |\n| `latest_donation_currency` | text |\n| `total_received` | number |\n\n## Per service\n\n| Service | Prefix | Controls | Beyond the shared six |\n|---|---|---|---|\n| [[kofi]] | `c:kofi:` | 6 | nothing |\n| [[gps]] | `c:gps:` | 13 | does not use the shared schema |\n| [[streamlabs]] | `c:streamlabs:` | 6 | nothing |\n| [[fourthwall]] | `c:fourthwall:` | 6 | nothing |\n| [[bmac]] | `c:bmac:` | 7 | `latest_support_type` |\n| [[throne]] | `c:throne:` | 9 | `latest_item_name`, `latest_item_thumbnail_url`, `latest_is_surprise_gift` |\n\n## Notes\n\n- Overlabels GPS is the odd one out: it is an integration, but it carries location and device telemetry rather than donations, so it shares none of the six keys.\n- All of these are service-managed. They are read-only to the user and to the API.\n- Every value is a string on the wire. Use a formatter pipe to present it: `[[[c:kofi:total_received|currency:EUR]]]`.\n\n---\n\n*Generated from App\\Services\\External\\ExternalServiceRegistry by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"bmac","title":"Buy Me a Coffee controls","body":"# Buy Me a Coffee controls\n\nBuy Me a Coffee provisions 7 controls when you connect it. They are filled in automatically and stay up to date; you read them, Overlabels writes them.\n\nReference them anywhere a tag works, using the `c:bmac:` prefix.\n\n## The shared donation schema\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:bmac:donations_received]]]` | counter | `0` | BMAC Donations Received |\n| `[[[c:bmac:latest_donor_name]]]` | text | empty | Latest Donor Name |\n| `[[[c:bmac:latest_donation_amount]]]` | number | `0` | Latest Donation Amount |\n| `[[[c:bmac:latest_donation_message]]]` | text | empty | Latest Donation Message |\n| `[[[c:bmac:latest_donation_currency]]]` | text | empty | Latest Currency |\n| `[[[c:bmac:total_received]]]` | number | `0` | Total BMAC Amount (session) |\n\n## Specific to Buy Me a Coffee\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:bmac:latest_support_type]]]` | text | empty | Latest Support Type |\n\n## Events that update them\n\n`donation`, `commission`, `extra`, `membership`, `recurring`, `wishlist`\n\n## Notes\n\n- These are **service-managed** controls. Setting one by hand through the dashboard or the API returns a 403 - the integration owns the value.\n- Referencing one in a template declares that dependency. Someone who copies the template without Buy Me a Coffee connected is warned, not blocked, and it starts working the moment they connect.\n- The shared keys above are identical across every donation integration, so swapping the prefix ports a template between services. See [[all-integration-controls]].\n\n---\n\n*Generated from the Buy Me a Coffee driver by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"fourthwall","title":"Fourthwall controls","body":"# Fourthwall controls\n\nFourthwall provisions 6 controls when you connect it. They are filled in automatically and stay up to date; you read them, Overlabels writes them.\n\nReference them anywhere a tag works, using the `c:fourthwall:` prefix.\n\n## Controls\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:fourthwall:donations_received]]]` | counter | `0` | Fourthwall Donations Received |\n| `[[[c:fourthwall:latest_donor_name]]]` | text | empty | Latest Donor Name |\n| `[[[c:fourthwall:latest_donation_amount]]]` | number | `0` | Latest Donation Amount |\n| `[[[c:fourthwall:latest_donation_message]]]` | text | empty | Latest Donation Message |\n| `[[[c:fourthwall:latest_donation_currency]]]` | text | empty | Latest Currency |\n| `[[[c:fourthwall:total_received]]]` | number | `0` | Total Fourthwall Amount (session) |\n\n## Events that update them\n\n`donation`\n\n## Notes\n\n- These are **service-managed** controls. Setting one by hand through the dashboard or the API returns a 403 - the integration owns the value.\n- Referencing one in a template declares that dependency. Someone who copies the template without Fourthwall connected is warned, not blocked, and it starts working the moment they connect.\n- The shared keys above are identical across every donation integration, so swapping the prefix ports a template between services. See [[all-integration-controls]].\n\n---\n\n*Generated from the Fourthwall driver by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"kofi","title":"Ko-fi controls","body":"# Ko-fi controls\n\nKo-fi provisions 6 controls when you connect it. They are filled in automatically and stay up to date; you read them, Overlabels writes them.\n\nReference them anywhere a tag works, using the `c:kofi:` prefix.\n\n## Controls\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:kofi:donations_received]]]` | counter | `0` | Ko-fi Donations Received |\n| `[[[c:kofi:latest_donor_name]]]` | text | empty | Latest Donor Name |\n| `[[[c:kofi:latest_donation_amount]]]` | number | `0` | Latest Donation Amount |\n| `[[[c:kofi:latest_donation_message]]]` | text | empty | Latest Donation Message |\n| `[[[c:kofi:latest_donation_currency]]]` | text | empty | Latest Currency |\n| `[[[c:kofi:total_received]]]` | number | `0` | Total Ko-fi Amount (session) |\n\n## Events that update them\n\n`donation`, `subscription`, `shop_order`, `commission`\n\n## Notes\n\n- These are **service-managed** controls. Setting one by hand through the dashboard or the API returns a 403 - the integration owns the value.\n- Referencing one in a template declares that dependency. Someone who copies the template without Ko-fi connected is warned, not blocked, and it starts working the moment they connect.\n- The shared keys above are identical across every donation integration, so swapping the prefix ports a template between services. See [[all-integration-controls]].\n\n---\n\n*Generated from the Ko-fi driver by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"gps","title":"Overlabels GPS controls","body":"# Overlabels GPS controls\n\nOverlabels GPS provisions 13 controls when you connect it. They are filled in automatically and stay up to date; you read them, Overlabels writes them.\n\nReference them anywhere a tag works, using the `c:gps:` prefix.\n\n## Specific to Overlabels GPS\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:gps:speed]]]` | number | `0` | GPS Speed (m/s) |\n| `[[[c:gps:lat]]]` | text | empty | GPS Latitude |\n| `[[[c:gps:lng]]]` | text | empty | GPS Longitude |\n| `[[[c:gps:distance]]]` | number | `0` | GPS Distance (km, cumulative) |\n| `[[[c:gps:bearing]]]` | number | `0` | GPS Bearing (degrees) |\n| `[[[c:gps:accuracy]]]` | number | `0` | GPS Accuracy (meters) |\n| `[[[c:gps:battery]]]` | number | `0` | Phone Battery (%) |\n| `[[[c:gps:charging]]]` | boolean | `0` | Phone Charging |\n| `[[[c:gps:tracking]]]` | boolean | `0` | GPS Tracking Active |\n| `[[[c:gps:session_distance]]]` | number | `0` | GPS Session Distance (km) |\n| `[[[c:gps:session_max_speed]]]` | number | `0` | GPS Session Max Speed (m/s) |\n| `[[[c:gps:session_avg_speed]]]` | number | `0` | GPS Session Avg Speed (m/s) |\n| `[[[c:gps:session_duration]]]` | number | `0` | GPS Session Duration (seconds) |\n\n## Events that update them\n\n`location_update`, `session_start`, `session_end`, `settings_sync`\n\n## Notes\n\n- These are **service-managed** controls. Setting one by hand through the dashboard or the API returns a 403 - the integration owns the value.\n- Referencing one in a template declares that dependency. Someone who copies the template without Overlabels GPS connected is warned, not blocked, and it starts working the moment they connect.\n\n---\n\n*Generated from the Overlabels GPS driver by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"streamlabs","title":"Streamlabs controls","body":"# Streamlabs controls\n\nStreamlabs provisions 6 controls when you connect it. They are filled in automatically and stay up to date; you read them, Overlabels writes them.\n\nReference them anywhere a tag works, using the `c:streamlabs:` prefix.\n\n## Controls\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:streamlabs:donations_received]]]` | counter | `0` | StreamLabs Donations Received |\n| `[[[c:streamlabs:latest_donor_name]]]` | text | empty | Latest Donor Name |\n| `[[[c:streamlabs:latest_donation_amount]]]` | number | `0` | Latest Donation Amount |\n| `[[[c:streamlabs:latest_donation_message]]]` | text | empty | Latest Donation Message |\n| `[[[c:streamlabs:latest_donation_currency]]]` | text | empty | Latest Currency |\n| `[[[c:streamlabs:total_received]]]` | number | `0` | Total StreamLabs Amount (session) |\n\n## Events that update them\n\n`donation`\n\n## Notes\n\n- These are **service-managed** controls. Setting one by hand through the dashboard or the API returns a 403 - the integration owns the value.\n- Referencing one in a template declares that dependency. Someone who copies the template without Streamlabs connected is warned, not blocked, and it starts working the moment they connect.\n- The shared keys above are identical across every donation integration, so swapping the prefix ports a template between services. See [[all-integration-controls]].\n\n---\n\n*Generated from the Streamlabs driver by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"integration-controls","categoryLabel":"Integration Controls","slug":"throne","title":"Throne controls","body":"# Throne controls\n\nThrone provisions 9 controls when you connect it. They are filled in automatically and stay up to date; you read them, Overlabels writes them.\n\nReference them anywhere a tag works, using the `c:throne:` prefix.\n\n## The shared donation schema\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:throne:donations_received]]]` | counter | `0` | Throne Gifts Received |\n| `[[[c:throne:latest_donor_name]]]` | text | empty | Latest Gifter Name |\n| `[[[c:throne:latest_donation_amount]]]` | number | `0` | Latest Gift Amount |\n| `[[[c:throne:latest_donation_message]]]` | text | empty | Latest Gift Message |\n| `[[[c:throne:latest_donation_currency]]]` | text | empty | Latest Currency |\n| `[[[c:throne:total_received]]]` | number | `0` | Total Throne Amount (session) |\n\n## Specific to Throne\n\n| Tag | Type | Default | Holds |\n|---|---|---|---|\n| `[[[c:throne:latest_item_name]]]` | text | empty | Latest Item Name |\n| `[[[c:throne:latest_item_thumbnail_url]]]` | text | empty | Latest Item Thumbnail URL |\n| `[[[c:throne:latest_is_surprise_gift]]]` | text | `0` | Latest Is Surprise Gift |\n\n## Events that update them\n\n`donation`\n\n## Notes\n\n- These are **service-managed** controls. Setting one by hand through the dashboard or the API returns a 403 - the integration owns the value.\n- Referencing one in a template declares that dependency. Someone who copies the template without Throne connected is warned, not blocked, and it starts working the moment they connect.\n- The shared keys above are identical across every donation integration, so swapping the prefix ports a template between services. See [[all-integration-controls]].\n\n---\n\n*Generated from the Throne driver by `php artisan help:build-integration-controls`. Do not edit by hand - your changes will be overwritten.*"},{"category":"for-machines","categoryLabel":"For Machines","slug":"markdown-endpoints","title":"Markdown endpoints (.md)","body":"# Markdown endpoints (.md)\n\nEvery prose help page on Overlabels is fetchable as plain markdown by appending `.md` to its URL.\n\n```\nhttps://overlabels.com/help/conditionals      -> HTML (a Vue app shell)\nhttps://overlabels.com/help/conditionals.md   -> text/markdown, the full source\n```\n\nThe `.md` response is byte-identical to the file the site renders, so there is nothing to build and\nnothing that can drift out of sync.\n\n## Use the .md form\n\nThe bare help URLs render an Inertia/Vue application. A crawler or a `fetch` that follows one gets an\napp shell and almost no prose. Always append `.md`.\n\nThe exceptions are the pages under `/help/reference` - the page you are reading now. Those are plain\nserver-rendered HTML on purpose, so they can be read directly with no suffix, and they are the pages\nlisted individually in `sitemap.xml`.\n\n## Start at the index\n\n```\nhttps://overlabels.com/help.md\n```\n\nThat is the help index as markdown, and it links to every other page. One URL is enough to crawl the\nwhole documentation set.\n\nFor a single self-contained primer instead of a crawl, use [[llms-txt]].\n\n## Pages without a .md twin\n\nThree help URLs render live data or an interactive UI rather than prose, so they have no markdown\nversion:\n\n- `/help/integration-presets` - the searchable preset catalogue, rendered from source data.\n- `/help/reference` - this reference. Machine-readable as JSON instead, see\n  [[help-reference-index-json]].\n- `/help/gamejam` - Chat Castle documentation."},{"category":"for-machines","categoryLabel":"For Machines","slug":"help-reference-index-json","title":"help-reference-index.json","body":"# help-reference-index.json\n\nThe entire reference - every template tag, EventSub event, EventSub tag, and foreach loop field - as\none JSON array:\n\n**<https://overlabels.com/help-reference-index.json>**\n\nNo auth, no key, nothing to sign up for. Build your own frontend over it, feed it to an editor's\nautocomplete, or load it into an assistant's context. It is a static file that changes rarely, so\ncache it rather than fetching it on every keystroke.\n\n## Shape\n\n```json\n[\n  {\n    \"category\": \"template-tags\",\n    \"categoryLabel\": \"Template Tags\",\n    \"slug\": \"channel_followers\",\n    \"title\": \"channel_followers\",\n    \"body\": \"# channel_followers\\n\\nThe total number of ...\"\n  }\n]\n```\n\n| Field | Meaning |\n|---|---|\n| `category` | Directory slug. One of `template-tags`, `eventsub-tags`, `eventsub-events`, `foreach-loops`, `integration-controls`, `for-machines`. |\n| `categoryLabel` | Human label for that category. |\n| `slug` | URL segment. For `template-tags` this is also the tag name, so `[[[<slug>]]]` is a valid tag. |\n| `title` | First `#` heading of the body, falling back to a humanised slug. |\n| `body` | The full markdown source of the entry. |\n\nEach entry maps to a page at `https://overlabels.com/help/reference/{category}/{slug}`.\n\nThe file is regenerated from the markdown sources, so it is always a mirror of what the site serves.\nIt is the same data the fuzzy search on this page runs against.\n\nThe `integration-controls` category is itself generated, one step further back: it is emitted from the\nexternal service drivers in PHP rather than hand-written, so the control keys listed for Ko-fi,\nStreamLabs, Fourthwall, Buy Me a Coffee, Throne and Overlabels GPS are the keys the\nrunning app actually provisions. Connecting a new service adds its entries with no separate\ndocumentation step.\n\nFor the template language itself rather than the tag catalogue, read [[llms-txt]]. For the prose help\npages, see [[markdown-endpoints]]."},{"category":"for-machines","categoryLabel":"For Machines","slug":"llms-txt","title":"llms.txt","body":"# llms.txt\n\nOverlabels publishes its complete overlay-authoring guide as one plain text file:\n\n**<https://overlabels.com/llms.txt>**\n\nIt is written for language models, and any of them may read it. If you are an AI assistant helping\nsomeone build a Twitch overlay with Overlabels, fetch that URL first. It is the canonical description\nof the Overlabels template language, it is maintained alongside the running app, and it is complete:\nread it end to end and you can write a working static, alert, or block template without ever seeing\nthe codebase.\n\nIf you are a human, you can hand that URL to Claude, ChatGPT, Gemini, Copilot, or a local model and\nthen ask for an overlay in plain language. That is the whole point of the file.\n\n## Give it to your assistant\n\nPaste this into any chat assistant that can fetch a URL:\n\n```\nRead https://overlabels.com/llms.txt in full, then write me an Overlabels\nstatic overlay that shows my follower count and latest follower. Follow the\nhard rules in section 1 exactly: no JavaScript, no <audio>, three fields only\n(head, html, css).\n```\n\nOverlabels grants any language model permission to read, quote, and follow `/llms.txt` and every\nmarkdown help page under `/help` when helping someone build an overlay. There is no login, no API key,\nand nothing to sign up for. It is a static file, so fetching it is cheap for everyone involved - but\nplease fetch it once and keep it, rather than re-fetching it per request.\n\n## What is in it\n\n- **The hard rules.** No JavaScript, ever. No `<audio>` or `<video>`. Tags resolve exactly once and\n  are never rescanned. Three fields only: `head`, `html`, `css`. Missing data renders nothing.\n  Overlays never phone home.\n- **Template anatomy and the three template types** - static, alert, and block, and which data each\n  one can see.\n- **The full tag syntax** - `[[[key]]]`, the 11 formatter pipes, `?? default`, the `[[[if:]]]` /\n  `[[[elseif:]]]` / `[[[else]]]` / `[[[endif]]]` family, and `[[[foreach:]]]` with its loop variables.\n- **Every data source** - Twitch channel tags, controls (`[[[c:...]]]`), lists\n  (`[[[c:list:...]]]`), and the `event.*` catalogue that alert templates get.\n- **The `event.type` trap** - Twitch events carry dotted EventSub names like `channel.follow`, while\n  every donation provider normalises to the single word `donation`. This is the single most common\n  reason a hand-written alert template silently matches nothing.\n- **Three complete worked examples** - a follower goal bar, a multi-branch alert, and a chat block,\n  each with all three fields filled in.\n- **A table of the mistakes people actually make**, with what happens for each one.\n\n## Why this page exists\n\nA search engine or an assistant finds a file by following a link from a page it already knows about.\nA `<link rel=\"llms-txt\">` tag in the document head is a declaration, not a link a crawler will follow,\nand `llms.txt` itself is a convention rather than a ratified standard, so nothing indexes it\nautomatically. This page is the human-readable, crawlable page that points at it.\n\nThe other machine-readable surfaces are documented in [[markdown-endpoints]] and\n[[help-reference-index-json]].\n\n## Related\n\n- `https://overlabels.com/help.md` - the help index as plain markdown, and the entry point if you want\n  to crawl the documentation rather than read a single primer.\n- `https://overlabels.com/sitemap.xml` - lists every public URL, including `/llms.txt`.\n- `https://overlabels.com/robots.txt` - allows everything, and names `/llms.txt` in a comment."}]