---
title: WebSockets
description: Communicate in real time with your Cloudflare Workers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt  
> Use this file to discover all available pages before exploring further.

[Skip to content](#%5Ftop) 

# WebSockets

## Background

WebSockets allow you to communicate in real time with your Cloudflare Workers serverless functions. For a complete example, refer to [Using the WebSockets API](https://developers.cloudflare.com/workers/examples/websockets/).

Note

If your application needs to coordinate among multiple WebSocket connections, such as a chat room or game match, you will need clients to send messages to a single-point-of-coordination. Durable Objects provide a single-point-of-coordination for Cloudflare Workers, and are often used in parallel with WebSockets to persist state over multiple clients and connections. In this case, refer to [Durable Objects](https://developers.cloudflare.com/durable-objects/) to get started, and prefer using the Durable Objects' extended [WebSockets API](https://developers.cloudflare.com/durable-objects/best-practices/websockets/).

## Constructor

JavaScript

```

// { 0: <WebSocket>, 1: <WebSocket> }

let websocketPair = new WebSocketPair();


```

The WebSocketPair returned from this constructor is an Object, with two WebSockets at keys `0` and `1`.

These WebSockets are commonly referred to as `client` and `server`. The below example combines `Object.values` and ES6 destructuring to retrieve the WebSockets as `client` and `server`:

JavaScript

```

let [client, server] = Object.values(new WebSocketPair());


```

## Methods

### accept

* `accept(options?)`  
   * Accepts the WebSocket connection and begins terminating requests for the WebSocket on Cloudflare's global network. This effectively enables the Workers runtime to begin responding to and handling WebSocket requests.

#### Parameters

* `options` object optional  
   * An optional configuration object with the following properties:  
         * `allowHalfOpen` boolean optional — When `true`, the runtime will not automatically send a reciprocal Close frame when a Close frame is received from the peer. Instead, `readyState` remains `CLOSING` until you explicitly call `close()`. This is useful for [WebSocket proxying](#close-behavior) where you need to coordinate the close across both sides of the proxy. Defaults to `false`.

### addEventListener

* `addEventListener(eventWebSocketEvent, callbackFunctionFunction)`  
   * Add callback functions to be executed when an event has occurred on the WebSocket.

#### Parameters

* `event` WebSocketEvent  
   * The WebSocket event (refer to [Events](https://developers.cloudflare.com/workers/runtime-apis/websockets/#events)) to listen to.
* `callbackFunction(messageMessage)` Function  
   * A function to be called when the WebSocket responds to a specific event.

### close

* `close(codenumber, reasonstring)`  
   * Close the WebSocket connection.

#### Parameters

* `codeinteger` optional  
   * An integer indicating the close code sent by the server. This should match an option from the [list of status codes ↗](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#status%5Fcodes) provided by the WebSocket spec.
* `reasonstring` optional  
   * A human-readable string indicating why the WebSocket connection was closed.

### send

* `send(messagestring | ArrayBuffer | ArrayBufferView)`  
   * Send a message to the other WebSocket in this WebSocket pair.

#### Parameters

* `messagestring`  
   * The message to send down the WebSocket connection to the corresponding client. This should be a string or something coercible into a string; for example, strings and numbers will be simply cast into strings, but objects and arrays should be cast to JSON strings using `JSON.stringify`, and parsed in the client.

---

## Properties

### readyState

* `readyState` number  
   * Returns the current state of the WebSocket connection. Possible values:  
   | Constant             | Value | Description                                      |  
   | -------------------- | ----- | ------------------------------------------------ |  
   | WebSocket.CONNECTING | 0     | The connection is not yet open.                  |  
   | WebSocket.OPEN       | 1     | The connection is open and ready to communicate. |  
   | WebSocket.CLOSING    | 2     | The connection is in the process of closing.     |  
   | WebSocket.CLOSED     | 3     | The connection is closed.                        |

### binaryType

* `binaryType` string  
   * Controls how binary frames received on this WebSocket are surfaced to the `message` event. Valid values are `"blob"` and `"arraybuffer"`. The value is consulted when each incoming binary frame is dispatched, so assigning a new value affects subsequent messages only. The default is controlled by the [websocket\_standard\_binary\_type](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#websocket-standard-binary-type) compatibility flag. Refer to [Binary messages](#binary-messages) for details.

---

## Events

* `close`  
   * An event indicating the WebSocket has closed. The `CloseEvent` includes `code` (number), `reason` (string), and `wasClean` (boolean) properties.
* `error`  
   * An event indicating there was an error with the WebSocket.
* `message`  
   * An event indicating a new message received from the client, including the data passed by the client.

Note

WebSocket messages received by a Worker have a size limit of 32 MiB (33,554,432 bytes). If a larger message is sent, the WebSocket will be automatically closed with a `1009` "Message is too large" response.

## Types

### Message

* `data` any - The data passed back from the other WebSocket in your pair.
* `type` string - Defaults to `message`.

---

## Close behavior

With the [web\_socket\_auto\_reply\_to\_close](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#websocket-auto-reply-to-close) compatibility flag (enabled by default on compatibility dates on or after `2026-04-07`), the Workers runtime automatically sends a reciprocal Close frame when it receives a Close frame from the peer. The `readyState` transitions to `CLOSED` before the `close` event fires. This matches the [WebSocket specification ↗](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close%5Fevent) and standard browser behavior.

If you still call `close()` inside the `close` event handler, the call is silently ignored. Existing code that manually replies to Close frames will continue to work without changes.

JavaScript

```

server.addEventListener("close", (event) => {

  // readyState is already CLOSED — no need to call server.close().

  console.log(server.readyState); // WebSocket.CLOSED

  console.log(event.code);        // 1000

  console.log(event.wasClean);    // true

});


```

### Half-open mode for proxying

The automatic close behavior can interfere with WebSocket proxying, where a Worker sits between a client and a backend and needs to coordinate the close on both sides independently. To support this, pass `{ allowHalfOpen: true }` to `accept()`:

JavaScript

```

server.accept({ allowHalfOpen: true });


server.addEventListener("close", (event) => {

  // readyState is still CLOSING here, giving you time

  // to coordinate the close on the other side.

  console.log(server.readyState); // WebSocket.CLOSING


  // Manually close when ready.

  server.close(event.code, "done");

});


```

Note

WebSockets created with `new WebSocket(url)` always auto-reply to Close frames after this flag takes effect. There is no way to pass `allowHalfOpen` because these WebSockets are automatically accepted. If you need half-open behavior for a client WebSocket, use `fetch()` with the `Upgrade: websocket` header instead, then call `resp.webSocket.accept({ allowHalfOpen: true })`.

### Prior behavior

On compatibility dates before `2026-04-07` (or with the `web_socket_manual_reply_to_close` flag), receiving a Close frame leaves the WebSocket in `CLOSING` state, and your code must call `close()` to complete the handshake. Failing to do so can result in `1006` abnormal closure errors on the client.

---

## Binary messages

WebSocket frames carry either text or binary payloads, and the choice between the two is made by the sender at the time the frame is sent. Text frames are always delivered to the `message` event as JavaScript strings. Binary frames are delivered either as [Blob ↗](https://developer.mozilla.org/en-US/docs/Web/API/Blob) or as [ArrayBuffer ↗](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global%5FObjects/ArrayBuffer), depending on the WebSocket's `binaryType`.

With the [websocket\_standard\_binary\_type](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#websocket-standard-binary-type) compatibility flag (enabled by default on compatibility dates on or after `2026-03-17`), `binaryType` defaults to `"blob"` and binary frames are delivered as `Blob` objects. This matches the [WebSocket specification ↗](https://websockets.spec.whatwg.org/) and standard browser behavior. Without the flag, `binaryType` defaults to `"arraybuffer"` and binary frames are delivered as `ArrayBuffer`, matching the runtime's historical behavior.

The `binaryType` property itself is always available. To opt back into `ArrayBuffer` delivery for a single WebSocket, assign `binaryType` before calling `accept()`:

JavaScript

```

const resp = await fetch("https://example.com", {

  headers: { Upgrade: "websocket" },

});

const ws = resp.webSocket;


// Opt back into ArrayBuffer delivery for this WebSocket.

ws.binaryType = "arraybuffer";

ws.accept();


ws.addEventListener("message", (event) => {

  if (typeof event.data === "string") {

    // Text frame.

  } else {

    // event.data is an ArrayBuffer because we set binaryType above.

  }

});


```

### Reading binary payloads

An incoming binary frame is fully buffered before the `message` event fires, regardless of `binaryType`. The choice between `Blob` and `ArrayBuffer` does not change when or whether the frame is received — only how you access its bytes:

* With `"arraybuffer"`, `event.data` is an [ArrayBuffer ↗](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global%5FObjects/ArrayBuffer). You can inspect its size and read bytes synchronously (for example, `new Uint8Array(event.data)`).
* With `"blob"`, `event.data` is a [Blob ↗](https://developer.mozilla.org/en-US/docs/Web/API/Blob). Reading the bytes is asynchronous — for example, `await event.data.arrayBuffer()` or `await event.data.bytes()`.

Under the new default, a binary message handler must be `async` in order to read the payload. If you want to keep an existing synchronous handler, set `binaryType` to `"arraybuffer"` on the WebSocket.

### When the value takes effect

Per the [WebSocket specification ↗](https://websockets.spec.whatwg.org/#feedback-from-the-protocol), `binaryType` is mutable: the value is consulted at the moment each binary frame is dispatched to the `message` event, so assigning a new value affects only subsequent messages. If you want every binary message on a WebSocket to be delivered as the same type, assign `binaryType` before calling `accept()`. That guarantees the setting is in place before the runtime starts dispatching any incoming frames.

### Worker-wide opt-out

If you are not ready to migrate and want to keep `ArrayBuffer` as the default for every WebSocket in your Worker, add the `no_websocket_standard_binary_type` flag to your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/). Individual WebSockets can still override the default by assigning `binaryType`.

Note

This flag has no effect on the Durable Object hibernatable WebSocket [webSocketMessage](https://developers.cloudflare.com/durable-objects/best-practices/websockets/) handler. That handler always receives binary data as `ArrayBuffer`, since it operates outside the normal WebSocket read loop.

---

## Related resources

* [Mozilla Developer Network's (MDN) documentation on the WebSocket class ↗](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
* [Our WebSocket template for building applications on Workers using WebSockets ↗](https://github.com/cloudflare/websocket-template)

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/workers/","name":"Workers"}},{"@type":"ListItem","position":3,"item":{"@id":"/workers/runtime-apis/","name":"Runtime APIs"}},{"@type":"ListItem","position":4,"item":{"@id":"/workers/runtime-apis/websockets/","name":"WebSockets"}}]}
```
