Build games and rewards

Turn a gift, a support amount, or a chat command into something on your stream.

Yes, your game can react to TikTok gifts

Viewer sends a gift or chat Social Stream Ninja captures it Your page decides what happens

Your JavaScript picks the action: boost a rocket, grow a garden, spawn an enemy, or fill a shared goal. You also pick the threshold. SSN cannot change a platform's gift prices.

I want to…Start here
Play a sound, alert, OBS action, or webhookEvent Flow (no code)
Build a game board or keep my own game stateA starter template below
Use a finished gameThe game gallery

Pick a starter

Each preview has sample buttons and a “Last received payload” inspector. Samples are fake events, not purchases. Preview mode never joins your live session.

StarterWhat it doesChange this
Coin rocket10 TikTok coins, 100 Twitch Bits, or 100 Facebook Stars earn one boost. Leftovers are saved per viewer and platform.COST
Shared support goalEstimated USD from all four platforms builds a moon base. Swap the progress for damage, fuel, or a timer.GOAL_USD
Gift and event gardenA chosen TikTok gift adds flowers. A TikTok follow adds a tree. Free !water chat adds water.GIFT_ID (a captured ID) or GIFT_NAME (exact name). “Demo flower” is made up.
  • In the HTML, search for EDIT THIS RULE or EDIT THESE RULES.
  • Put your game logic in the receive(data) function.
  • Connection and counting helpers live in starter.js. Styles live in starter.css.

Connect a starter in 3 steps

  1. Start SSN and connect your chat. Check that chat and gifts show up in the dock. For TikTok, see connection modes.
  2. Open the starter without ?demo, using your session ID (and password, if you set one).
  3. Check it in a browser. Then add the same link to OBS as a Browser Source, for example 1000 × 800.
https://socialstream.ninja/games/templates/coin-rocket.html?session=YOUR_SESSION&password=YOUR_PASSWORD&clean
  • &clean hides the inspector, connection status, and host buttons.
  • No password? Leave out &password=….
  • On the beta site, keep /beta/ before games/.
Keep your session links private.
Other connection routes (WebSocket)

By default the starters use the same iframe bridge as SSN overlays.

  • Hosted WebSocket: turn on Send messages to Dock from Extension via server in SSN, then add &server2.
  • Local server: add &server2&localserver, or &localserverport=3000. See the WebSocket guide.
  • localserver alone does not turn on a route.
  • The older server feed uses a different channel and may need a dock publishing to it.

Make your own copy and run it from disk

No server to install. You edit a file on your computer and point OBS at it.

  1. Download the beta source ZIP and extract it.
  2. Copy the starter you want, next to the original. Example: games/templates/my-rocket.html.
  3. Keep the folder layout as is. Starters load js/local-server-url.js, and the support goal loads currency.js from the top folder. Keep any images or audio in place too.
  4. Drag your HTML file into Chrome or Edge and copy the file:/// address.
  5. Add everything from ? onward from your working game link (session, password, transport options).
  6. In OBS, leave Local file unchecked. Paste the full address into the Browser Source URL field.
  7. After each edit, refresh the Browser Source.
file:///C:/SSN/social_stream-beta/games/templates/my-rocket.html?session=YOUR_SESSION&clean

Use your real path. Don't move the extracted folder. The session is your SSN connection ID, not the game name. Remove demo for live input. Keep SSN and capture running. More examples: file setup guide.

Editing an existing game? You can copy any page from games/. games.html and battle.html have their own game logic. The starters' rule settings are not a shared game API.
AI prompt for restyling a game

Give the AI your copied HTML, starter.js, starter.css, the root js/ helpers, any art or audio, and docs/event-reference.html.

Customize [game file] to match [reference], at [canvas size].
Include its existing CSS/JS and local artwork/audio. Preserve the game's
rules, controls, gift/coin/USD distinctions, streak handling, duplicate
handling, and demo/clean modes. Change the visual design, not the reward rules,
unless I explicitly specify a rule change. Keep session/password and
transport parsing, relative paths, and Chrome 80-compatible classic scripts.
Read docs/event-reference.html and docs/making-games.html.

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 game work directly from disk using a file:/// URL,
without requiring a local web server.
Return the edited files/assets, file URL and OBS setup steps, and tests using
fictional data. Preserve image-only events and a valid donoValue of zero.
Never treat chat text as proof of a payment.

