AI OVERLAY SPEC

Build HypeTally OBS overlays with AI

This page is the system contract for custom overlays. Paste a short dashboard prompt into any AI chat, point it here, and paste the HTML it returns into the overlay editor.

Add ?slug=your-slug (from your dashboard prompt) to personalize the API URLs.

Bar layout: Compact Camera Bar · canvas 920 × 120

Like Counter 920 × 120Member Ticker 920 × 48Subscriber Counter 920 × 120Discord Voice Queue 920 × 280Discord On Air 420 × 120Twitch Sub Counter 920 × 120Twitch Sub Ticker 920 × 48Twitch Follower Counter 920 × 120Twitch Follow Ticker 920 × 48Twitch Bits Ticker 920 × 48Twitch Raid Alert 720 × 160Twitch Hype Train 640 × 96Twitch Stream Goal 920 × 120

Twitch Stream Goal

Followers, subs, or bits goal with progress.

  • OBS URL https://hypetally.com/overlay/your-slug/twitch-goal
  • Data API https://hypetally.com/api/your-slug/twitch-goal
  • Selected bar layout Compact Camera Bar
  • Recommended size 920 × 120

GET /api/{slug}/twitch-goal — { goalLabel, current, target, percent, pollingIntervalMillis, paused? }

Twitch goal requirements

  • Show goalLabel, current / target, progress bar, and percent from the twitch-goal API.
  • Schedule the next poll from pollingIntervalMillis.

Editor-ready layers

Structure HTML so the visual editor can import separate layers (panel, counter, progress bar, ticker) instead of one locked embed. The dashboard AI prompt asks models to follow this section.

Editor-ready sub / counter bar

  • Root shell: .SubBar (full canvas size).
  • Count: #SubCurrent or .SubCurrent · goal: #SubGoal or .SubGoal · eyebrow: #SubEyebrow / .SubEyebrow.
  • Progress: .SubTrack > #SubFill or .SubFill · optional #SubPercent / .SubPercent.
  • Optional: .SubIcon, .SubBrand, .SubStats.
  • Valid data-ht-bind values: likeCount, likeGoal, likeFill, likePercent · subCount, subGoal, subFill, subPercent · members · queue, queueLength, queueFrozen · onAir · twitchRaid · twitchHypeTrain. Map live elements to these (e.g. id="SubCurrent" with data-ht-bind="subCount").

Minimal shape: <div class="SubBar">…<span id="SubCurrent">0</span>…<div class="SubTrack"><span id="SubFill"></span></div>…</div>

All overlay types

  • Put layout styles in a <style> block using the class names below — the editor reads CSS by selector when importing layers.
  • Use separate DOM nodes for shell chrome vs live data (counter, fill bar, ticker track, queue list). Avoid one wrapper that only draws everything with background-image or a single SVG.
  • Size the root bar/panel to the target canvas width and height from this page.
  • Use only the documented data-ht-bind names — custom bind strings are ignored by the editor runtime.
  • Build API URLs as relative paths: `/api/{slug}/…` (same origin as the overlay). Never hardcode ngrok or trycloudflare URLs.
  • After generation, the streamer can Apply to canvas in the HTML panel; if needed, use Break into layers for finer clip-based splits.

Global rules

  • One self-contained <!DOCTYPE html> document with inline HTML, CSS, and JS only.
  • Transparent page background — only the overlay chrome should be visible in OBS.
  • No frameworks, npm packages, bundlers, or external JS CDNs. Google Fonts CSS is OK.
  • Never embed API keys, tokens, or private credentials. Overlay APIs are public and slug-scoped.
  • Poll cadence is controlled by HypeTally. Always schedule the next request from pollingIntervalMillis on the last data API response. Do not invent intervals or drive polling from config poll*Ms fields.
  • Graceful errors: keep the last good UI on screen if a poll fails; always reschedule the next poll in finally.
  • Use a ~15s fetch timeout (AbortController) so a hung request cannot stall the loop.
  • Match the streamer’s selected overlay design pack and canvas size shown on this page.
  • Promoted preset overlays (dashboard bar designs) use the same class names as the examples below — that is the reference HTML for editor-ready imports.
  • Paste the finished HTML into the overlay editor HTML panel, Apply to canvas or Break into layers, then Save & Publish. OBS Browser Source URLs stay the same.

