> ## Documentation Index
> Fetch the complete documentation index at: https://tiktools.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket Events

> Complete reference for all 30+ real-time events available via the TikTok Live WebSocket API.

## Event Types

Every WebSocket message contains an `event` field and a `data` object. Below is the complete list of events.

### chat

A viewer sends a chat message.

```json theme={null}
{
  "event": "chat",
  "data": {
    "type": "chat",
    "comment": "Hello streamer!",
    "user": {
      "uniqueId": "viewer123",
      "nickname": "Cool Viewer",
      "userId": "6892636847263982593",
      "profilePictureUrl": "https://...",
      "followRole": 0,
      "userBadges": [],
      "isModerator": false,
      "isSubscriber": false
    },
    "emotes": []
  }
}
```

| Field               | Type              | Description                                                                                                                                                    |
| ------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `comment`           | string            | The chat message text                                                                                                                                          |
| `user`              | object            | Sender's profile info                                                                                                                                          |
| `user.uniqueId`     | string            | TikTok username                                                                                                                                                |
| `user.nickname`     | string            | Display name                                                                                                                                                   |
| `user.userId`       | string            | Numeric user ID                                                                                                                                                |
| `user.isModerator`  | boolean           | Whether user is a moderator                                                                                                                                    |
| `user.isSubscriber` | boolean           | Whether user is a subscriber                                                                                                                                   |
| `emotes`            | array             | Custom emotes used in the message                                                                                                                              |
| `language`          | string\|undefined | **v3 (2026-06-07)**: ISO 639-1 language code TikTok auto-detected for this comment ("en", "tr", "un" = unknown).                                               |
| `messageUuid`       | string\|undefined | **v3 (2026-06-07)**: stable per-message UUID. Used by the upcoming `imDelete` moderation event to correlate "this chat got deleted" back to the original line. |
| `protoVersion`      | number\|undefined | **v3 (2026-06-07)**: 3 when this event carries v3-only fields, otherwise 2. See [Schema Versions](#schema-versions) below.                                     |

***

### gift

A viewer sends a virtual gift.

```json theme={null}
{
  "event": "gift",
  "data": {
    "type": "gift",
    "giftName": "Rose",
    "giftId": 5655,
    "diamondCount": 1,
    "repeatCount": 5,
    "repeatEnd": true,
    "giftType": 1,
    "giftPictureUrl": "https://...",
    "user": {
      "uniqueId": "gifter",
      "nickname": "Gift Sender",
      "userId": "123456"
    }
  }
}
```

| Field            | Type              | Description                                                                                                                                                                                                                |
| ---------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `giftName`       | string            | Name of the gift                                                                                                                                                                                                           |
| `giftId`         | number            | Gift identifier                                                                                                                                                                                                            |
| `diamondCount`   | number            | Diamond value of the gift                                                                                                                                                                                                  |
| `repeatCount`    | number            | How many times this gift was sent in a streak                                                                                                                                                                              |
| `repeatEnd`      | boolean           | `true` when the gift streak ends (final count)                                                                                                                                                                             |
| `giftType`       | number            | 1 = repeatable, 2 = non-repeatable                                                                                                                                                                                         |
| `giftPictureUrl` | string            | URL of the gift image                                                                                                                                                                                                      |
| `transactionId`  | string\|undefined | **v3 (2026-06-07)**: stable per-gift transaction UUID (hex). Dedup key across upstream retries - the same combo always carries the same `transactionId` even when `repeatCount` updates twice.                             |
| `senderUserId`   | string\|undefined | **v3 (2026-06-07)**: explicit sender id parsed from the `{"sender_id":"..."}` envelope. Mirrors `user.id` but delivered separately on the wire so it remains available on truncated frames.                                |
| `relationship`   | object\|undefined | **v3 (2026-06-07)**: relationship metadata when TikTok attaches it. Shape: `{ joinDayNumber, fromUser, toUser }`. `joinDayNumber` = days the gifter has been following the creator. Use for "Day 131 fan sent X" overlays. |
| `protoVersion`   | number\|undefined | **v3 (2026-06-07)**: 3 when v3-only fields are present, otherwise 2.                                                                                                                                                       |

<Note>
  For streak gifts (`giftType: 1`), wait for `repeatEnd: true` to get the final count. Intermediate events show the running count.
</Note>

***

### like

A viewer sends likes.

```json theme={null}
{
  "event": "like",
  "data": {
    "type": "like",
    "likeCount": 15,
    "totalLikeCount": 5678,
    "user": { "uniqueId": "liker", "nickname": "Like Fan" }
  }
}
```

| Field            | Type   | Description               |
| ---------------- | ------ | ------------------------- |
| `likeCount`      | number | Likes sent in this batch  |
| `totalLikeCount` | number | Total likes in the stream |

***

### member

A viewer joins the live stream.

```json theme={null}
{
  "event": "member",
  "data": {
    "type": "member",
    "user": { "uniqueId": "new_viewer", "nickname": "New Viewer" },
    "actionId": 1,
    "actionCode": 38,
    "entrySource": "homepage_hot-live_cell",
    "entryAction": "draw",
    "entryType": "rec",
    "protoVersion": 3
  }
}
```

| Field          | Type              | Description                                                                                                                                                                                                                      |
| -------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user`         | object            | The viewer who joined                                                                                                                                                                                                            |
| `actionId`     | number            | Legacy action id (1 = join). Kept for backwards compat with v1/v2 clients.                                                                                                                                                       |
| `actionCode`   | number\|undefined | **v3 (2026-06-07)**: granular numeric subcode (38, 44, ...). Finer-grained than `actionId`.                                                                                                                                      |
| `entrySource`  | string\|undefined | **v3 (2026-06-07)**: where the viewer came from. Examples: `"homepage_hot-live_cell"` (Discover hot row), `"follow-tab"`, `"share-link"`. Critical creator-analytics signal - shows what surface drives a creator's viewer base. |
| `entryAction`  | string\|undefined | **v3 (2026-06-07)**: how the viewer entered. `"draw"` = TikTok algorithmically pulled the viewer in. `"click"` = explicit click (search / follow). `"other"` = uncategorised.                                                    |
| `entryType`    | string\|undefined | **v3 (2026-06-07)**: `"rec"` when TikTok recommended this stream. Absent on direct joins.                                                                                                                                        |
| `protoVersion` | number\|undefined | **v3 (2026-06-07)**: 3 when v3-only fields are present, otherwise 2.                                                                                                                                                             |

***

### caption

**v3 (2026-06-07).** TikTok native auto-captions on the LIVE WebSocket. Each frame carries one caption window with text + start/end timestamps + `isFinal` flag. This is what TikTok's own viewer UI renders for accessibility and the Discover feed; it is independent of the operator-managed TikTok Live Captions product.

```json theme={null}
{
  "event": "caption",
  "data": {
    "type": "caption",
    "text": "Hello everyone welcome to the stream",
    "isFinal": true,
    "startedAtMs": 1780798747292,
    "endsAtMs": 1780798748292,
    "protoVersion": 3
  }
}
```

| Field          | Type    | Description                                                                                                                      |
| -------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `text`         | string  | Caption text (utf-8). Partial windows arrive while the speaker talks; the final window for the same segment has `isFinal: true`. |
| `isFinal`      | boolean | `true` on the segment-final caption, `false` on partial / streaming updates.                                                     |
| `startedAtMs`  | number  | Caption window start (ms epoch on TikTok server clock).                                                                          |
| `endsAtMs`     | number  | Caption window end (ms epoch).                                                                                                   |
| `protoVersion` | number  | Always 3 - this event was added in the v3 schema.                                                                                |

***

### linkMicOpponentGift

**v3 (2026-06-07).** Per-gift breakdown from the OPPONENT side of a PK. TikTok now ships every gift sent on the opposing host's stream as a separate frame, so PK dashboards no longer need to relay-tap the opponent's room separately.

**v3.1 (2026-07-07).** Now carries `diamondCount` and `repeatCount`, making cross-room and out-of-room gifts fully itemizable from a single connection: price a combo frame as `diamondCount x (repeatCount delta)` keyed on `transactionId`.

<Note>
  **Being phased out (2026-07-07).** TikTok has stopped emitting this standalone event for most rooms and instead embeds the triggering gift inline on `battleArmies` as `lastGift`. Consume both: prefer `battleArmies.lastGift` when present, fall back to this event.
</Note>

```json theme={null}
{
  "event": "linkMicOpponentGift",
  "data": {
    "type": "linkMicOpponentGift",
    "senderUserId": "7366557450243605522",
    "opponentRoomId": "7569885742970635284",
    "giftId": 5655,
    "diamondCount": 1,
    "repeatCount": 17,
    "giftPictureUrl": "https://...",
    "startedAtMs": 1780798748470,
    "endsAtMs": 1780798748589,
    "transactionId": "2026060710190765D03BD889F88B8F065D",
    "protoVersion": 3
  }
}
```

| Field            | Type   | Description                                                                                                                                                                                   |
| ---------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `senderUserId`   | string | TikTok user id of the opponent-side gifter.                                                                                                                                                   |
| `opponentRoomId` | string | Room id of the opposing host.                                                                                                                                                                 |
| `giftId`         | number | Gift identifier (same id-space as the main `/webcast/gift_info` catalog).                                                                                                                     |
| `diamondCount`   | number | **v3.1**: per-unit diamond value of the gift. Constant per giftId and matches the catalog price.                                                                                              |
| `repeatCount`    | number | **v3.1**: running combo counter within a `transactionId`. Most combos never send a terminal frame - consume per-frame deltas, the same rule as `giftType: 1` combos on the main `gift` event. |
| `giftPictureUrl` | string | Full TikTok CDN URL for the gift image.                                                                                                                                                       |
| `startedAtMs`    | number | Gift animation start (ms epoch).                                                                                                                                                              |
| `endsAtMs`       | number | Gift animation end (ms epoch).                                                                                                                                                                |
| `transactionId`  | string | Stable per-gift UUID (hex) - dedup key.                                                                                                                                                       |
| `protoVersion`   | number | Always 3.                                                                                                                                                                                     |

***

### imDelete

**v3 (2026-06-07).** Chat moderation delete. Correlate back to the original chat event via `chat.messageUuid` (also v3).

```json theme={null}
{
  "event": "imDelete",
  "data": {
    "type": "imDelete",
    "deletedMsgId": "7648470148944628496",
    "protoVersion": 3
  }
}
```

***

### goalUpdate

**v3 (2026-06-07).** Stream goal progress (subscriber goal, gift goal, watch-time goal).

```json theme={null}
{
  "event": "goalUpdate",
  "data": {
    "type": "goalUpdate",
    "goalKey": "live_goal_indicator_stream_goal",
    "creatorUserId": "7280230115615114245",
    "contributionLevel": 4,
    "metadataJson": "{\"is_first_contribute\":false,\"challenge_type\":0,\"update_source\":2}",
    "protoVersion": 3
  }
}
```

| Field               | Type   | Description                                                              |
| ------------------- | ------ | ------------------------------------------------------------------------ |
| `goalKey`           | string | TikTok goal key, e.g. `"live_goal_indicator_stream_goal"`.               |
| `creatorUserId`     | string | User id of the creator running the goal.                                 |
| `contributionLevel` | number | Current contribution level (1..N).                                       |
| `metadataJson`      | string | Raw JSON: `{ is_first_contribute, challenge_type, update_source, ... }`. |
| `protoVersion`      | number | Always 3.                                                                |

***

### countdownForAll

**v3.2 (2026-07-07).** A timed "countdown for all" ranking round shown to every viewer - the gift-race / mission countdown used by game-mode PKs. Carries the round window and a live rank-ordered leaderboard of participants with their scores.

```json theme={null}
{
  "event": "countdownForAll",
  "data": {
    "type": "countdownForAll",
    "startedAtMs": 1783449438672,
    "endsAtMs": 1783449558841,
    "durationSec": 120,
    "participants": [
      { "userId": "6968452437901788165", "score": 199, "rank": 1 },
      { "userId": "7542969520541942806", "score": 199, "rank": 2 },
      { "userId": "6742123907992273925", "score": 0, "rank": 3 }
    ],
    "protoVersion": 3
  }
}
```

| Field                   | Type   | Description                                  |
| ----------------------- | ------ | -------------------------------------------- |
| `startedAtMs`           | number | Round start (ms epoch).                      |
| `endsAtMs`              | number | Round end (ms epoch).                        |
| `durationSec`           | number | Round length in seconds.                     |
| `participants[]`        | array  | Live standings, rank-ordered (rank 1 first). |
| `participants[].userId` | string | Entrant's TikTok userId.                     |
| `participants[].score`  | number | Score so far (0 if none yet).                |
| `participants[].rank`   | number | Current rank.                                |
| `protoVersion`          | number | Always 3.                                    |

***

### competitionRankList

**v3.2 (2026-07-07).** A competition / event ranking snapshot pushed to the room (seasonal events, hosted tournaments). Rank-ordered entries with score. Rare - a handful per hour across all rooms.

```json theme={null}
{
  "event": "competitionRankList",
  "data": {
    "type": "competitionRankList",
    "competitionId": "7637443360546145300",
    "entries": [
      { "userId": "7650050378419242004", "rank": 1, "score": 3120 },
      { "userId": "7615529915723416597", "rank": 2, "score": 2813 }
    ],
    "protoVersion": 3
  }
}
```

| Field              | Type   | Description              |
| ------------------ | ------ | ------------------------ |
| `competitionId`    | string | Competition / event id.  |
| `entries[]`        | array  | Rank-ordered entries.    |
| `entries[].userId` | string | Entrant's TikTok userId. |
| `entries[].rank`   | number | Current rank.            |
| `entries[].score`  | number | Score.                   |
| `protoVersion`     | number | Always 3.                |

***

### privilegeAdvance

**v3 (2026-06-07).** Viewer privilege tier-up notification (gallery lit-up, sub-perk advances). Carries TikTok CDN background frame URLs so overlays can render the banner without a separate fetch.

```json theme={null}
{
  "event": "privilegeAdvance",
  "data": {
    "type": "privilegeAdvance",
    "privilegeKey": "gallery_all_lit_up_d",
    "action": "gift_broadcast_msg",
    "bgUrls": [
      "https://p16-webcast.tiktokcdn.com/...",
      "https://p16-webcast.tiktokcdn.com/...",
      "https://p16-webcast.tiktokcdn.com/..."
    ],
    "protoVersion": 3
  }
}
```

***

### commentTray

**v3 (2026-06-07).** Comment tray UI state change.

```json theme={null}
{
  "event": "commentTray",
  "data": {
    "type": "commentTray",
    "trayCount": 3978,
    "updatedAtMs": 1780798747613,
    "relatedMsgId": "7648470148944628496",
    "protoVersion": 3
  }
}
```

***

### linkLayer

**v3 (2026-06-07).** PK / link-mic negotiation event (invite, cancel, accept, source change). Fires throughout the PK lifecycle alongside `battle`.

```json theme={null}
{
  "event": "linkLayer",
  "data": {
    "type": "linkLayer",
    "action": 11,
    "subAction": 4,
    "sourceType": "SOURCE_TYPE_FRIEND_LIST",
    "targetUserId": "7648408274391419681",
    "protoVersion": 3
  }
}
```

| Field          | Type              | Description                                                                                 |
| -------------- | ----------------- | ------------------------------------------------------------------------------------------- |
| `action`       | number            | Top-level action code (11 = invite, ...).                                                   |
| `subAction`    | number            | Sub-action code.                                                                            |
| `sourceType`   | string\|undefined | Where the link originated. Examples: `"inviteCancel_new_arc"`, `"SOURCE_TYPE_FRIEND_LIST"`. |
| `targetUserId` | string\|undefined | User id of the link target.                                                                 |
| `protoVersion` | number            | Always 3.                                                                                   |

***

### link

**v3 (2026-06-07).** Generic link-mic envelope (lower-level than `linkMicMethod` / `linkMicLayoutState`).

```json theme={null}
{
  "event": "link",
  "data": {
    "type": "link",
    "action": 20,
    "subAction": 4,
    "relatedUser": { "uniqueId": "cristina_ailerua" },
    "protoVersion": 3
  }
}
```

***

### giftPanelUpdate

**v3 (2026-06-07).** Real-time gift catalog change for the room. Use as a cache-bust signal for local `/webcast/gift_info` copies - no need to re-fetch on every frame.

```json theme={null}
{
  "event": "giftPanelUpdate",
  "data": {
    "type": "giftPanelUpdate",
    "panelId": "7648436315382123281",
    "updatedAtSec": 1780798748,
    "protoVersion": 3
  }
}
```

<Note>
  `updatedAtSec` is epoch **seconds**, not ms.
</Note>

***

### gameServerFeature

**v3 (2026-06-07).** TikTok Gaming live integration descriptor (e.g. "106 Roblox", "2348 Marvel Rivals").

```json theme={null}
{
  "event": "gameServerFeature",
  "data": {
    "type": "gameServerFeature",
    "rawTag": "106Roblox",
    "protoVersion": 3
  }
}
```

***

### anchorToolModification

**v3 (2026-06-07).** Creator modified a panel/widget on their stream (added a video anchor, changed Q\&A topic, etc.).

```json theme={null}
{
  "event": "anchorToolModification",
  "data": {
    "type": "anchorToolModification",
    "toolPayload": "video_anchor 7392706231896379905",
    "protoVersion": 3
  }
}
```

***

### shareRevenueNotice

**v3 (2026-06-07).** Share-revenue subscriber count change notice.

```json theme={null}
{
  "event": "shareRevenueNotice",
  "data": {
    "type": "shareRevenueNotice",
    "creatorUserId": "7648373500877261590",
    "protoVersion": 3
  }
}
```

***

### viewerPicksUpdate

**v3 (2026-06-07).** "Viewer picks" - TikTok-promoted gift highlights shown to viewers as quick picks.

```json theme={null}
{
  "event": "viewerPicksUpdate",
  "data": {
    "type": "viewerPicksUpdate",
    "pickType": 2,
    "payload": "Kiss 5655, Bullet 7934",
    "protoVersion": 3
  }
}
```

***

### fanTicket

**v3 (2026-06-07).** Fan-club ticket flow event.

```json theme={null}
{
  "event": "fanTicket",
  "data": {
    "type": "fanTicket",
    "rawPayload": "mg_default ...",
    "protoVersion": 3
  }
}
```

***

## v3 Tier 4 events

The events below were modeled from a 30-minute capture across 1963 concurrent rooms (752,955 frames). Each carries `protoVersion: 3`.

### giftDynamicRestriction

Dynamic gift-catalog restriction flip (per-room availability / age-gating).

```json theme={null}
{ "event": "giftDynamicRestriction", "data": { "type": "giftDynamicRestriction", "rawPayload": "...", "protoVersion": 3 } }
```

***

### inRoomBanner

In-room activity banner (challenges, donation drives) carrying a JSON descriptor.

```json theme={null}
{ "event": "inRoomBanner", "data": { "type": "inRoomBanner", "activityJson": "{\"activity_indicator\":{\"currents\":[...]}}", "protoVersion": 3 } }
```

***

### battlePunishFinish

PK punishment phase finished. Loser-side punishment screen ended.

```json theme={null}
{
  "event": "battlePunishFinish",
  "data": {
    "type": "battlePunishFinish",
    "battleId": "7648485765504125714",
    "punishedUserId": "7204121790628185094",
    "punishType": 1,
    "sessionId": "7648485804360108818",
    "protoVersion": 3
  }
}
```

***

### battleNotice

PK notice (version-mismatch toasts, invite-failure messages).

```json theme={null}
{ "event": "battleNotice", "data": { "type": "battleNotice", "noticeCode": 6, "noticeKey": "ttlive_liveMatch_inviteFail_versionUpdateTo", "noticeText": "Update your TikTok to the latest version...", "protoVersion": 3 } }
```

***

### hostBoard

Host leaderboard board update.

```json theme={null}
{ "event": "hostBoard", "data": { "type": "hostBoard", "rawPayload": "...", "protoVersion": 3 } }
```

***

### poll

In-stream poll lifecycle (open / vote / close).

```json theme={null}
{
  "event": "poll",
  "data": {
    "type": "poll",
    "pollId": "7648486279037946655",
    "action": 2,
    "status": 2,
    "questionPayload": "LETS FILL UP THE GALLERY",
    "optionsPayload": "HeartMe | Like | Share | repost | Subscribe",
    "protoVersion": 3
  }
}
```

***

### competition

Cross-stream competition event (gift duels, group challenges).

```json theme={null}
{ "event": "competition", "data": { "type": "competition", "competitionType": 8, "layoutSubtype": "cohost_take_stage_v2_2", "protoVersion": 3 } }
```

***

### streamStatus

Stream status flip (recording state, content-classification rechecks).

```json theme={null}
{ "event": "streamStatus", "data": { "type": "streamStatus", "rawPayload": "...", "protoVersion": 3 } }
```

***

### streamEnd

**v3.2 (2026-07-07).** The creator ended or restarted their live. Emitted once, immediately before the socket closes with code **4005 (STREAM\_END)**. Previously a creator ending mid-session closed the socket with a bare **1006** that was indistinguishable from a network error - this event and the 4005 code make it unambiguous.

```json theme={null}
{ "event": "streamEnd", "data": { "type": "streamEnd", "uniqueId": "sdmdq", "reason": "creator_offline", "reconnect": true, "closeCode": 4005 } }
```

| Field       | Type    | Description                                                                                   |
| ----------- | ------- | --------------------------------------------------------------------------------------------- |
| `uniqueId`  | string  | The creator whose stream ended.                                                               |
| `reason`    | string  | Always `"creator_offline"` for now.                                                           |
| `reconnect` | boolean | Always `true` - reconnect to pick up their next live (the server auto-resolves the new room). |
| `closeCode` | number  | The close code that follows this event: `4005`.                                               |

<Note>
  **Always auto-reconnect.** TikTok live connections drop constantly, most of all when a creator restarts a stream. A client with reconnect disabled will appear to "only work 1 in 3-4 times". Treat `1006`/`1005`/`1011` the same as `4005`: the stream is over, reconnect on your next preflight tick. The server resolves the creator's new room automatically.
</Note>

***

### battleGameplay

PK mini-game gameplay state (Whack-A-Mole, Tic-Tac-Toe, etc.).

```json theme={null}
{
  "event": "battleGameplay",
  "data": {
    "type": "battleGameplay",
    "gameplayId": "7648486290535369480",
    "gameplayType": 2,
    "subType": 1,
    "protoVersion": 3
  }
}
```

***

### aiSummary

TikTok AI summary of the room (entry-time recap).

```json theme={null}
{
  "event": "aiSummary",
  "data": {
    "type": "aiSummary",
    "summary": "Casual dance session with spontaneous singing",
    "scenarioKey": "web_enter_room_asr_summary",
    "iconUrl": "https://p16-webcast.tiktokcdn.com/...",
    "labelKey": "ttlive_AIsummary_viewer_label",
    "displayDurationMs": 3000,
    "protoVersion": 3
  }
}
```

***

### giftGallery

Host-side gift wall snapshot.

```json theme={null}
{ "event": "giftGallery", "data": { "type": "giftGallery", "transactionId": "202606070317035805FCD15954308C96D1", "protoVersion": 3 } }
```

***

### cohostLayoutUpdate

Cohost layout subtype change.

```json theme={null}
{ "event": "cohostLayoutUpdate", "data": { "type": "cohostLayoutUpdate", "layoutSubtype": "cohost_normal_expand_4", "protoVersion": 3 } }
```

***

### fansEvent

Fan-club event (tier-up, community heart-me look refresh, etc.).

```json theme={null}
{ "event": "fansEvent", "data": { "type": "fansEvent", "fanType": 7, "eventKey": "ttlive_fanClub_communityHeartMe_tierUp_club", "protoVersion": 3 } }
```

***

### linkScreenChange

PK split-screen layout flip (1v1 / 1vN / cohost mode swap).

```json theme={null}
{ "event": "linkScreenChange", "data": { "type": "linkScreenChange", "changeType": 2, "sessionInfo": "7648433431395453718_16994212205653601499_0", "protoVersion": 3 } }
```

***

### roomSticker

Room-wide sticker drop (host posted a labelled sticker).

```json theme={null}
{ "event": "roomSticker", "data": { "type": "roomSticker", "stickerPayload": "My label - BAYAN NG KONOHA - #000000", "protoVersion": 3 } }
```

***

### bottomMessage

Bottom-bar safety / risk notice (`"LIVE health warning"`, `"risk_notice ..."`).

```json theme={null}
{
  "event": "bottomMessage",
  "data": {
    "type": "bottomMessage",
    "noticeKey": "pm_mt_health_warning",
    "anchorUserId": "6925591924343669765",
    "durationSec": 599,
    "riskKey": "risk_notice7648487247360672544",
    "protoVersion": 3
  }
}
```

***

### oecLiveShopping

OEC live-shopping event (product card display / hide).

```json theme={null}
{ "event": "oecLiveShopping", "data": { "type": "oecLiveShopping", "status": 1, "productInfo": "Make Me Melt Makeup Removing Balm $23.80", "protoVersion": 3 } }
```

***

### rankText

Rank text update (top-viewer announcement template).

```json theme={null}
{ "event": "rankText", "data": { "type": "rankText", "templateKey": "pm_mt_topviewer_comment/{0:user} just became the top viewer", "userId": "7089122432367674373", "protoVersion": 3 } }
```

***

### accessRecall

Access recall (content-classification recheck pulls a gift / chat permission).

```json theme={null}
{
  "event": "accessRecall",
  "data": {
    "type": "accessRecall",
    "status": 1,
    "reason": "CONTENT_CLASSIFICATION",
    "durationSec": 600,
    "suspendKey": "pm_mt_giftAccess_10MinSuspend_toast",
    "protoVersion": 3
  }
}
```

***

### unauthorizedMember

Unauthorized member notice (non-logged-in viewer hit a gated feature).

```json theme={null}
{
  "event": "unauthorizedMember",
  "data": {
    "type": "unauthorizedMember",
    "templateKey": "web_nonlogin_im_1Viewer%s",
    "countLabel": "440680",
    "enterToastKey": "live_room_enter_toast",
    "protoVersion": 3
  }
}
```

***

### guestShowdown

Guest showdown lifecycle (showdown intro / round flip).

```json theme={null}
{ "event": "guestShowdown", "data": { "type": "guestShowdown", "showdownType": 4, "protoVersion": 3 } }
```

***

## v3 Tier 5 events (long tail)

Modeled from `<20`-frame samples across the 10-min + 30-min capture runs. Field shapes carry less confidence than Tier 1-4; future captures may refine semantics. Each carries `protoVersion: 3`.

### hotRoom

TikTok promoted the room to a high-traffic slot. The `hotKey` carries the surface descriptor (e.g. `"revenue_high_traffic"`).

```json theme={null}
{ "event": "hotRoom", "data": { "type": "hotRoom", "hotKey": "revenue_high_traffic", "protoVersion": 3 } }
```

***

### envelopePortal

Red-envelope portal advance (multi-room envelope chain).

```json theme={null}
{ "event": "envelopePortal", "data": { "type": "envelopePortal", "sessionInfo": "...", "status": 2, "kind": 2, "level": 2, "protoVersion": 3 } }
```

***

### groupLiveMemberNotify

Group-live member join / leave notify.

```json theme={null}
{ "event": "groupLiveMemberNotify", "data": { "type": "groupLiveMemberNotify", "userId": "7467181997212075026", "nickname": "Kris", "protoVersion": 3 } }
```

***

### shortTouch

Short-touch UI state change (poll, ecommerce lucky bag, custom UI element).

```json theme={null}
{ "event": "shortTouch", "data": { "type": "shortTouch", "variant": "CustomPoll", "action": "shortTouchCustomPoll", "refId": "7648483782558993174", "protoVersion": 3 } }
```

***

### linkMicAnchorGuide

Anchor (creator) guide nudges (TikTok prompts the host with a tip).

```json theme={null}
{ "event": "linkMicAnchorGuide", "data": { "type": "linkMicAnchorGuide", "guideCode": 7, "rawPayload": "...", "protoVersion": 3 } }
```

***

### gameMoment

PK / mini-game moment window (highlight clip start / end).

```json theme={null}
{ "event": "gameMoment", "data": { "type": "gameMoment", "momentType": 3, "startedAtMs": 1780803292414, "endsAtMs": 1780803297414, "momentMsgId": "7648491877775774737", "protoVersion": 3 } }
```

***

### competitionContributor

Per-contributor breakdown inside a cross-stream competition.

```json theme={null}
{ "event": "competitionContributor", "data": { "type": "competitionContributor", "competitionType": 3, "contributorUserId": "7648483205057776397", "receiverUserId": "7648489576457587469", "protoVersion": 3 } }
```

***

### pictionaryUpdate

Drawing-game (Pictionary) round update.

```json theme={null}
{ "event": "pictionaryUpdate", "data": { "type": "pictionaryUpdate", "status": 2, "pictionaryId": "7648487101176056583", "protoVersion": 3 } }
```

***

### pictionaryEnd

Drawing-game round end with revealed answer.

```json theme={null}
{ "event": "pictionaryEnd", "data": { "type": "pictionaryEnd", "pictionaryId": "7648487101176056583", "answer": "dog", "status": 2, "protoVersion": 3 } }
```

***

### pictionaryExit

Drawing-game exit (early quit).

```json theme={null}
{ "event": "pictionaryExit", "data": { "type": "pictionaryExit", "pictionaryId": "7648483515134167815", "exitReason": 1, "protoVersion": 3 } }
```

***

### oecLiveManager

OEC live-manager event (manager assigned / unassigned).

```json theme={null}
{ "event": "oecLiveManager", "data": { "type": "oecLiveManager", "status": 2, "managerNickname": "Luna Volare", "protoVersion": 3 } }
```

***

### oecLiveBillboard

OEC live billboard slot (product wall snapshot).

```json theme={null}
{ "event": "oecLiveBillboard", "data": { "type": "oecLiveBillboard", "status": 2, "slotCount": 5, "updatedAtMs": 1780802349750, "productPayload": "...", "flagsPayload": ["is_new0", "is_auto_display0"], "protoVersion": 3 } }
```

***

### perception

Perception event (mute cancel etc - TikTok hint signal sent to the room).

```json theme={null}
{ "event": "perception", "data": { "type": "perception", "perceptionCode": 8, "action": "muting_cancel7648486963015877389", "protoVersion": 3 } }
```

***

### questionSelected

Host picked a viewer-submitted question.

```json theme={null}
{ "event": "questionSelected", "data": { "type": "questionSelected", "questionText": "Quel est ton acteur ou ton actrice preferee?", "protoVersion": 3 } }
```

***

### questionSlideDown

Selected-question card slid down (UI dismiss).

```json theme={null}
{ "event": "questionSlideDown", "data": { "type": "questionSlideDown", "questionId": "7648490528341835796", "protoVersion": 3 } }
```

***

### giftUnlock

Gift-unlock reveal (host unlocked a gated gift; viewer hint shown).

```json theme={null}
{ "event": "giftUnlock", "data": { "type": "giftUnlock", "iconUrl": "https://p16-webcast.tiktokcdn.com/...", "tooltipKey": "ttlive_commGift_postReveal_tooltip", "protoVersion": 3 } }
```

***

### ecShortItemRefresh

Short-touch ecommerce item refresh (lucky bag drop refreshed).

```json theme={null}
{ "event": "ecShortItemRefresh", "data": { "type": "ecShortItemRefresh", "refreshToken": "shortTouchEcommerceLuckyBag7648485714367643661", "protoVersion": 3 } }
```

***

### capsule

Capsule overlay (TikTok service-plus pin reminder for high-intention viewers).

```json theme={null}
{
  "event": "capsule",
  "data": {
    "type": "capsule",
    "imageUrl": "https://...",
    "titleKey": "ttlive_servicePlus_live_modPinCapsule",
    "btnKey": "ttlive_servicePlus_live_modPinCapsule_btnPin",
    "deepLink": "sslocal://webcast_subscribe/allinone?sec_anchor_id=...",
    "reminderKey": "high_intention_comment_pincard_reminder",
    "displayDurationSec": 90,
    "protoVersion": 3
  }
}
```

***

### roomVerify

Room age / content-classification verification event.

```json theme={null}
{ "event": "roomVerify", "data": { "type": "roomVerify", "verifyCode": 3, "protoVersion": 3 } }
```

***

### smbBoard

SMB (small/medium-business) board overlay - a styled sponsor/business panel rendered on the LIVE. Rare (\~1/hr, host-triggered). The payload is a UI panel definition (3D text styling, colors, layout), not a data leaderboard.

```json theme={null}
{ "event": "smbBoard", "data": { "type": "smbBoard", "boardId": "7657756442560531213", "status": 1, "protoVersion": 3 } }
```

| Field          | Type   | Description             |
| -------------- | ------ | ----------------------- |
| `boardId`      | string | Board component id.     |
| `status`       | number | Board status/type flag. |
| `protoVersion` | number | Always 3.               |

***

### follow

A viewer follows the streamer.

```json theme={null}
{
  "event": "follow",
  "data": {
    "type": "follow",
    "user": { "uniqueId": "new_follower", "nickname": "New Follower" }
  }
}
```

***

### share

A viewer shares the live stream.

```json theme={null}
{
  "event": "share",
  "data": {
    "type": "share",
    "user": { "uniqueId": "sharer", "nickname": "Share User" }
  }
}
```

***

### roomUserSeq

Periodic viewer count update.

```json theme={null}
{
  "event": "roomUserSeq",
  "data": {
    "type": "roomUserSeq",
    "viewerCount": 1234,
    "topViewers": [
      { "user": { "uniqueId": "top1" }, "coinCount": 500 }
    ]
  }
}
```

| Field         | Type   | Description                  |
| ------------- | ------ | ---------------------------- |
| `viewerCount` | number | Current viewer count         |
| `topViewers`  | array  | Top gifters with coin counts |

***

### subscribe

A viewer subscribes to the streamer.

```json theme={null}
{
  "event": "subscribe",
  "data": {
    "type": "subscribe",
    "user": { "uniqueId": "subscriber", "nickname": "Subscriber" }
  }
}
```

***

### battle

PK lifecycle - fires when a battle (Link Mic PK) starts, changes status, or ends.

```json theme={null}
{
  "event": "battle",
  "data": {
    "type": "battle",
    "battleId": "7298765432109876543",
    "status": 1,
    "battleDuration": 300,
    "teams": [],
    "scores": []
  }
}
```

| Field              | Type                 | Description                                                                                                                           |
| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `battleId`         | string               | Unique battle ID                                                                                                                      |
| `status`           | number               | 1 = ACTIVE, 2 = STARTING, 3 = ENDED, 4 = PREPARING                                                                                    |
| `battleDuration`   | number               | Total battle duration in seconds (typically 300)                                                                                      |
| `extraHostUserIds` | string\[]\|undefined | **v3 (2026-06-07)**: additional host user IDs surfaced on multi-guest battles (host pairs beyond the primary two).                    |
| `layoutSubtype`    | string\|undefined    | **v3 (2026-06-07)**: TikTok layout subtype (`"cohost_normal_expand_2"`, ...) - overlays use this to pick the right PK frame template. |
| `protoVersion`     | number\|undefined    | **v3 (2026-06-07)**: 3 when v3-only fields are present, otherwise 2.                                                                  |

***

### battleArmies

Periodic score update during a PK with **per-host MVP breakdown**.

```json theme={null}
{
  "event": "battleArmies",
  "data": {
    "type": "battleArmies",
    "battleId": "7298765432109876543",
    "status": 1,
    "matchId": "...",
    "sessionId": "...",
    "serverTsMs": 1747654321000,
    "durationSec": 300,
    "secsRemaining": 187,
    "hosts": [
      {
        "hostUserId": "6892636847263982593",
        "teamTotalScore": 12450,
        "teamIdx": 0,
        "contributors": [
          { "userId": "111", "score": 8000, "nickname": "MVP_Gifter" },
          { "userId": "222", "score": 3000, "nickname": "OtherFan" },
          { "userId": "333", "score": 1450, "nickname": "ThirdFan" }
        ]
      },
      {
        "hostUserId": "7012345678901234567",
        "teamTotalScore": 9800,
        "teamIdx": 1,
        "contributors": []
      }
    ],
    "transactionId": "202607072219033A38D7B466DD66036089",
    "lastGift": {
      "gifterUserId": "6781226035679396870",
      "giftId": 5655,
      "count": 1,
      "diamondCount": 1,
      "repeatCount": 4,
      "giftPictureUrl": "https://p16-webcast.tiktokcdn.com/img/maliva/webcast-va/..."
    },
    "battleGame": { "name": "ICE_SHOWDOWN", "id": "6551516166106447873" }
  }
}
```

<Note>
  `transactionId` is a **top-level** field on the `battleArmies` frame (a sibling of `lastGift`), not a field inside `lastGift`. Dedup a combo on the pair (`transactionId`, `lastGift.repeatCount`).
</Note>

| Field                     | Type              | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `battleId`                | string            | Battle session tag                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `matchId`                 | string            | Stable match ID across multi-round PK                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `sessionId`               | string            | Per-round session ID                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `serverTsMs`              | number            | TikTok server clock (ms epoch) at frame emit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `durationSec`             | number            | Total battle duration in seconds                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `secsRemaining`           | number            | Seconds remaining, computed from `serverTsMs` (no clock drift)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `hosts[]`                 | array             | One entry per PK-side host. Multi-guest PKs include up to 4 per side                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `hosts[].hostUserId`      | string            | Host's TikTok userId                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `hosts[].teamTotalScore`  | number            | Total diamonds for this host's team                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `hosts[].teamIdx`         | number            | Side index (0 = left, 1 = right)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `hosts[].contributors[]`  | array             | Per-gifter breakdown, **sorted MVP first**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `contributors[].userId`   | string            | Gifter's TikTok userId                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `contributors[].score`    | number            | Diamonds contributed                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `contributors[].nickname` | string            | Gifter's display name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `transactionId`           | string\|undefined | **v3 (2026-06-07)**: stable per-frame transaction UUID (hex). Use as a dedup key to avoid double-counting score updates when upstream retries a frame.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `lastGift`                | object\|undefined | **v3.2 (2026-07-07)**: the gift that triggered this score update, embedded inline: `{ gifterUserId, giftId, count, diamondCount, repeatCount, giftPictureUrl }`. The score frame is broadcast to BOTH PK rooms, so this itemizes cross-room and out-of-room gifts from a single connection - the same purpose as `linkMicOpponentGift`, on the frame that also carries the resulting score delta. Present ONLY on frames with an actual priced gift (absent on plain score ticks). `diamondCount` is the per-unit value and matches the gift catalog. Dedup a combo on the pair (`transactionId`, `lastGift.repeatCount`) - `transactionId` is the top-level `battleArmies` field (a sibling of `lastGift`), **not** a field inside the `lastGift` object. |
| `battleGame`              | object\|undefined | **v3.2 (2026-07-07)**: mini-game context `{ name, id }` for game-mode PKs (e.g. name `"ICE_SHOWDOWN"`). Absent on plain PKs.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `protoVersion`            | number\|undefined | **v3 (2026-06-07)**: 3 when `transactionId` is present, otherwise 2.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |

<Note>
  `hosts[0].contributors[0]` is always the **MVP** (highest gifter on that side).
</Note>

<Note>
  **Battle gift itemization (2026-07-07):** TikTok is phasing out the standalone `linkMicOpponentGift` event for many rooms and instead embeds the triggering gift here as `lastGift`. Consume both: prefer `battleArmies.lastGift` when present, fall back to `linkMicOpponentGift`.
</Note>

***

### battleItemCard

Booster / power-up card activated during a PK: x2/x3 multipliers, gloves (crit),
mist, thunder, extra-time, match-guide. Includes drop-in overlay assets straight
from TikTok's CDN.

```json theme={null}
{
  "event": "battleItemCard",
  "data": {
    "type": "battleItemCard",
    "battleId": "7298765432109876543",
    "cardType": 11,
    "effect": "booster_x3",
    "effectKey": "ttlive_match_announcement_userSentBooster_no3",
    "multiplier": 3,
    "senderUserId": "111",
    "senderNickname": "Big_Spender",
    "senderUniqueId": "big_spender",
    "senderAvatarUrl": "https://p16-sign.tiktokcdn-us.com/...",
    "activatedAtSec": 1747654321,
    "durationSec": 30,
    "endsAtSec": 1747654351,
    "commentTemplate": "{0:user} sent x3 booster",
    "iconUrl": "https://p19.tiktokcdn-us.com/...card_crit_v3.webp",
    "iconKey": "card_crit_v3",
    "accentColor": "#E0D4BC"
  }
}
```

| Field             | Type   | Description                                                                                                 |
| ----------------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| `battleId`        | string | The PK this card belongs to                                                                                 |
| `cardType`        | number | 2 = gloves/crit, 3 = mist, 4 = match\_guide, 10 = x2?, 11 = x3, ...                                         |
| `effect`          | string | `gloves` \| `mist` \| `booster_x2` \| `booster_x3` \| `match_guide` \| `thunder` \| `extra_time` \| raw key |
| `effectKey`       | string | Raw TikTok resource key                                                                                     |
| `multiplier`      | number | 2 or 3 for boosters, else 0                                                                                 |
| `senderUserId`    | string | Gifter who activated the card                                                                               |
| `senderNickname`  | string | Display name of the sender                                                                                  |
| `senderUniqueId`  | string | Username (`@handle`) of the sender                                                                          |
| `senderAvatarUrl` | string | Sender's avatar (TikTok CDN URL)                                                                            |
| `activatedAtSec`  | number | Unix seconds when activated                                                                                 |
| `durationSec`     | number | Active duration in seconds                                                                                  |
| `endsAtSec`       | number | Unix seconds when buff ends                                                                                 |
| `commentTemplate` | string | Display string, e.g. `"{0:user} sent 1 magic mist"`                                                         |
| `iconUrl`         | string | Full TikTok CDN URL for the card art (webp/jpeg)                                                            |
| `iconKey`         | string | Short id, e.g. `card_mist_v3`, `card_crit_v3`, `top3_buffer`                                                |
| `accentColor`     | string | Hex color, e.g. `#BCD9E0` (mist blue), `#E0D4BC` (gloves tan)                                               |

***

### roomPin

A message is pinned in the live room.

```json theme={null}
{
  "event": "roomPin",
  "data": {
    "type": "roomPin",
    "pinnedMessage": "Welcome to the stream!",
    "user": { "uniqueId": "streamer" }
  }
}
```

***

### emote

An animated emote is sent.

```json theme={null}
{
  "event": "emote",
  "data": {
    "type": "emote",
    "emoteId": "7012345",
    "emoteUrl": "https://...",
    "user": { "uniqueId": "emoter" }
  }
}
```

***

### envelope

A treasure box / envelope event.

```json theme={null}
{
  "event": "envelope",
  "data": {
    "type": "envelope",
    "coins": 100,
    "canOpen": 5,
    "timestamp": 1234567890
  }
}
```

***

### questionNew

A Q\&A question is submitted.

```json theme={null}
{
  "event": "questionNew",
  "data": {
    "type": "questionNew",
    "questionText": "When did you start streaming?",
    "user": { "uniqueId": "curious_viewer" }
  }
}
```

***

### roomInfo

Initial room metadata sent immediately after connecting.

```json theme={null}
{
  "event": "roomInfo",
  "roomId": "71234567890",
  "uniqueId": "streamer",
  "roomInfo": {
    "title": "Stream Title",
    "user_count": 1234,
    "like_count": 5678,
    "owner": { "nickname": "Streamer Name", "uniqueId": "streamer" }
  }
}
```

***

## User Object

Most events include a `user` object with this structure:

```json theme={null}
{
  "uniqueId": "username",
  "nickname": "Display Name",
  "userId": "6892636847263982593",
  "profilePictureUrl": "https://...",
  "followRole": 0,
  "userBadges": [],
  "isModerator": false,
  "isSubscriber": false,
  "isNewGifter": false,
  "topGifterRank": null,
  "payGrade": 12
}
```

| Field               | Type              | Description                                                                                                                                                                                |
| ------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `uniqueId`          | string            | TikTok username                                                                                                                                                                            |
| `nickname`          | string            | Display name                                                                                                                                                                               |
| `userId`            | string            | Numeric user ID                                                                                                                                                                            |
| `profilePictureUrl` | string            | Avatar URL                                                                                                                                                                                 |
| `followRole`        | number            | 0 = not following, 1 = following, 2 = friend                                                                                                                                               |
| `isModerator`       | boolean           | Whether user is a room moderator                                                                                                                                                           |
| `isSubscriber`      | boolean           | Whether user is a subscriber                                                                                                                                                               |
| `topGifterRank`     | number\|null      | Rank in top gifter leaderboard                                                                                                                                                             |
| `payGrade`          | number\|undefined | TikTok donator level (1 to 50). Present on every user-bearing event when the user has gifted at least once on TikTok. Absent when they have never gifted. Alias of the wire field `level`. |

***

## Schema Versions

Many event payloads carry an optional `protoVersion` field. It is the schema revision the relay parser decoded the event against, allowing v1 and v2 clients to coexist with v3 producers.

| Version | First seen      | What it means                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `1`     | initial release | Original parser shape. Kept for legacy clients pinned to v1 typings.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `2`     | 2026-05-19      | Multi-host PK breakdown on `battleArmies` (`hosts[].contributors[]`), `payGrade` surfacing on every user-bearing event, `matchId` / `sessionId` / `secsRemaining` on PK frames.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `3`     | 2026-06-07      | TikTok native captions on the WS (new `caption` event), per-chat `language` + `messageUuid`, per-gift `transactionId` + `senderUserId` + `relationship`, member `entrySource` / `entryAction` / `entryType` (creator-analytics signals), 54 brand-new event types across Tier 1 / Tier 2 / Tier 3 / Tier 4 / Tier 5 rollouts (`linkMicOpponentGift`, `imDelete`, `goalUpdate`, `privilegeAdvance`, `commentTray`, `linkLayer`, `link`, `giftPanelUpdate`, `gameServerFeature`, `anchorToolModification`, `shareRevenueNotice`, `viewerPicksUpdate`, `fanTicket`, `giftDynamicRestriction`, `inRoomBanner`, `battlePunishFinish`, `battleNotice`, `hostBoard`, `poll`, `competition`, `streamStatus`, `battleGameplay`, `aiSummary`, `giftGallery`, `cohostLayoutUpdate`, `fansEvent`, `linkScreenChange`, `roomSticker`, `bottomMessage`, `oecLiveShopping`, `rankText`, `accessRecall`, `unauthorizedMember`, `guestShowdown`, `hotRoom`, `envelopePortal`, `groupLiveMemberNotify`, `shortTouch`, `linkMicAnchorGuide`, `gameMoment`, `competitionContributor`, `pictionaryUpdate`, `pictionaryEnd`, `pictionaryExit`, `oecLiveManager`, `oecLiveBillboard`, `perception`, `questionSelected`, `questionSlideDown`, `giftUnlock`, `ecShortItemRefresh`, `capsule`, `roomVerify`, `smbBoard`), battle `extraHostUserIds` + `layoutSubtype`, battleArmies `transactionId` dedup. |

`protoVersion` is **only** emitted on events that actually carry v3-additive fields - if a chat message has no language tag and no UUID, `protoVersion` is `2`. Clients written against the v1 or v2 schema can keep ignoring the field; clients that want the new data can read `if (evt.protoVersion === 3) { ... }` without any feature-detection.

The full v3 discovery spec was built from a 10-minute capture across 1739 concurrent TikTok LIVE rooms (304,325 frames decoded across 67 distinct method names) and a follow-on 30-minute capture across 1963 rooms (752,955 frames). Every event documented above ships as of the v3 rollout. Long-tail rare methods observed only a handful of times across both runs (single-digit frame counts) are tracked internally and will land in point releases as sample diversity allows safe field modelling.