Then test in this order: demo buttons (including repeated streak updates and a zero-value override), your real session, then the OBS source at its real size. Check the game rules and safe rendering. A working animation alone doesn't prove the rules work.

How do I choose a coin amount for an action?

First decide what you are measuring. Then pick a number.

MeasureRead thisExample
Native units (coins, Bits, Stars)TikTok meta.coinsPerGift × meta.tiktokGiftCount when present, or a hasDonation label like 10 coins, 100 bits, 100 Stars.Every 10 coins = one boost.
One particular giftTikTok meta.giftId or meta.giftName, plus its count.Each matching gift adds a flower, whatever it's worth.
Comparable money valuegetDonationValueUSD(data) from currency.js.Each estimated $1 adds 10 fuel. $25 finishes the goal.
A free or membership actionThe source's real event, or a chat command.A follow grows a tree. A new sub plays an animation.

Exact, minimum, or running balance?

  • Exact: coins === 10. A 25-coin gift does nothing.
  • Minimum per event: coins >= 10.
  • Running balance: what the rocket uses. 25 coins = two boosts, with 5 coins left over.

Several tiers? Check the highest one first, so one gift doesn't trigger every lower tier.

TikTok coins aren't always known. If capture only gives a gift name, count, or diamond label, the coin rocket skips that event. Use a gift rule or the USD starter instead. Never get “exact coins” by dividing a USD estimate or by treating diamonds as coins.
More about TikTok coins, gifts, and diamonds
  • Viewers buy Coins and spend them on Gifts. The coin cost is shown with the gift. See TikTok's explanation of Coins and Gifts.
  • A gift name, gift count, Coins, and Diamonds are four different things.
  • Pick gifts available in your own LIVE, and check the captured data before you publish a rule.
  • Coin values can come from SSN's gift mapping. Compare with your current LIVE gift tray when exact pricing matters.
  • Gift catalogs and capture methods differ. No coin field is guaranteed on every TikTok message.

What each platform sends

type says where it came from. event says what happened, when present. What arrives depends on capture mode, settings, and the platform. This reflects SSN's current code, not a promise every account gets every event.

PlatformWhat you getWatch out for
TikToktype: "tiktok", event: "gift". Donation capture can add hasDonation and donoValue. Gift metadata may include ID, name, count, coins per gift, diamonds per gift, and streak ID.Coins buy Gifts; Diamonds are creator rewards. SSApp WebSocket capture settles streaks before sending; browser capture can send running totals. Turning off TikTok donation capture can leave gifts with no money fields.
TwitchCheers use Bits, like hasDonation: "100 bits". API capture can send event: "cheer" and donoValue: 1. Chat capture may have no event.Subs, gift subs, raids, and Channel Points are separate. A sub badge on a normal message is not a new sub. Bits used in Twitch Extensions are a different system.
FacebookVisible Stars rows in Live Chat give e.g. hasDonation: "100 Stars" and donoValue: 1, with no event.The comments API path doesn't read Stars from chat text. The Stars row must be visible to page capture. Comments and reactions are not payments.
YouTubesuperchat and supersticker carry the original currency in hasDonation. Gifts use jeweldonation with N Jewels, or 1 YouTube Gift if the amount is hidden.Viewers spend Jewels; creators earn Rubies. Memberships and gifted memberships are separate events. Super Thanks is a separate product, not a promised chat event.

Other sources can report tips, gifts, memberships, or purchases. Check the event reference before adding them to the starter's isSupport filter. A sale or gifted sub isn't automatically a tip. YouTube sends both the gift purchase and each recipient notice; counting both rewards the same gift twice.

Platform reference links

TikTok Diamonds · Twitch Bits and subscriptions · Meta's Stars overview · YouTube Super Chat and Super Stickers · YouTube Jewels, Gifts, and Rubies.

Terms checked September 29, 2026. Check current platform pages for eligibility.

