Skip to main content
The WireSocket dataplane is a globally distributed set of WebSocket nodes. This page covers how to connect your editor, handle regions, and manage token renewal and reconnection.

Regions

WireSocket has two region concepts you need to understand: License Region — Set during app creation. Defines where your app’s license and plan data is stored. This is the dbCode claim in your JWT. These regions always have an aws- prefix.
CodeLocation
aws-ap-northeast-1Asia Pacific (Tokyo)
aws-ap-south-1Asia Pacific (Mumbai)
aws-eu-west-1Europe (Ireland)
aws-us-east-1US East (N. Virginia)
aws-us-east-2US East (Ohio)
aws-us-west-2US West (Oregon)
WebSocket Regions — The standard cloud regions where your editors connect for real-time sync. Each region maps to a specific Sync Cluster and has its own URL:
wss://{region-name}-{cluster-id}.wiresocket.net
Example: eu-central-1 (Region: Europe Central, Cluster: 1). Currently available WebSocket regions and their URLs are listed in your dashboard.
License Region (dbCode) and WebSocket region (regionCode) are independent. Your license can be stored in EU while your editors connect to a US node.

Document Discovery

WireSocket supports two strategies for connecting to the correct regional node for your document:
StrategyHowBest For
Discovery firstCall /discovery, then connect to returned URLLowest latency, zero wrong-region attempts
Connect and catchConnect directly, handle 4009 REDIRECT on errorFewer HTTP requests, simpler client code
Both are fully supported. Use Discovery if first-connect latency matters. Use connect-and-catch if you want to avoid the extra HTTP round trip.

Discovery First

GET https://{region-code}.wiresocket.net/discovery?documentName=your-document-id
Authorization: Bearer YOUR_ACCESS_TOKEN
Response:
{
  "region": "eu-central-1",
  "url": "wss://eu-central-1.wiresocket.net/your-document-id",
  "isNew": false
}
FieldDescription
regionThe node region currently hosting this document
urlThe full WebSocket URL including the doc ID. Include this as your provider’s URL.
isNewtrue if no active session exists — connect to your preferred region
async function resolveAndConnect(docId, getAccessToken) {
  const token = await getAccessToken();

  // Step 1: Discover the correct node
  // You can call any regional node to perform the lookup
  const res = await fetch(
    `https://eu-central-1.wiresocket.net/discovery?documentName=${docId}`,
    { headers: { Authorization: `Bearer ${token}` } },
  );

  if (!res.ok) {
    // 401 = invalid token, 400 = bad request — stop and check config
    throw new Error(`Discovery failed: ${res.status}`);
  }

  const { url, isNew } = await res.json();

  // Step 2: Resolve the node URL
  // If isNew, no session exists yet — connect to your preferred region
  const nodeUrl = url ?? "wss://eu-central-1.wiresocket.net";

  // Step 3: Connect
  const provider = new WebsocketProvider(nodeUrl, docId, ydoc, {
    protocols: ["access_token", token],
  });

  return provider;
}
A 401 or 400 response means a configuration problem — invalid token or missing documentName. Do not retry automatically. Surface the error to the developer.

Connect and Catch

If you prefer to skip the HTTP round trip entirely, connect directly to any regional node. If the region is wrong, WireSocket closes the connection with a 4009 code and the correct URL in the close reason — your client catches this and reconnects transparently.
async function connectWithFallback(docId, getAccessToken) {
  const token = await getAccessToken();

  const provider = new WebsocketProvider(
    "wss://eu-central-1.wiresocket.net", // connect to any region directly
    docId,
    ydoc,
    { protocols: ["access_token", token] },
  );

  provider.ws.addEventListener("close", async (event) => {
    if (event.code === 4009 && event.reason.startsWith("REDIRECT:")) {
      const correctUrl = event.reason.replace("REDIRECT:", "");
      const freshToken = await getAccessToken();
      provider.destroy();

      return new WebsocketProvider(correctUrl, docId, ydoc, {
        protocols: ["access_token", freshToken],
      });
    }
  });

  return provider;
}

Document ID Format

Pass any string as your document ID. WireSocket handles isolation internally by prefixing it with tenantId::appId:: before it reaches the storage layer. Recommendations:
  • Keep document IDs under 255 characters
  • Use URL-safe characters — alphanumeric, hyphens, underscores
// Good
"my-document-123";
"user_notes_abc";

Connecting Your Editor

TipTap

import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";
import { Editor } from "@tiptap/core";
import Collaboration from "@tiptap/extension-collaboration";
import CollaborationCursor from "@tiptap/extension-collaboration-cursor";

const ydoc = new Y.Doc();

const provider = new WebsocketProvider(
  "wss://eu-central-1.wiresocket.net",
  "your-document-id",
  ydoc,
  {
    protocols: ["access_token", "YOUR_ACCESS_TOKEN"],
  },
);

const editor = new Editor({
  extensions: [
    Collaboration.configure({ document: ydoc }),
    CollaborationCursor.configure({ provider }),
  ],
});

Passing the Token

Three methods are supported. All work in all regions.
MethodHow
WebSocket Subprotocol (recommended)protocols: ['access_token', 'YOUR_ACCESS_TOKEN']
Query Parameterwss://{region-code}.wiresocket.net?token=YOUR_ACCESS_TOKEN
Auth HeaderAuthorization: Bearer YOUR_ACCESS_TOKEN
The subprotocol method is preferred — it keeps the token out of server access logs and browser history.

Token Expiry & Reconnection

JWT validation happens at handshake only. Once connected, an expiring token does not drop an active session. When your token is close to expiry, reconnect with a fresh token:
async function connectWithFreshToken(docId, getAccessToken) {
  const token = await getAccessToken();

  provider.destroy();

  return new WebsocketProvider(
    "wss://eu-central-1.wiresocket.net",
    docId,
    ydoc,
    { protocols: ["access_token", token] },
  );
}
Reconnecting re-validates the JWT against the JWKS endpoint and re-reads plan limits from the token claims (dbCode). This is the correct way to pick up plan changes or credential rotations.
Last modified on March 3, 2026