Yes, your game can react to TikTok gifts
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 webhook | Event Flow (no code) |
| Build a game board or keep my own game state | A starter template below |
| Use a finished game | The 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.
| Starter | What it does | Change this |
|---|---|---|
| Coin rocket | 10 TikTok coins, 100 Twitch Bits, or 100 Facebook Stars earn one boost. Leftovers are saved per viewer and platform. | COST |
| Shared support goal | Estimated USD from all four platforms builds a moon base. Swap the progress for damage, fuel, or a timer. | GOAL_USD |
| Gift and event garden | A 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 RULEorEDIT 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
- Start SSN and connect your chat. Check that chat and gifts show up in the dock. For TikTok, see connection modes.
- Open the starter without
?demo, using your session ID (and password, if you set one). - 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
&cleanhides the inspector, connection status, and host buttons.- No password? Leave out
&password=…. - On the beta site, keep
/beta/beforegames/.
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. localserveralone does not turn on a route.- The older
serverfeed 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.
- Download the beta source ZIP and extract it.
- Copy the starter you want, next to the original. Example:
games/templates/my-rocket.html. - Keep the folder layout as is. Starters load
js/local-server-url.js, and the support goal loadscurrency.jsfrom the top folder. Keep any images or audio in place too. - Drag your HTML file into Chrome or Edge and copy the
file:///address. - Add everything from
?onward from your working game link (session, password, transport options). - In OBS, leave Local file unchecked. Paste the full address into the Browser Source URL field.
- 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.
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.
| Measure | Read this | Example |
|---|---|---|
| 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 gift | TikTok meta.giftId or meta.giftName, plus its count. | Each matching gift adds a flower, whatever it's worth. |
| Comparable money value | getDonationValueUSD(data) from currency.js. | Each estimated $1 adds 10 fuel. $25 finishes the goal. |
| A free or membership action | The 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.
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.
| Platform | What you get | Watch out for |
|---|---|---|
| TikTok | type: "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. |
| Twitch | Cheers 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. |
Visible 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. | |
| YouTube | superchat 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
| Field | What it is |
|---|---|
hasDonation | The original label, like €5.00 or 100 bits. Show this to viewers. |
donoValue | Optional 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
chatmessageto 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
| Unit | Estimated 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 gift | 1 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:
- Add Compare Property.
- Set it to
donoValue, greater than or equal, and your USD amount. - 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.giftIdormeta.giftName, and limit the flow to TikTok gift events. - Number checks on
hasDonationalso 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
- Sample buttons. A 1 → 2 → 3 streak adds three gifts. The zero-override sample adds no USD. An unknown price adds no exact coins.
- 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.
- 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.
| Problem | Try this |
|---|---|
| Nothing arrives | Check the SSN dock first. Then the session, password, and transport setting. |
| Chat arrives but a gift doesn't match | Look at the payload, and check your donation and event filters. |
| No follows or subs | This varies by source. See the event reference. |
More connection details: custom overlays.