Use donoValue and currency.js correctly

FieldWhat it is
hasDonationThe original label, like €5.00 or 100 bits. Show this to viewers.
donoValueOptional USD number from the source. If valid (even zero), use it before estimating from the label.
<script src="../../currency.js"></script>
<script>
// From games/templates/: use the existing helper, including its zero handling.
var usd = getDonationValueUSD(data);
// Use usd for your rule; display data.hasDonation for the original amount/unit.
</script>

Don't do this

  • donoValue || convertToUSD(...) — it throws away an intended zero.
  • Pulling numbers out of chatmessage to spot payments.
  • Requiring event === "donation" — Facebook Stars and some Cheers have no event.

The support-goal starter picks support types first, then calls the shared converter.

SSN's built-in estimates
UnitEstimated as
1 TikTok coin$0.01
1 TikTok diamond$0.005
1 Twitch Bit or Facebook Star$0.01
1 YouTube Jewel$0.005
Unpriced TikTok gift1 coin per gift
YouTube Gift with no Jewel count$0.01 placeholder

Other currencies use built-in approximate rates, not live exchange rates. These are for comparing support only. They are not what the viewer paid, what you earn, or what you can withdraw. Different capture methods can give different estimates. The one-coin fallback does not mean that gift costs one coin.

Source: currency.js and the payload reference. Gift metadata is optional; the examples don't invent fields your capture lacks.

Count a gift streak once

TikTok can report a streak as running totals: 1, 2, 3. That's three gifts, not six. Remember the highest total you've seen for that streak and only add the increase.

// All three events refer to the same streak:
// incoming total: 1, 2, 3, 3
// added to game:  1, 1, 1, 0
var newCoins = RewardStarter.increment(data, RewardStarter.coins(data), 'coins');
  • The helper matches streaks by TikTok group/sender/gift IDs, then meta.tiktokGiftStreakId, then message IDs. Message IDs also block repeat deliveries.
  • It doesn't wait for repeatEnd, because browser capture may never send it. Need one action only when a streak ends? Write a separate rule using the fields your connection sends.
  • Use one capture route. A second capture of the same channel can use different IDs and double count.
Memory limits of the starters
  • They remember up to 2,000 IDs, in memory only.
  • Reset or reload wipes that memory and the game progress.
  • Messages without stable IDs can't be reliably de-duplicated.
  • The rocket groups balances by platform and user ID, or display name if there's no ID. Viewers with the same name can share a balance.
  • For a game that must survive restarts, add saved state and replay handling before relying on paid rewards.

Rewards without a custom game

In Event Flow:

  1. Add Compare Property.
  2. Set it to donoValue, greater than or equal, and your USD amount.
  3. Connect an action, like a sound, animation, or OBS control.

It uses the source's own value when valid, and SSN's currency conversion otherwise.

  • One specific TikTok gift: compare meta.giftId or meta.giftName, and limit the flow to TikTok gift events.
  • Number checks on hasDonation also become USD. They are not raw coin checks. Use native metadata or custom code for coin rules.
  • Each check runs per message. It is not a running balance or streak counter. Use state nodes if you need that, or keep that logic in your game.

Test it before attaching a paid action

  1. Sample buttons. A 1 → 2 → 3 streak adds three gifts. The zero-override sample adds no USD. An unknown price adds no exact coins.
  2. Real source. Look at a real captured payload. Confirm the gift name/ID, amount, unit, count, and event. Samples test your rule, not live capture.
  3. OBS scene. Check repeated events, a reconnect, and a reload. Don't refresh or shut down the Browser Source if you need to keep the in-memory progress.
ProblemTry this
Nothing arrivesCheck the SSN dock first. Then the session, password, and transport setting.
Chat arrives but a gift doesn't matchLook at the payload, and check your donation and event filters.
No follows or subsThis varies by source. See the event reference.
Running an unattended (AFK) game? SSN, capture, and the game page must all stay running. Sleep, an expired login, or a dropped feed stops actions. The starters don't catch up on missed events or handle refunds. Automated reactions don't make an unattended stream allowed to earn money; check the platform's current LIVE and monetization rules.

More connection details: custom overlays.