Public APIs (no keys)

All endpoints are JSON, cache: no-store friendly, and scoped to the creator slug. Never ask the streamer for YouTube or Discord secrets inside overlay code.

GET /api/your-slug/config

{ likeGoal, subGoal, subsDisplayMode, twitchSubsDisplayMode, twitchFollowsDisplayMode, twitchFollowGoal, memberScrollSeconds, pollingEnabled, apis } — display/settings only; ignore pollLikesMs/pollSubsMs/pollMembersMs/pollQueueMs for overlay poll cadence

GET /api/your-slug/likes

{ likeCount, likeGoal, pollingIntervalMillis, paused?, awaitingLive?, pollingEnabled? }

GET /api/your-slug/members?pageToken=...

{ newMembers[{ id, displayName, profileImageUrl?, memberLevelName?, isUpgrade? }], nextPageToken, pollingIntervalMillis, paused?, awaitingLive? }

GET /api/your-slug/subs

{ subscriberCount, subsGained, subGoal, subsDisplayMode: "total"|"gained", pollingIntervalMillis, paused?, awaitingLive? }

GET /api/your-slug/queue

{ queueLength, queueFrozen, queue[{ position, displayName, avatarUrl? }], pollingIntervalMillis, paused?, awaitingBot?, subscriptionRequired?, discordNotLinked? }

GET /api/your-slug/on-air

{ onAir[{ displayName, avatarUrl?, durationMs?, isBypass? }], showHostOnOverlay, hideHostOnOverlay, showTimerOnOverlay, pollingIntervalMillis, paused?, awaitingBot? }

GET /api/your-slug/twitch-subs

{ subscriberCount, subCount, subsGained, subGoal, subsDisplayMode: "total"|"gained", pollingIntervalMillis, paused?, awaitingLive?, twitchRequired?, subscriptionRequired? }

GET /api/your-slug/twitch-goal

{ goalLabel, current, target, percent, pollingIntervalMillis, paused? }

GET /api/your-slug/twitch-subs-ticker

{ newMembers[{ displayName, profileImageUrl? }], nextPageToken?, pollingIntervalMillis, paused?, awaitingLive? }

GET /api/your-slug/twitch-followers

{ followCount, subscriberCount, subCount, subsGained, followsGained, subGoal, subsDisplayMode: "total"|"gained", pollingIntervalMillis, paused?, awaitingLive?, twitchRequired?, subscriptionRequired? } — same shape as twitch subs; do NOT use followerCount/followerGoal/displayMode

GET /api/your-slug/twitch-followers-ticker

{ newMembers[{ displayName, profileImageUrl? }], pollingIntervalMillis, paused?, awaitingLive? }

GET /api/your-slug/twitch-cheers

{ newMembers[{ displayName, bits?, message? }], pollingIntervalMillis, paused?, awaitingLive? }

GET /api/your-slug/twitch-raid

{ active, from, viewers, pollingIntervalMillis }

GET /api/your-slug/twitch-hype-train

{ active, level, progress, goal, percent, pollingIntervalMillis }

Polling behavior

  • Poll cadence is set by HypeTally. Always schedule the next request using pollingIntervalMillis from the last likes/members/subs/queue/on-air response (fallback ~5s / 30s only if the field is missing).
  • Do not drive overlay polling from /config pollLikesMs, pollMembersMs, pollSubsMs, or pollQueueMs — those are dashboard/software settings.
  • If paused, awaitingLive, or pollingEnabled: false: keep the last good UI and recheck every pollingIntervalMillis || 30000.
  • Always schedule the next poll in a finally block.
  • Use ~15s fetch timeouts so a hung request cannot stall the loop.

Where to paste the result

  1. Open the HypeTally dashboard → Overlays → copy the prompt for your overlay type (YouTube, Discord, or Twitch).
  2. Open the matching editor tab, or use the Spec link next to Copy Prompt.
  3. Open the HTML editor, paste the full document, Apply to canvas if you want layers.
  4. Save & Publish — your OBS Browser Source URL does not change.

Open dashboard overlays