100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Web Development

Text and Binary Frames

How WebSocket messages are broken into frames, and the difference between UTF-8 text frames and raw binary frames.

The ProtocolIntermediate9 min readJul 10, 2026
Analogies

Frames vs. Messages

A WebSocket message is a logical unit of data an application sends, but on the wire it is split into one or more frames. Each frame has a small header describing an opcode, whether it is the final fragment (the FIN bit), a masking flag, and a payload length, followed by the payload itself. A single short chat message might fit in one frame with FIN set to 1, while a large file transfer can be split across many frames, with the first frame carrying the real opcode (0x1 for text or 0x2 for binary) and subsequent continuation frames using opcode 0x0 until the final one sets FIN to 1.

🏏

Cricket analogy: It's like a partnership between two batters being described as a single stand of runs, even though it's actually built delivery by delivery, each ball its own discrete event, with the final wicket or declaration marking the stand as complete.

Text Frames and UTF-8 Validation

Opcode 0x1 marks a text frame, and the payload must be valid UTF-8 — this is not optional. If an endpoint receives a text frame (or a fragmented text message once reassembled) that isn't valid UTF-8, it is required by the specification to fail the connection, typically closing with code 1007 (invalid payload data). This strictness exists because text frames are meant for human-readable and JSON-style application data where character encoding correctness matters, so implementations like browsers' WebSocket API expose text frame payloads directly as JavaScript strings without giving the developer a chance to inspect raw bytes first.

🏏

Cricket analogy: It's like the DRS ball-tracking system rejecting any review where the tracking data is incomplete or corrupted rather than guessing — an invalid input simply cannot be processed as a valid decision.

javascript
const socket = new WebSocket('wss://example.com/stream');
socket.binaryType = 'arraybuffer';

socket.addEventListener('message', (event) => {
  if (typeof event.data === 'string') {
    // Text frame: opcode 0x1, guaranteed valid UTF-8
    const payload = JSON.parse(event.data);
    console.log('Text message:', payload);
  } else {
    // Binary frame: opcode 0x2, delivered as ArrayBuffer
    const view = new DataView(event.data);
    const messageType = view.getUint8(0);
    console.log('Binary message, type byte:', messageType);
  }
});

// Sending a binary frame
const buffer = new Uint8Array([0x01, 0xff, 0x10, 0x22]);
socket.send(buffer.buffer);

Choosing Binary Frames

Opcode 0x2 marks a binary frame, whose payload is an opaque byte sequence with no encoding constraints — it can carry Protocol Buffers, MessagePack, compressed audio chunks, or any custom byte layout the application defines. Binary frames are the right choice whenever payload size matters, since encodings like Protobuf or MessagePack are typically far more compact than an equivalent JSON string, and whenever the data is inherently binary already, like image tiles or audio samples, where converting to base64 text would inflate the payload by roughly a third and add unnecessary encode/decode overhead on both ends.

🏏

Cricket analogy: It's like a broadcaster sending the raw high-definition camera feed to the production truck rather than a written play-by-play description — the raw feed is bulkier per second but preserves everything without the lossy overhead of converting motion into text.

The extension permessage-deflate can compress both text and binary frame payloads transparently at the protocol layer, negotiated during the handshake via the Sec-WebSocket-Extensions header — useful for repetitive JSON text frames, though it adds CPU overhead and is sometimes disabled for already-compressed binary payloads like images or video.

  • A WebSocket message can be split across multiple frames; the FIN bit marks the final frame of a message.
  • Opcode 0x1 marks a text frame; opcode 0x2 marks a binary frame; opcode 0x0 marks a continuation frame.
  • Text frame payloads must be valid UTF-8, or the connection must be failed with close code 1007.
  • Binary frames carry opaque bytes with no encoding requirement, ideal for Protobuf, MessagePack, images, or audio.
  • Browsers expose text frames as JavaScript strings and binary frames as Blob or ArrayBuffer depending on binaryType.
  • Binary encodings are typically more compact than JSON text, avoiding base64 inflation for inherently binary data.
  • permessage-deflate can compress frame payloads at the protocol level when negotiated during the handshake.

Practice what you learned

Was this page helpful?

Topics covered

#WebDevelopment#WebSocketsStudyNotes#TextAndBinaryFrames#Text#Binary#Frames#Messages#StudyNotes#SkillVeris#ExamPrep