TikTok LIVE WebSocket API
Stream gifts, joins, likes and PK battles from any LIVE room the moment they happen — plus goody bags and treasure boxes. One connection, decoded JSON, no per-minute billing.
Updated
How it works
Three steps from API key to live gifts
Mint a stream token
Your API key asks for a short-lived token; the SDKs do this and refresh it for you.
POST /v1/live/stream/token
→ { "token": "…", "wsUrl": "wss://…" }Subscribe to creators
Send one command per @handle. Each one is a LIVE room your plan holds; offline creators wait and start when they go live.
{"type":"subscribe","creatorId":"@creator_handle"}
→ status: queued → activeReceive decoded frames
Every event is JSON with the creator, the room and a decoded body — gifts already carry their diamond value.
{"type":"event","event":"gift",
"data":{"decoded":{"gift":{"giftName":"Rose"…}}}}Events
Everything that happens in the room
Gifts with their real diamond value, every join, like, follow and comment, PK and team battles with their live score, the room's viewers and rank — and the goody bags and treasure boxes dropped in it.
Giftsgift
Every gift with its name, type, diamond value and sender — streaks, batch sends (one frame per gift) and gifts to guests included.
Sample data.decoded
{
"gift": { "giftName": "Rose", "diamondCount": 1, "giftType": 1 },
"repeatCount": 5,
"repeatEnd": true,
"isCompleted": true,
"fanTicketCount": 0,
"user": { "uniqueId": "whale_01", "nickname": "Top Fan" }
}Subscriptionssubscribe
A new or renewed paid subscription to the creator, with how many months in a row.
Sample data.decoded
{
"subMonth": 3,
"subscribeType": 1,
"user": { "uniqueId": "loyal_fan", "nickname": "Loyal Fan" }
}Joinsmember
Each viewer who enters the room, with the room's running member count.
Sample data.decoded
{
"action": 1,
"memberCount": 3120,
"user": { "uniqueId": "new_viewer" }
}Likeslike
Like bursts with the room's total so far.
Sample data.decoded
{
"likeCount": 15,
"totalLikeCount": 998240,
"user": { "uniqueId": "fan_77" }
}Follows & sharessocial
Who followed the creator or shared the LIVE, with running counts.
Sample data.decoded
{
"socialType": "follow",
"followCount": 412,
"user": { "uniqueId": "loyal_viewer" }
}Commentschat
Every comment posted in the room and who wrote it.
Sample data.decoded
{
"comment": "let's go 🔥",
"user": { "uniqueId": "guest_842", "nickname": "Guest", "verified": false }
}Viewers & top giftersroomUser
Viewers right now, total entries and the room's top contributors by coins.
Sample data.decoded
{
"viewerCount": 2841,
"totalUser": 51230,
"topViewers": [
{ "rank": 1, "coinCount": 12040, "user": { "uniqueId": "whale_01" } }
]
}PK battle startslinkMicBattle
The moment a battle starts: its format — 1v1, 2v2, 1v3 or free-for-all — and every host on the roster.
Sample data.decoded
{
"battleType": 1,
"participants": [
{ "user": { "uniqueId": "hostA", "nickname": "Host A" } },
{ "user": { "uniqueId": "hostB", "nickname": "Host B" } }
]
}Battle scorelinkMicArmies
The live score: each host in a 1v1; each team's points and every host's own points in team and multi-host battles.
Sample data.decoded
{
"battleId": "7700872369384409908",
"battleStatus": 1,
"battleType": 2,
"teams": [],
"teamArmies": [
{ "teamId": "1", "points": 2200, "hosts": [ { "userId": "111", "points": 1200 }, { "userId": "333", "points": 1000 } ] },
{ "teamId": "2", "points": 980, "hosts": [ { "userId": "222", "points": 980 }, { "userId": "444", "points": 0 } ] }
]
}Went LIVEliveStart
The creator just went live — a subscription that was waiting starts streaming on its own.
Sample data.decoded
{
"startedAt": "2026-08-05T10:00:00.000Z"
}Paused & endedcontrol
The LIVE was paused, resumed, ended or suspended.
Sample data.decoded
{
"action": "STREAM_ENDED",
"isStreamEnd": true,
"tips": ""
}Hourly rankhourlyRank
Where the room stands on TikTok's hourly ranking right now.
Sample data.decoded
{
"type": "hourly",
"label": "No. 3",
"rankId": "3",
"colour": "#FFB300"
}Goody bagsgoodyBag
+ drop feedA goody bag the moment it appears: coins, how many people share it, who may join and when it opens.
Sample frame
{
"type": "goodybag.event",
"event": "goodyBag",
"eventId": "evt_goody_bag:7699967922753145632:7700088522992667425",
"roomId": "7699967922753145632",
"creatorId": "creator_handle",
"creatorUid": "7298720060985852961",
"goodyBag": {
"roomId": "7699967922753145632",
"goodyBagId": "7700088522992667425",
"biz": "Fan club",
"diamondCount": 500,
"peopleCount": 100,
"countDownMinutes": 10,
"unpackAt": 1793629815,
"joinedHeadcount": 61,
"participateMethod": "Share",
"participateMethodContent": "",
"participateThresholdSelected": "Level: 3"
},
"is_bxh": 1,
"room": {
"country": {
"code": "US",
"name": "United States",
"flag": "🇺🇸"
},
"regionGroup": null,
"liveUrl": "https://www.tiktok.com/@creator_handle/live",
"viewerCount": 1912
},
"provenance": {
"observedAt": "2026-11-02T14:20:15.069Z",
"freshness": "near_realtime",
"source": "platform_observed_goody_bag_poll",
"coverageStatus": "observed",
"methodologyVersion": "goodybag-watch-v1"
}
}Treasure boxestreasureBox
+ drop feedA treasure box with its colour (red, green or gold), coins, number of people, sender and opening time. Rooms you stream send it as the envelope room event.
Sample frame
{
"type": "goodybag.event",
"event": "treasureBox",
"eventId": "evt_chest:7700091835551205128",
"roomId": "7699967922753145632",
"creatorId": "dance.queen",
"creatorUid": "7298720060985852961",
"chest": {
"envelopeId": "7700091835551205128",
"businessType": 1,
"color": "red",
"diamondCount": 2000,
"peopleCount": 40,
"unpackAt": 1793630001,
"createAtMs": 1793629821000,
"sendUserId": "6950012345678901234",
"sendUserName": "Top Fan"
},
"is_bxh": 1,
"room": {
"country": {
"code": "US",
"name": "United States",
"flag": "🇺🇸"
},
"regionGroup": null,
"liveUrl": "https://www.tiktok.com/@dance.queen/live",
"viewerCount": 1912
},
"provenance": {
"observedAt": "2026-11-02T14:20:16.004Z",
"freshness": "near_realtime",
"source": "platform_observed_treasure_chest_push",
"coverageStatus": "observed",
"methodologyVersion": "treasure-box-v1"
}
}Treasure-box statustreasureBoxStatus
+ drop feedA follow-up when the timer ran out (pending) and when the box left the room (closed).
Sample frame
{
"type": "goodybag.event",
"event": "treasureBoxStatus",
"eventId": "evt_chest_status:7700091835551205128:closed:hidden",
"roomId": "7699967922753145632",
"creatorId": "dance.queen",
"creatorUid": "7298720060985852961",
"chest": {
"envelopeId": "7700091835551205128",
"status": "closed",
"reason": "hidden",
"at": "2026-11-02T14:33:41.000Z",
"businessType": 1,
"color": "red",
"diamondCount": 2000,
"peopleCount": 40,
"unpackAt": 1793630001,
"createAtMs": 1793629821000,
"sendUserId": "6950012345678901234",
"sendUserName": "Top Fan"
},
"is_bxh": 1,
"provenance": {
"observedAt": "2026-11-02T14:23:41.200Z",
"freshness": "near_realtime",
"source": "platform_observed_treasure_chest_push",
"coverageStatus": "observed",
"methodologyVersion": "treasure-box-status-v1"
}
}Every field and edge case in the realtime reference and the goody-bag feed docs.
Add-on · same WebSocket
Catch every goody bag and treasure box before it opens
Every plan already streams the treasure boxes of the rooms you subscribe to. The drop feed adds goody bags, watches many more rooms for you and sends one frame the moment a goody bag or a treasure box appears in one: how many coins it holds, how many people share it and exactly when it opens.
- Watch the rooms that matter — the best-ranked LIVE rooms (the set refills as rooms end) or your own list of creators.
- Filter before it reaches you — minimum coins, coins per person, join level, room size, chest colour (red, green, gold), leaderboard rooms only.
- Follow each treasure box — a second frame when its timer runs out and when it leaves the room.
- One frame per drop — de-duplicated, with the room's viewer count when it is known.
Sold per watched room, separately from your plan.
Pricing
Pay for LIVE rooms, not minutes
You pay for how many LIVE rooms stream to you at once — all over one WebSocket connection. Every plan is one flat monthly price, and every step up costs less per room.
One room = one creator's LIVE. Every room comes over the same connection.
- LIVE rooms at once
- 600
- Price per room
- $0.065
- Per room you stream
- $0.16
Room to grow: 350 more rooms before you need Scale.
More than 3,000 rooms, yearly invoicing, or goody bags bundled in? Sales sets it up.
Code
A gift stream in a dozen lines
- Tokens handledThe SDK mints the short-lived handshake token and renews it.
- Reconnects and resubscribesA dropped connection comes back with your creators still subscribed.
- Exact diamondsCount a gift on the frame where isCompleted is true: diamondCount × repeatCount — a streak once, each gift of a batch send once.
import asyncio from toktik import TokTikClient async def main(): client = TokTikClient(api_key="ttk_live_...") async for frame in await client.live.stream(["@creator_handle"]): if frame.type == "status": print("status", frame.creator_id, frame.status) elif frame.type == "event" and frame.event == "gift": g = frame.data["decoded"] if g.get("isCompleted"): print(g["gift"]["giftName"], g["gift"]["diamondCount"] * g["repeatCount"]) asyncio.run(main())
import { TokTikClient } from "@toktikhq/sdk-js"; const client = new TokTikClient({ apiKey: process.env.TOKTIK_API_KEY! }); const stream = await client.live.stream(["@creator_handle"], { onStatus: (s) => console.log("status", s.creatorId, s.status), // queued → active onEvent: (frame) => { if (frame.event === "gift") { const g = frame.data.decoded; if (g.isCompleted) console.log(g.gift?.giftName, (g.gift?.diamondCount ?? 0) * g.repeatCount); } }, onError: (e) => console.error(e), onReconnect: (attempt) => console.warn("reconnected", attempt) }); // later: await stream.close();
Compare
Hosted WebSocket or a self-hosted LIVE connector?
Open-source “TikTok LIVE connector” libraries join one room from your own process — fine for a room or two, hard work when you follow hundreds.
| Aspect | Self-hosted connector | Toktik WebSocket API |
|---|---|---|
| Where it runs | Your servers: one connection per room you follow. | Toktik holds the rooms; you open one connection for all of them. |
| Many rooms | You manage connections, retries and limits as you grow. | One connection for every LIVE room your plan holds. |
| TikTok changes | You wait for a library update, then redeploy. | Toktik updates the collection; your /v1 frames stay the same. |
| Events | Raw room messages to decode and de-duplicate yourself. | Decoded JSON: diamonds per gift, batch sends split, team battle scores. |
| Goody bags & treasure boxes | You poll and watch every room yourself. | Treasure boxes in every room you stream; the drop feed adds goody bags and rooms you don't stream, filtered by coins, level and colour. |
| Beyond the room | — | Rankings, gifter boards and creator history on the same key. |
| Cost | Servers, proxies and engineering time. | From $0 (1 LIVE room) down to $0.033 per room a month. No per-minute billing. |
FAQ
Questions developers ask
Something else? Ask us.
Is there an official TikTok LIVE WebSocket API?
Not a public one for LIVE events, as far as we know. Toktik's WebSocket API is an independent service that streams the public events of the LIVE rooms you subscribe to. It is not affiliated with TikTok.
What counts toward my plan?
The LIVE rooms streaming to you at the same time. A plan with 600 rooms follows 600 creators at once, all over one WebSocket connection. New rooms open in turn — each subscription reports queued, then active. Unsubscribe from a creator and that room is free for another.
Am I billed per minute?
No. The monthly plan price covers your LIVE rooms however long they stream, and streaming spends no credits — your credits stay for REST reads.
What happens when all my plan's rooms are in use?
The next subscription gets the status unavailable with the reason plan_cap_reached until you unsubscribe from a creator or move up a plan. Nothing is billed extra.
Does an offline creator count?
It can, while you stay subscribed. The subscription waits as offline and starts streaming when the creator goes live, on the same connection — no need to reconnect.
Can I get goody bags and treasure boxes?
Yes. Treasure boxes arrive in every room you stream as the envelope room event, on every plan. The drop feed on the same WebSocket adds goody bags and catches both in many more rooms than you stream — the best-ranked LIVE rooms or creators you name: one frame per goody bag or treasure box, filtered by coins, level and colour, with a follow-up when a treasure box closes. The drop feed is sold per watched room, separately from your plan — ask us to turn it on.
Which events can I receive?
Gifts (batch sends and gifts to guests included), subscriptions, joins, likes, follows and shares, comments, viewer counts and top gifters, PK battles with their live score (1v1, 2v2, 1v3, free-for-all), the creator going live, pauses and the end of the LIVE, the hourly rank, and the treasure boxes dropped in those rooms. The drop feed adds goody bags, and drops from rooms you don't stream.
Is there a Python or Node.js SDK?
Yes: toktik 0.4.0 on PyPI (with the realtime extra) and @toktikhq/sdk-js 0.5.0 on npm. Both handle the token, reconnects and resubscribing.
Stream your first LIVE room today
Create a free key, subscribe to one creator and watch the gifts arrive. Move up a plan when you need more rooms.
Toktik is independent and not affiliated with TikTok.
@dance.queen
Galaxy ×1 ·
Rose ×5 ·