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

# WebSocket Connectivity

> WebSocket support for browser-based NATS clients

## Overview

NATS Server provides native WebSocket connectivity, enabling web browsers and other WebSocket clients to communicate using the NATS protocol. This makes it possible to build real-time web applications with direct NATS messaging from the browser.

<Info>
  WebSocket support is built directly into NATS Server with no additional proxy or gateway required.
</Info>

## Why WebSocket?

WebSocket connectivity unlocks NATS for web applications:

* **Browser Support**: Native NATS messaging directly from JavaScript
* **Real-Time Web Apps**: Build interactive dashboards, chat, notifications
* **No HTTP Polling**: Persistent bidirectional connection
* **Single Port**: WebSocket and HTTP monitoring can share a port
* **TLS Support**: Secure WebSocket (WSS) with TLS certificates
* **Per-Message Compression**: Optional compression for bandwidth reduction

## WebSocket Protocol

NATS implements the [RFC 6455 WebSocket Protocol](https://tools.ietf.org/html/rfc6455) with extensions:

* **Binary and Text Frames**: Support for both message types
* **Compression**: Optional per-message deflate compression (RFC 7692)
* **Masking**: Configurable frame masking for clients
* **Control Frames**: PING/PONG for keepalive, CLOSE for clean shutdown

### Frame Types

Implemented WebSocket opcodes (websocket.go:41-49):

```go Frame Types theme={null}
wsTextMessage   = 0x1  // UTF-8 text data
wsBinaryMessage = 0x2  // Binary data
wsCloseMessage  = 0x8  // Connection close
wsPingMessage   = 0x9  // Keepalive ping
wsPongMessage   = 0xA  // Keepalive pong
```

### WebSocket Extensions

**Per-Message Compression** (websocket.go:89-93):

```text theme={null}
Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover
```

Compression is negotiated during the WebSocket handshake and applied per-frame.

## Configuration

### Basic WebSocket Setup

Configure WebSocket by specifying a port:

```hcl websocket.conf theme={null}
websocket {
    port: 8080
    no_tls: true
    
    # Optionally bind to specific host
    # host: "0.0.0.0"
    
    # Enable compression (optional)
    compression: true
}
```

Clients connect to: `ws://localhost:8080`

### WebSocket with TLS

Secure WebSocket (WSS) requires TLS configuration:

```hcl websocket-tls.conf theme={null}
websocket {
    port: 443
    
    tls {
        cert_file: "/path/to/server-cert.pem"
        key_file: "/path/to/server-key.pem"
        # Optional CA for client cert verification
        ca_file: "/path/to/ca.pem"
        verify: true
    }
    
    # Compression recommended for WAN clients
    compression: true
}
```

Clients connect to: `wss://yourserver.com`

<Warning>
  Always use WSS (TLS) in production. Unencrypted WebSocket connections expose credentials and message content.
</Warning>

### Shared Port with HTTP Monitoring

WebSocket can share a port with HTTP monitoring:

```hcl shared-port.conf theme={null}
http_port: 8222

websocket {
    port: 8222
    no_tls: true
    
    # Same port serves both /varz and WebSocket
}
```

The server automatically detects WebSocket upgrade requests on the HTTP port.

### Advanced Configuration

```hcl websocket-advanced.conf theme={null}
websocket {
    port: 8080
    
    # Listen address
    host: "0.0.0.0"
    
    # Compression settings
    compression: true
    
    # TLS configuration
    tls {
        cert_file: "/path/to/cert.pem"
        key_file: "/path/to/key.pem"
        timeout: 2.0  # TLS handshake timeout
    }
    
    # Authentication
    # Inherits from server auth configuration
    # Can be overridden per WebSocket connection
    
    # CORS and origin restrictions
    same_origin: false
    allowed_origins: [
        "https://app.example.com",
        "https://dashboard.example.com"
    ]
    
    # Handshake timeout
    handshake_timeout: 2s
    
    # No masking (server to client)
    # Server responses can skip masking for performance
    no_masking: true
}
```

<ParamField path="port" type="int" required>
  WebSocket listener port
</ParamField>

<ParamField path="host" type="string" default="0.0.0.0">
  Listen address for WebSocket connections
</ParamField>

<ParamField path="compression" type="bool" default="false">
  Enable per-message deflate compression
</ParamField>

<ParamField path="same_origin" type="bool" default="false">
  Require connections from same origin as server
</ParamField>

<ParamField path="allowed_origins" type="array">
  List of allowed origins for CORS
</ParamField>

<ParamField path="handshake_timeout" type="duration" default="2s">
  Maximum time to complete WebSocket handshake
</ParamField>

<ParamField path="no_masking" type="bool" default="false">
  Disable masking for server-to-client frames (performance optimization)
</ParamField>

## Browser Clients

### JavaScript/TypeScript

Connect from the browser using the NATS WebSocket client:

```typescript Browser Example theme={null}
import { connect } from '@nats-io/nats.ws';

// Connect to NATS via WebSocket
const nc = await connect({
    servers: ['ws://localhost:8080'],
    // Or secure: ['wss://nats.example.com']
});

// Subscribe to messages
const sub = nc.subscribe('updates');
(async () => {
    for await (const msg of sub) {
        console.log('Received:', new TextDecoder().decode(msg.data));
    }
})();

// Publish messages
nc.publish('events', new TextEncoder().encode('Hello from browser!'));

// Request-reply
const response = await nc.request(
    'api.user.info',
    new TextEncoder().encode('user123'),
    { timeout: 1000 }
);
```

### React Application

```tsx React Hook theme={null}
import { useEffect, useState } from 'react';
import { connect, NatsConnection } from '@nats-io/nats.ws';

function useNATS(url: string) {
    const [nc, setNc] = useState<NatsConnection | null>(null);
    
    useEffect(() => {
        let connection: NatsConnection;
        
        (async () => {
            connection = await connect({ servers: [url] });
            setNc(connection);
        })();
        
        return () => {
            connection?.close();
        };
    }, [url]);
    
    return nc;
}

function Dashboard() {
    const nc = useNATS('ws://localhost:8080');
    const [messages, setMessages] = useState<string[]>([]);
    
    useEffect(() => {
        if (!nc) return;
        
        const sub = nc.subscribe('dashboard.>');
        (async () => {
            for await (const msg of sub) {
                const text = new TextDecoder().decode(msg.data);
                setMessages(prev => [...prev, text]);
            }
        })();
        
        return () => sub.unsubscribe();
    }, [nc]);
    
    return (
        <div>
            {messages.map((msg, i) => <div key={i}>{msg}</div>)}
        </div>
    );
}
```

## Web Client Support

### Authentication

WebSocket clients support all NATS authentication methods:

```typescript Authentication theme={null}
// Token authentication
await connect({
    servers: ['ws://localhost:8080'],
    token: 'your-secret-token'
});

// Username/password
await connect({
    servers: ['ws://localhost:8080'],
    user: 'webapp',
    pass: 'secret'
});

// JWT/NKey authentication
await connect({
    servers: ['ws://localhost:8080'],
    authenticator: jwtAuthenticator(jwt, seed)
});

// From cookie (set by server)
await connect({
    servers: ['ws://localhost:8080']
    // Server can set auth via cookie
});
```

### Cookie-Based Authentication

NATS supports passing authentication via cookies (websocket.go:119-123):

```typescript Cookie Auth theme={null}
// Server sets cookies in HTTP response:
// - jwt: JWT token
// - username/password: Basic auth
// - token: Token auth

// Client connects without explicit credentials
const nc = await connect({
    servers: ['ws://localhost:8080']
});
// Credentials automatically extracted from cookies
```

### Compression

Enable compression for bandwidth-constrained clients:

```typescript Compression theme={null}
const nc = await connect({
    servers: ['ws://localhost:8080'],
    // Compression negotiated automatically if server supports it
});
```

Compression is applied when message size exceeds threshold (websocket.go:62).

## MQTT over WebSocket

MQTT clients can connect via WebSocket using the `/mqtt` path:

```javascript MQTT WebSocket theme={null}
import Paho from 'paho-mqtt';

const client = new Paho.Client(
    'ws://localhost:8080/mqtt',  // Note: /mqtt path
    'client-' + Math.random()
);

client.connect({
    onSuccess: () => {
        console.log('MQTT connected via WebSocket');
        client.subscribe('sensors/#');
    }
});
```

See [MQTT](/features/mqtt) for more details on MQTT support (mqtt.go:191).

## Implementation Details

### WebSocket Handshake

The server performs standard WebSocket upgrade (websocket.go:102-103):

1. Client sends HTTP Upgrade request with `Sec-WebSocket-Key`
2. Server validates and computes accept hash using GUID
3. Server responds with 101 Switching Protocols
4. Connection upgraded to WebSocket protocol

### Frame Processing

WebSocket frames are processed efficiently (websocket.go:125-193):

* **Masking**: Client-to-server frames must be masked per RFC 6455
* **Fragmentation**: Large messages can be fragmented across frames
* **Control Frames**: PING/PONG handled automatically
* **Browser Optimization**: Frame size limited to 4KB for better browser performance (websocket.go:61)

### Connection Detection

The server detects WebSocket clients via the `ws` field (websocket.go:197-199):

```go Client Detection theme={null}
func (c *client) isWebsocket() bool {
    return c.ws != nil
}
```

## Performance Optimization

<CardGroup cols={2}>
  <Card title="Disable Masking" icon="mask">
    Use `no_masking: true` to skip server-to-client masking for better performance (websocket.go:85-86).
  </Card>

  <Card title="Compression Threshold" icon="gauge">
    Compression only applied for messages larger than 64 bytes (websocket.go:62).
  </Card>

  <Card title="Frame Size" icon="window-restore">
    Server uses 4KB frames for optimal browser performance (websocket.go:61).
  </Card>

  <Card title="Connection Pooling" icon="layer-group">
    Reuse WebSocket connections for multiple subscriptions to reduce overhead.
  </Card>
</CardGroup>

## Security

### TLS Best Practices

<Steps>
  <Step title="Always Use WSS in Production">
    Unencrypted WebSocket exposes all traffic including credentials.
  </Step>

  <Step title="Verify Certificates">
    Set `verify: true` in TLS configuration to validate client certificates.
  </Step>

  <Step title="Restrict Origins">
    Configure `allowed_origins` to prevent unauthorized domains from connecting.
  </Step>

  <Step title="Use Strong Authentication">
    Prefer JWT/NKey authentication over username/password for web clients.
  </Step>
</Steps>

### Origin Restrictions

```hcl Origin Control theme={null}
websocket {
    port: 443
    
    # Only allow specific domains
    allowed_origins: [
        "https://app.example.com",
        "https://dashboard.example.com"
    ]
    
    # Or require same origin
    same_origin: true
}
```

### X-Forwarded-For

The server respects `X-Forwarded-For` headers for client IP tracking (websocket.go:87):

```text theme={null}
X-Forwarded-For: 203.0.113.195, 198.51.100.178
```

Useful when behind a reverse proxy or load balancer.

## Monitoring

Monitor WebSocket connections via `/connz`:

```bash WebSocket Monitoring theme={null}
curl http://localhost:8222/connz | jq '.connections[] | select(.kind == "Websocket")'
```

Check WebSocket configuration in `/varz`:

```bash Server Info theme={null}
curl http://localhost:8222/varz | jq '.websocket'
```

## Use Cases

### Real-Time Dashboard

```typescript Dashboard Example theme={null}
import { connect } from '@nats-io/nats.ws';

const nc = await connect({ servers: ['wss://nats.example.com'] });

// Subscribe to metrics
const sub = nc.subscribe('metrics.*');
for await (const msg of sub) {
    const metric = JSON.parse(new TextDecoder().decode(msg.data));
    updateChart(metric);
}
```

### Chat Application

```typescript Chat Example theme={null}
const nc = await connect({ servers: ['ws://localhost:8080'] });

// Join room
const room = 'chat.room.general';

// Receive messages
const sub = nc.subscribe(room);
for await (const msg of sub) {
    displayMessage(msg);
}

// Send messages
function sendMessage(text: string) {
    nc.publish(room, new TextEncoder().encode(JSON.stringify({
        user: currentUser,
        text: text,
        timestamp: Date.now()
    })));
}
```

### Live Notifications

```typescript Notifications theme={null}
const nc = await connect({ servers: ['wss://nats.example.com'] });

// Subscribe to user-specific notifications
const userSub = nc.subscribe(`notifications.${userId}`);
for await (const msg of userSub) {
    const notification = JSON.parse(new TextDecoder().decode(msg.data));
    showNotification(notification);
}
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connection Refused" icon="circle-xmark">
    Check that WebSocket port is configured and server is listening:

    ```bash theme={null}
    netstat -an | grep 8080
    ```
  </Accordion>

  <Accordion title="Origin Blocked" icon="shield">
    Ensure client origin is in `allowed_origins` or disable origin checking in development.
  </Accordion>

  <Accordion title="TLS Handshake Failed" icon="lock">
    Verify certificate paths and ensure certificates are valid. Check server logs for TLS errors.
  </Accordion>

  <Accordion title="Compression Not Working" icon="compress">
    Both client and server must support and negotiate `permessage-deflate` extension.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Client SDKs" icon="code" href="/sdks">
    Explore NATS WebSocket client libraries
  </Card>

  <Card title="Security" icon="shield" href="/operations/security">
    Configure authentication and TLS
  </Card>

  <Card title="MQTT" icon="message" href="/features/mqtt">
    MQTT clients can also use WebSocket
  </Card>

  <Card title="Monitoring" icon="chart-line" href="/operations/monitoring">
    Monitor WebSocket connections
  </Card>
</CardGroup>
