Search documentation

Search pages and headings

Message Model

Message Schema

Every field on a normalized message, including which are always present and which only appear sometimes.

Every chat event — a plain message, a Super Chat, a membership, a deletion — arrives in the same flat shape. Fields that do not apply are present but empty rather than missing, so you never have to branch just to read a value.

Message

Field Type Always present Description
type string yes Which kind of event this is — see Message Types
id string yes YouTube's message id. "" for events that carry none, such as deletions
timestamp string yes Display timestamp as YouTube renders it, e.g. "1:23 PM" or "1:02:03". Not a parseable date
author string yes Display name, falling back to the channel id. "" when there is no author
message string yes Flattened plain-text body. Emoji become their shortcut, e.g. :yt:
amount string yes Formatted purchase amount for paid events, e.g. "$5.00". "" otherwise
color string yes Background colour as #rrggbb for paid events. "" otherwise
parts Part[] yes Structured body — render chat UI from this, not from message
iconType string no Present on engagement events, e.g. YOUTUBE_ROUND
isMember boolean no Present and true only when the author is a member
isModerator boolean no Present and true only when the author is a moderator
isOwner boolean no Present and true only when the author owns the channel
memberBadge MemberBadge no Present only when the author has a custom member badge
authorPhoto Thumbnail[] no Present only when the author has an avatar

The optional fields are omitted entirely rather than set to false or null. Test with message.isMember === true, or just truthiness — never 'isMember' in message ? ... : ... expecting a false value to exist.

Part

A discriminated union on kind. See Rendering Message Bodies for how to draw it.

Text part

Field Type Description
kind "text" Discriminant
text string A literal run of text

Emoji part

Field Type Description
kind "emoji" Discriminant
shortcut string The :shortcut: form, e.g. ":yt:"
emoji_id string YouTube's emoji id. Sometimes a raw emoji character
is_custom boolean true for channel-specific emoji that must be drawn as an image
mapped_unicode string A unicode equivalent when one is known, otherwise ""
thumbnails Thumbnail[] Image sources, ascending by size

Thumbnail

Field Type Description
url string Image URL
width number Width in pixels, 0 when YouTube omitted it
height number Height in pixels, 0 when YouTube omitted it

Arrays are ordered smallest to largest, so the last entry is the highest resolution.

MemberBadge

Field Type Description
tooltip string Badge tooltip, e.g. "Member (6 months)"
thumbnails Thumbnail[] Badge images, ascending by size

Types in TypeScript

The schemas are published by the client package and are the same ones the server validates against, so there is one definition rather than two:

import type {
  MessageSchema,
  PartSchema,
  ThumbnailSchema,
  MemberBadgeSchema,
} from '@gettersethya/yt-livechat-client'

function onMessage(message: MessageSchema) {
  if (message.isOwner === true) highlight(message)
}

These are effect schemas: each export is both a runtime validator and a type of the same name.

import { Schema } from 'effect'
import { MessageSchema } from '@gettersethya/yt-livechat-client'

const message = Schema.decodeUnknownSync(MessageSchema)(payload)