Design your own Social Stream overlays

Download, customize, connect, and test local overlay designs in OBS, with guides for each overlay family.

Make your own overlay in 5 steps

Download the filesChange the designOpen in OBS
  1. Pick the overlay you want to change.
  2. Download the source ZIP, unzip it, and copy that overlay's HTML file.
  3. Edit the copy yourself, or ask an AI tool to.
  4. Open your copy in OBS with your SSN session settings added to its address.
  5. Test it with the overlay's real trigger.
Just want new colors or fonts? Skip the download. Keep the normal hosted link and paste CSS into the OBS Browser Source's Custom CSS box.

Pick the overlay to change

You can change an overlay's colors, fonts, layout, artwork, and motion. The HTML file is the page. The OBS URL points to it and adds your session and display settings.

Choose a working overlay before changing its appearance.
Start from an overlay that already works.

Each overlay type listens for different things. A chat page, a featured-message page, and a poll don't use the same input. Open the design guide for the one you use:

Design guideStarting filesWhat drives it
Chat and Docksampleoverlay.html, dock.html, themes/*Every captured chat message
Featured messagesfeatured.html, samplefeatured.html, themes/featured-styles/*Selected messages and clear commands
Alerts and event feedsmulti-alerts.html, events.html, themes/events/index.htmlMatching events / paid chat rows
Graphical pollspoll.htmlVotes plus host poll settings
Tip jars and goalstipjar.htmlConfigured support/count/Hype metric
Counters and rankingshype.html, meta.html, leaderboard.html, scoreboard.htmlCounts, metadata, activity, or point snapshots
Waitlists and queue drawswaitlist.htmlHost queue and winner state
Giveaway displaysgiveaway.html, giveaway-obs-entries.htmlManaged giveaway state or legacy entry feed
Timerstimer.htmlTimer state and controls
Tickersticker.htmlConfigured ticker content
Word clouds and mapswordcloud.html, map.htmlMatching words or location entries
Reactions and media effectsreactions.html, emotes.html, content.html, gif.html, confetti.html, stickers.html, actions.htmlThe page's specific media/event/action trigger
Creditscredits.htmlCollected participants and credits controls
Music and AI displaysspotify-overlay.html, cohost-overlay.html, bot.html, chatbot.htmlNow-playing or bot/cohost updates
Products and boardsmonetization.html, commerce-board.html, shop_the_stream.htmlShared commerce state
Games and rewardsgames/*, games/templates/*, games.html, battle.htmlGame-specific chat, gifts, and commands
Generated AI overlaysaioverlay.html, aievent-overlay.htmlSaved designs and their configured event route

Want something ready-made? Try the Overlay Gallery or Templates Gallery. Bringing a StreamElements or Streamlabs chat skin? Follow the import guide. That export comes with its own setup steps.

Download the files

  1. Download the beta source ZIP. Or open the beta repository and choose Code → Download ZIP.
  2. Unzip it into a folder you'll keep, like C:\SSN\social_stream-beta\. Don't edit inside the ZIP. You don't need to reinstall SSN.
  3. Find your overlay's file (see the table above). Make a copy next to the original, like poll.html → my-poll.html. For a theme such as themes/featured-styles/featured-modern.html, keep the copy in the same folder.
  4. Open the copy in a text or code editor. Save it as .html, not .html.txt.
Keep the whole unzipped folder. One HTML file can load scripts, styles, fonts, images, audio, or data from nearby folders. Moving the page breaks those links. GitHub's page view or a browser's “Save page” won't get everything.
What the folder looks like, and how paths work
social_stream-beta/
    poll.html
    my-poll.html
    currency.js
    js/
    libs/
    shared/
    thirdparty/
    media/
    sources/images/
    themes/
        featured-styles/
            featured-modern.html
            my-featured.html
    docs/
        event-reference.html

A path like ../../shared/utils/chatHtml.js is relative to the page that loads it. Move that page to the root and the path breaks. Copy your own artwork and fonts into the folder too, and use relative paths. Your edited copy won't get future SSN fixes automatically.

Keep your session link

Start SSN, connect a source, and check the original overlay works. Then copy the full link from the SSN tool for that overlay.

https://socialstream.ninja/poll.html?session=YOUR_SESSION&password=YOUR_PASSWORD&server2

The value after session= is your SSN session. It's not your YouTube channel, Twitch name, file name, or poll title. SSN and your page must use the same session and password. Keep SSN running: overlays only receive data. They don't capture chat themselves.

RuleWhy
? starts the settings, & joins the restCopy them, don't retype. Inside an HTML attribute write &. In the browser or OBS URL box, use a plain &.
Keep the server settingsserver, server2, server3, local endpoints, labels, and version values differ by page. Don't add a server flag just because another overlay uses it.
Keep everything after #It can matter. AI Event Overlay, for example, uses a private #aieventauth=... token.
Use placeholders when sharingKeep your real session, password, and private tokens out of screenshots, repos, and AI prompts.

If your copy stays blank, check the original link first. Some pages ask for missing settings; others stay hidden or redirect. Putting the right session in the link avoids guessing.

Open your file in OBS

Open the edited file straight from your computer. No server needed.

  1. Drag your HTML copy into Chrome or Edge. Copy its address. It starts with file:///.
  2. From your working SSN overlay link, copy everything from ? onward. Paste it on the end of the file address. This keeps your session, password, settings, and any # part.
  3. Open that combined address in your browser to test it.
  4. In OBS, add a Browser Source. Leave Local file unchecked. Paste the full address into URL and set the width and height.

Example: this SSN link…

https://socialstream.ninja/poll.html?session=YOUR_SESSION&password=YOUR_PASSWORD&server2

…becomes this for a downloaded poll copy on Windows:

file:///C:/SSN/social_stream-beta/my-poll.html?session=YOUR_SESSION&password=YOUR_PASSWORD&server2

On macOS it starts with file:///Users/..., on Linux usually file:///home/.... Copying from the browser handles spaces and slashes for you.

Good to knowDetails
You only set this up onceOBS saves the address. Keep the folder where it is, and keep SSN and your chat source running.
Saved a change?Click Refresh cache of current page in the source properties.
Why leave Local file unchecked?The URL box lets you add ?session=.... Picking the file with Local file doesn't add those settings.
Optional: use the Local file checkbox with a launcher

OBS's file picker picks a file but can't add your settings. A small launcher page can open your edited page with the settings attached:

  1. Save the code below as launch-my-poll.html next to my-poll.html.
  2. Replace the placeholder link with your full copied SSN link. Change ./my-poll.html to your file name. Keep the link in quotes, with plain & characters.
  3. Double-click the launcher to test it. In OBS, check Local file and pick the launcher. It forwards to your overlay with the settings and # part.
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>My local overlay launcher</title>
<p>Opening the local overlay...</p>
<script>
var copiedLink = new URL("https://socialstream.ninja/poll.html?session=YOUR_SESSION");
var localPage = new URL("./my-poll.html", window.location.href);
localPage.search = copiedLink.search;
localPage.hash = copiedLink.hash;
window.location.replace(localPage.href);
</script>
</html>

For a theme in a subfolder, put the launcher next to that theme copy. Keep the launcher private, since it holds your connection link. A self-contained export that already includes its settings follows its own instructions instead.

OBS explains file/URL modes, sizes, Custom CSS, and refresh in its Browser Source reference.

Change the design, or ask AI to

I want to…Do this
Only change CSSKeep the hosted link and use OBS's Custom CSS box. It only affects that OBS source, not a normal browser.
Restyle my edited HTML copyAdd your styles after the existing ones, or link a local stylesheet after them.
Use &css= or &b64css=Only some pages support it. poll.html, for example, reads neither. Check the page's code first.
Change the HTML layoutKeep IDs and classes that scripts use. If a script rebuilds an element on every update, put permanent artwork outside it, or add it to the renderer.
Edit a shared stylesheet or scriptCopy it and point your page at the copy, so only your design changes.

Have your logo, font files, brand colors, canvas size, and a visual reference ready. A web page generally can't load fonts or images from another computer's disk.

AI prompt

Use the type-specific prompt in each design guide, or start with this one. Give the AI your copied file and the styles and scripts it loads.

Customize [copied overlay filename] to match [reference/design].
Canvas: [width x height]. Placement: [position]. Colors/fonts: [details].
Use the existing page and its supporting files, rather than replacing its
connection and event logic. Read docs/event-reference.html and the relevant
overlay design guide. Preserve query parameters, session/password, URL
fragments, bridge labels, transport channels, settings, and controls.
Use CSS first. Keep relative paths and package all executable dependencies
locally. Use classic scripts compatible with Chrome 80.
Keep operator controls, private links, and credentials off the audience view.

Treat all incoming messages, names, labels, donations, and metadata as untrusted.
Prevent HTML/JavaScript injection in every renderer you change. Use textContent
for plain fields and for chatmessage when textonly is true. For HTML-mode
chatmessage, keep supported emotes/formatting through the packaged
SocialStreamChatHTML.sanitize helper (libs/objects.js loaded first).
Do not concatenate raw input into innerHTML, attributes, CSS, or JavaScript.
Validate media/link URLs with the page's existing URL policy and assign DOM
properties; do not enable javascript: URLs or executable embedded content.
Never eval incoming data or treat a viewer message as an AI instruction.
Keep source checks, connection handling, and existing sanitizers.
Test plain text, allowed emotes, quotes, angle brackets, and an HTML injection
probe in an isolated preview; verify the probe cannot execute.

Make the edited overlay work directly from disk using a file:/// URL,
without requiring a local web server. Return the edited files and assets,
file URL and OBS setup steps, and tests
for this overlay's real trigger. Use session placeholders in shared examples.
Explain any behavior changes separately from the design edits.
Don't accept a fake. A design that only works with hard-coded sample messages isn't done. Keep the original file and compare both with the same test inputs.

Keep incoming chat from becoming code

Names, messages, titles, amounts, and links come from viewers and outside services. Treat them as text, never as code. Clean them where your renderer puts them on the page.

FieldHow to show it
chatmessage with textonly truePlain text (textContent).
chatmessage otherwiseMay hold emotes and allowed formatting. Use the packaged sanitizer.
Names, amounts, titles, other plain fieldsPlain text (textContent).
chatimg, contentimg, linksURLs, not HTML. Check them with the page's existing media/link rules, then set DOM properties.
<!-- Example for a copied page at the repository root. -->
<script src="./libs/objects.js"></script>
<script src="./shared/utils/chatHtml.js"></script>
<script>
function renderChatBody(element, data) {
    var message = String(data.chatmessage == null ? "" : data.chatmessage);
    if (data.textonly) {
        element.textContent = message;
    } else {
        element.innerHTML = SocialStreamChatHTML.sanitize(message);
    }
}
// Names, amounts, titles, and other plain fields use textContent:
// nameElement.textContent = String(data.chatname || "");
</script>
  • If the page already has a sanitizer, keep it. Don't add a second one.
  • For files in subfolders, fix the script paths.
  • Don't paste raw names into attribute strings or raw colors into style markup. Check style values before setting them one property at a time.
  • Cleaned HTML still isn't safe to run as JavaScript or to use as an AI instruction.

More background: OWASP's guide to safe sinks and HTML sanitization.

How to test the renderer safely

Run these in a private local preview, not in public chat.

  • Use a name like Guest <b>One</b>. The brackets should show as text.
  • Send chatmessage: "<b>Hello</b>" with textonly: true, then false. One should show the tags as text; the other should show bold text.
  • Check a supported emote and an image-only message still work.
  • Have the AI test a harmless probe like <img src=x onerror="window.__ssnInjectionProbe=1">. It must not run, set the marker, or leave event attributes behind. Test a script-scheme link too.

A passing probe only covers the paths you tested. Focus on the renderers and fields your design changed.

Test it, one piece at a time

TestHow
LayoutUse the page's preview/demo mode if it has one, or made-up local samples. Try long names and messages, missing avatars, empty data, and the expected number of rows.
SSN deliveryKeep SSN on and use Create Test Message with the same session. The usual Extension API mode needs remote API control of extension turned on. Use a test setup: test messages can set off your automations.
The real triggerFeature a Dock message for a featured card, vote in a poll, pick a giveaway winner, change ticker text, or start a timer. Plain chat doesn't test everything.
Real captureCheck a real message or event reaches both the original and your copy. A fake event only proves the display works.
OBSCheck the final size, transparency, animations, audio, fonts, and layering. Try show/hide, clear/reset, and a refresh. OBS and your browser don't share logins or saved storage.
Refreshing can lose data. Some pages keep data in memory. Check the type guide before turning on auto-refresh or shutdown-when-hidden. Remove demo or preview from the link before expecting live data.

Files to give your AI

Give the AI the overlay's own file and the CSS/JS it loads, plus these. The event reference alone doesn't explain a poll's controls or each overlay's layout code.

FileWhat it's for
docs/event-reference.htmlOfficial fields, named events, metadata, media, and donation values.
docs/customoverlays.mdCustom receivers and connection examples.
Events and Alerts CompatibilityWhich events and fields each source sends.
Test-message guide and createtestmessage.htmlSample payloads and delivery modes.
libs/objects.js and shared/utils/chatHtml.jsThe packaged display sanitizer.
shared/utils/chatBadges.js and shared/utils/contentImage.jsExisting badge and image handling.
js/transport-dedupe.js, js/local-server-url.js, shared/overlay-control-transport.jsExisting connection support, when your page loads them.
currency.jsKeep hasDonation for display, and use a valid numeric USD donoValue, including zero.
Event Flow and Commands & APIReuse existing controls when the design needs a trigger.

Fix problems

ProblemTry this
File not foundDrag the HTML into your browser again and copy its address. Check the name ends in .html, not .html.txt.
Missing script, font, or imageKeep the unzipped folder as it is, with your copy next to the original. Check your added artwork and fonts are where the page expects.
Blank or “waiting” displayCheck the session, password, full ? and # parts, that SSN is running, the feature is on, and the right input is arriving. Compare with the original SSN link.
Looks different in OBS than the browserCheck width/height, old Custom CSS, fonts, cache, and browser storage. Refresh after saving.
Logo disappears on updateThe script may be rebuilding its container. Put permanent decoration outside it, or update the rendering template.
Data resets or actions happen twiceCheck refresh/unload settings, duplicate copies of the overlay or controls, and the page's own duplicate and state handling.
Special case: pages that read separate data files

The map loads local JSON files with fetch(), which browsers can block when opening from disk. For a simple map restyle, use its hosted link with OBS Custom CSS. For an edited copy, ask your AI to put the map data inside the page so it opens from disk. Hosting is an advanced option for pages that really need it, not a normal step.

Fix the smallest confirmed problem first. A restyle shouldn't need changes to capture scripts or new event fields. If you share a public fork, include its assets and leave private launchers out.