### Complete Working Example
Source: https://context7.com/stomp-js/stompjs/llms.txt
A comprehensive Node.js example demonstrating connection, subscription, publishing (transactional and non-transactional), manual acknowledgments, and graceful shutdown.
```APIDOC
## Complete working example — Node.js producer/consumer
A full end-to-end example that demonstrates connecting, subscribing, publishing, transactional publishing, manual ACK, and graceful shutdown.
```typescript
import { Client, IMessage, ReconnectionTimeMode } from '@stomp/stompjs';
import { WebSocket } from 'ws';
Object.assign(global, { WebSocket });
const DESTINATION = '/queue/example';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: { login: 'guest', passcode: 'guest' },
reconnectDelay: 3000,
maxReconnectDelay: 30_000,
reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
heartbeatIncoming: 10_000,
heartbeatOutgoing: 10_000,
debug: (msg) => console.debug('[DEBUG]', msg),
onConnect: async () => {
console.log('✓ Connected, version:', client.connectedVersion);
// Subscribe with manual ACK
const sub = client.subscribe(
DESTINATION,
(msg: IMessage) => {
console.log('← Received:', msg.body);
msg.ack(); // acknowledge each message
},
{ ack: 'client-individual' },
);
// Transactional publish
const tx = client.begin();
client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 1' });
client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 2' });
tx.commit();
console.log('→ Published 2 messages in transaction', tx.id);
// Non-transactional publish with receipt
const receiptId = 'rcpt-001';
client.watchForReceipt(receiptId, () => console.log('✓ Broker confirmed receipt', receiptId));
client.publish({ destination: DESTINATION, headers: { receipt: receiptId }, body: 'Message 3' });
// Graceful shutdown after a short delay
await new Promise(r => setTimeout(r, 3000));
sub.unsubscribe();
await client.deactivate();
console.log('✓ Deactivated');
},
onStompError: (frame) => console.error('✗ STOMP error:', frame.headers['message'], frame.body),
onWebSocketError: (evt) => console.error('✗ WebSocket error:', evt),
});
client.activate();
```
```
--------------------------------
### Install and Connect in Node.js
Source: https://github.com/stomp-js/stompjs/blob/develop/README.md
Steps to install STOMP.js and its WebSocket dependency for Node.js, followed by an example of connecting to a broker, subscribing, and publishing. The 'ws' library needs to be explicitly assigned to the global WebSocket object.
```bash
npm install @stomp/stompjs ws
```
```javascript
import { Client } from '@stomp/stompjs';
import { WebSocket } from 'ws';
Object.assign(global, { WebSocket });
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
client.subscribe('/topic/test01', message =>
console.log(`Received: ${message.body}`),
);
client.publish({ destination: '/topic/test01', body: 'First Message' });
},
});
client.activate();
```
--------------------------------
### Install Dependencies with npm
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Installs project dependencies. Ensure Node.js and npm are installed before running.
```bash
$ npm i
```
--------------------------------
### Node.js Producer/Consumer Example
Source: https://context7.com/stomp-js/stompjs/llms.txt
A full example demonstrating connection, subscription with manual ACK, transactional publishing, publishing with receipts, and graceful shutdown. Requires `ws` package for Node.js.
```typescript
import { Client, IMessage, ReconnectionTimeMode } from '@stomp/stompjs';
import { WebSocket } from 'ws';
Object.assign(global, { WebSocket });
const DESTINATION = '/queue/example';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: { login: 'guest', passcode: 'guest' },
reconnectDelay: 3000,
maxReconnectDelay: 30_000,
reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
heartbeatIncoming: 10_000,
heartbeatOutgoing: 10_000,
debug: (msg) => console.debug('[DEBUG]', msg),
onConnect: async () => {
console.log('✓ Connected, version:', client.connectedVersion);
// Subscribe with manual ACK
const sub = client.subscribe(
DESTINATION,
(msg: IMessage) => {
console.log('← Received:', msg.body);
msg.ack(); // acknowledge each message
},
{ ack: 'client-individual' },
);
// Transactional publish
const tx = client.begin();
client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 1' });
client.publish({ destination: DESTINATION, headers: { transaction: tx.id }, body: 'Message 2' });
tx.commit();
console.log('→ Published 2 messages in transaction', tx.id);
// Non-transactional publish with receipt
const receiptId = 'rcpt-001';
client.watchForReceipt(receiptId, () => console.log('✓ Broker confirmed receipt', receiptId));
client.publish({ destination: DESTINATION, headers: { receipt: receiptId }, body: 'Message 3' });
// Graceful shutdown after a short delay
await new Promise(r => setTimeout(r, 3000));
sub.unsubscribe();
await client.deactivate();
console.log('✓ Deactivated');
},
onStompError: (frame) => console.error('✗ STOMP error:', frame.headers['message'], frame.body),
onWebSocketError: (evt) => console.error('✗ WebSocket error:', evt),
});
client.activate();
```
--------------------------------
### Install @stomp/stompjs for Node.js and Browser
Source: https://context7.com/stomp-js/stompjs/llms.txt
Install the library using npm for Node.js environments. For browser usage without a bundler, importmap or CDN can be used.
```bash
# Node.js
npm install @stomp/stompjs ws
```
```html
```
--------------------------------
### Start Transaction with client.begin
Source: https://context7.com/stomp-js/stompjs/llms.txt
Initiate a transaction using `client.begin()` to group `publish`, `ack`, and `nack` calls atomically. The library generates a unique transaction ID if none is provided.
```typescript
import { Client, ITransaction } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
const tx: ITransaction = client.begin(); // auto-generated ID
console.log('Transaction ID:', tx.id);
try {
// All publishes under this transaction are atomic
client.publish({
destination: '/queue/ledger',
headers: { transaction: tx.id },
body: JSON.stringify({ type: 'debit', account: 'A', amount: 100 }),
});
client.publish({
destination: '/queue/ledger',
headers: { transaction: tx.id },
body: JSON.stringify({ type: 'credit', account: 'B', amount: 100 }),
});
tx.commit();
console.log('Transaction committed');
} catch (err) {
tx.abort();
console.error('Transaction aborted:', err);
}
},
});
client.activate();
```
--------------------------------
### Connect and Subscribe in Browser
Source: https://github.com/stomp-js/stompjs/blob/develop/README.md
Example of connecting to a STOMP broker, subscribing to a topic, and publishing a message in a browser environment. Ensure the script tags for import maps and es-module-shims are included in your HTML.
```html
```
```javascript
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
client.subscribe('/topic/test01', message =>
console.log(`Received: ${message.body}`),
);
client.publish({ destination: '/topic/test01', body: 'First Message' });
},
});
client.activate();
```
--------------------------------
### client.begin(transactionId?)
Source: https://context7.com/stomp-js/stompjs/llms.txt
Starts a new transaction, returning an `ITransaction` object with `id`, `commit()`, and `abort()` methods. Operations like `publish`, `ack`, and `nack` can be associated with this transaction ID for atomic execution.
```APIDOC
## `client.begin(transactionId?)` — Start a transaction
### Description
Initiates a STOMP transaction. Returns an `ITransaction` object that allows grouping of `publish`, `ack`, and `nack` operations to be committed or aborted atomically. If no `transactionId` is provided, a unique ID is generated.
### Usage
```typescript
const tx: ITransaction = client.begin(); // auto-generated ID
console.log('Transaction ID:', tx.id);
try {
// All publishes under this transaction are atomic
client.publish({ ... });
client.publish({ ... });
tx.commit();
console.log('Transaction committed');
} catch (err) {
tx.abort();
console.error('Transaction aborted:', err);
}
```
### Parameters
- `transactionId` (string, optional): A unique identifier for the transaction. If not provided, the library generates one.
```
--------------------------------
### Run RabbitMQ Docker Container
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Starts a RabbitMQ Docker container in detached mode, exposing the WebStomp port.
```bash
docker run -d -p 15674:15674 myrabbitmq
```
--------------------------------
### Atomic Message Grouping with ITransaction
Source: https://context7.com/stomp-js/stompjs/llms.txt
Use `client.begin()` to start a transaction. Messages published with the transaction ID will be grouped atomically. Commit or abort the transaction to finalize.
```typescript
import { Client, ITransaction } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
const tx: ITransaction = client.begin('my-tx-001');
// Enqueue multiple messages atomically
for (const item of ['A', 'B', 'C']) {
client.publish({
destination: '/queue/batch',
headers: { transaction: tx.id },
body: item,
});
}
// Acknowledge a message within the transaction
// message.ack({ transaction: tx.id });
// Commit or abort
const success = true; // application logic
if (success) {
tx.commit();
console.log('Transaction my-tx-001 committed');
} else {
tx.abort();
console.log('Transaction my-tx-001 aborted');
}
},
});
client.activate();
```
--------------------------------
### Legacy STOMP Client API (Deprecated)
Source: https://context7.com/stomp-js/stompjs/llms.txt
The `CompatClient` extends `Client` to maintain the pre-v5 API. Use `Stomp.client()` or `Stomp.over()` to create a `CompatClient`. Migration to the modern `Client` API is recommended. This example shows connecting, sending, and subscribing using the legacy API.
```typescript
import { Stomp } from '@stomp/stompjs';
// Legacy factory — creates a CompatClient
const client = Stomp.over(() => new WebSocket('ws://localhost:15674/ws'));
client.connect(
{ login: 'guest', passcode: 'guest' }, // headers
(frame) => { // connectCallback
console.log('Connected (legacy API)', frame);
// Legacy send() — equivalent to client.publish()
client.send('/queue/test', {}, 'Hello from legacy API');
// Legacy subscribe
client.subscribe('/queue/test', (msg) => {
console.log('Received (legacy):', msg.body);
});
},
(error) => console.error('Error:', error), // errorCallback
);
// Legacy heartbeat configuration
client.heartbeat.incoming = 10_000;
client.heartbeat.outgoing = 5_000;
```
--------------------------------
### Activate STOMP Client Connection
Source: https://context7.com/stomp-js/stompjs/llms.txt
Call `client.activate()` to initiate the connection lifecycle. This method transitions the client to an active state and starts connection attempts. It handles automatic reconnections if the connection is lost.
```typescript
import { Client, ActivationState } from '@stomp/stompjs';
const client = new Client({ brokerURL: 'ws://localhost:15674/ws' });
client.onChangeState = (state: ActivationState) => {
console.log('State →', ActivationState[state]);
// Logs: State → ACTIVE, State → DEACTIVATING, State → INACTIVE
};
client.onConnect = () => {
console.log('Broker connected, client.active =', client.active); // true
console.log('Negotiated STOMP version:', client.connectedVersion); // "1.2"
console.log('Client.connected =', client.connected); // true
};
client.activate();
// Output: State → ACTIVE
// [STOMP] Opening Web Socket...
// Broker connected, client.active = true
// Negotiated STOMP version: 1.2
```
--------------------------------
### Incoming Subscription Message Interface
Source: https://context7.com/stomp-js/stompjs/llms.txt
The `IMessage` interface extends `IFrame` and is received in subscription callbacks. It provides `ack()` and `nack()` methods for message acknowledgment. This example shows how to access message details and handle acknowledgments.
```typescript
import { Client, IMessage } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
client.subscribe('/queue/items', (msg: IMessage) => {
// Frame fields
console.log('Destination:', msg.headers['destination']);
console.log('Message-id:', msg.headers['message-id']);
console.log('Subscription:', msg.headers['subscription']);
console.log('Body:', msg.body); // UTF-8 string
console.log('Binary body:', msg.binaryBody); // Uint8Array
console.log('Is binary:', msg.isBinaryBody);
// Parse JSON body
if (msg.headers['content-type']?.includes('json')) {
const payload = JSON.parse(msg.body);
console.log('Parsed payload:', payload);
}
// ACK when using 'client' or 'client-individual' ack mode
// msg.ack();
// msg.nack({ 'requeue': 'false' });
}, { ack: 'auto' });
},
});
client.activate();
```
--------------------------------
### Build RabbitMQ Docker Image
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Builds a Docker image for RabbitMQ with necessary plugins and configuration. This command only needs to be run once.
```bash
docker build -t myrabbitmq rabbitmq/
```
--------------------------------
### Client Class
Source: https://context7.com/stomp-js/stompjs/llms.txt
The `Client` class is the primary entry point for creating a STOMP client instance. Configuration options can be provided during instantiation or updated later using `client.configure()`.
```APIDOC
## new Client(conf?: StompConfig) — Create a STOMP client instance
The `Client` class is the main entry point. All configuration is passed at construction time via a `StompConfig` object, or updated at any time via `client.configure()`. Every field is optional; sensible defaults are provided (5-second reconnect delay, 10-second heartbeats, STOMP 1.2/1.1/1.0 negotiation).
### Parameters
- **conf** (StompConfig) - Optional - Configuration object for the STOMP client.
- **brokerURL** (string) - WebSocket endpoint.
- **connectHeaders** (object) - STOMP CONNECT frame headers.
- **login** (string) - Login username.
- **passcode** (string) - Login password.
- **host** (string) - Virtual host.
- **reconnectDelay** (number) - Milliseconds between reconnect attempts.
- **maxReconnectDelay** (number) - Cap for exponential backoff.
- **reconnectTimeMode** (ReconnectionTimeMode) - Mode for reconnect delay (e.g., EXPONENTIAL).
- **heartbeatIncoming** (number) - Incoming heartbeat interval in milliseconds (0 to disable).
- **heartbeatOutgoing** (number) - Outgoing heartbeat interval in milliseconds.
- **heartbeatToleranceMultiplier** (number) - Multiplier for heartbeat tolerance.
- **heartbeatStrategy** (TickerStrategy) - Strategy for heartbeats (e.g., Interval, Worker).
- **connectionTimeout** (number) - Timeout in milliseconds to abort a connect attempt.
- **debug** (function) - Callback function for debug messages.
- **onConnect** (function) - Callback function when connected.
- **frame** (IFrame) - The CONNECTED frame.
- **onDisconnect** (function) - Callback function when disconnected.
- **onStompError** (function) - Callback function for STOMP errors.
- **frame** (IFrame) - The ERROR frame.
- **onWebSocketClose** (function) - Callback function for WebSocket close events.
- **evt** (object) - The close event object.
- **onWebSocketError** (function) - Callback function for WebSocket errors.
- **evt** (object) - The error event object.
### Request Example
```typescript
import { Client, StompConfig, ReconnectionTimeMode, TickerStrategy, IFrame } from '@stomp/stompjs';
// Node.js only: polyfill WebSocket
import { WebSocket } from 'ws';
Object.assign(global, { WebSocket });
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
connectHeaders: {
login: 'guest',
passcode: 'guest',
host: '/',
},
reconnectDelay: 5000,
maxReconnectDelay: 60_000,
reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
heartbeatIncoming: 10_000,
heartbeatOutgoing: 10_000,
heartbeatToleranceMultiplier: 2,
heartbeatStrategy: TickerStrategy.Interval,
connectionTimeout: 5_000,
debug: (msg: string) => console.log('[STOMP]', msg),
onConnect: (frame: IFrame) => {
console.log('Connected, session:', frame.headers['session']);
},
onDisconnect: () => console.log('Disconnected'),
onStompError: (frame: IFrame) => console.error('STOMP error:', frame.body),
onWebSocketClose: (evt) => console.warn('WebSocket closed, code:', evt.code),
onWebSocketError: (evt) => console.error('WebSocket error:', evt),
});
```
```
--------------------------------
### Create and Configure STOMP Client Instance
Source: https://context7.com/stomp-js/stompjs/llms.txt
Instantiate the `Client` class with a `StompConfig` object to set up connection details, headers, reconnection logic, and callbacks. For Node.js, polyfill the WebSocket API.
```typescript
import { Client, StompConfig, ReconnectionTimeMode, TickerStrategy, IFrame } from '@stomp/stompjs';
// Node.js only: polyfill WebSocket
import { WebSocket } from 'ws';
Object.assign(global, { WebSocket });
const client = new Client({
brokerURL: 'ws://localhost:15674/ws', // WebSocket endpoint
connectHeaders: {
login: 'guest',
passcode: 'guest',
host: '/',
},
reconnectDelay: 5000, // ms between reconnect attempts
maxReconnectDelay: 60_000, // cap for exponential backoff
reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
heartbeatIncoming: 10_000, // ms, 0 = disabled
heartbeatOutgoing: 10_000,
heartbeatToleranceMultiplier: 2, // tolerance = incoming * multiplier
heartbeatStrategy: TickerStrategy.Interval, // or TickerStrategy.Worker
connectionTimeout: 5_000, // abort connect attempt after 5s
debug: (msg: string) => console.log('[STOMP]', msg),
onConnect: (frame: IFrame) => {
console.log('Connected, session:', frame.headers['session']);
},
onDisconnect: () => console.log('Disconnected'),
onStompError: (frame: IFrame) => console.error('STOMP error:', frame.body),
onWebSocketClose: (evt) => console.warn('WebSocket closed, code:', evt.code),
onWebSocketError: (evt) => console.error('WebSocket error:', evt),
});
```
--------------------------------
### Configure Client at Runtime
Source: https://context7.com/stomp-js/stompjs/llms.txt
Merges new configuration onto the client instance. Can be called before or after `activate()`. Useful for rotating credentials before each reconnect via `beforeConnect`.
```typescript
import { Client } from '@stomp/stompjs';
const client = new Client({ brokerURL: 'ws://localhost:15674/ws' });
// Dynamically refresh an auth token before every connect attempt
client.beforeConnect = async (c: Client) => {
const token = await fetch('/api/token').then(r => r.text());
c.configure({
connectHeaders: { login: 'app', passcode: token },
});
};
client.onConnect = () => console.log('Authenticated and connected');
client.activate();
```
--------------------------------
### STOMP Frame Interface and Callbacks
Source: https://context7.com/stomp-js/stompjs/llms.txt
The `IFrame` interface represents a STOMP frame. Lifecycle callbacks like `onConnect`, `onDisconnect`, and `onStompError` receive an `IFrame` object. This example demonstrates accessing frame properties and headers within the `onConnect` and `onStompError` callbacks.
```typescript
import { Client, IFrame } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: (frame: IFrame) => {
console.log('Command:', frame.command); // "CONNECTED"
console.log('Version:', frame.headers['version']); // "1.2"
console.log('Session:', frame.headers['session']); // broker session ID
console.log('Heart-beat:', frame.headers['heart-beat']); // "0,0" or "10000,10000"
console.log('Is binary:', frame.isBinaryBody); // false for CONNECTED frame
},
onStompError: (frame: IFrame) => {
console.error('STOMP ERROR');
console.error(' command:', frame.command); // "ERROR"
console.error(' message:', frame.headers['message']);
console.error(' body:', frame.body);
},
});
client.activate();
```
--------------------------------
### client.activate()
Source: https://context7.com/stomp-js/stompjs/llms.txt
Initiates the connection lifecycle by transitioning the client to an active state. If the connection is lost, the client will automatically attempt to reconnect.
```APIDOC
## client.activate() — Start the connection lifecycle
Transitions the client to `ActivationState.ACTIVE` and initiates a connection attempt. If the connection drops, the client automatically schedules reconnections. Calling `activate()` while already active is a no-op; calling it during deactivation queues activation for after shutdown completes.
### Description
This method starts the STOMP client's connection process. It handles the WebSocket connection and STOMP handshake. If the connection is interrupted, it will automatically attempt to re-establish the connection based on the configured reconnection settings.
### Method
`client.activate()`
### Parameters
This method does not accept any parameters.
### Usage Example
```typescript
import { Client, ActivationState } from '@stomp/stompjs';
const client = new Client({ brokerURL: 'ws://localhost:15674/ws' });
client.onChangeState = (state: ActivationState) => {
console.log('State →', ActivationState[state]);
// Logs: State → ACTIVE, State → DEACTIVATING, State → INACTIVE
};
client.onConnect = () => {
console.log('Broker connected, client.active =', client.active); // true
console.log('Negotiated STOMP version:', client.connectedVersion); // "1.2"
console.log('Client.connected =', client.connected); // true
};
client.activate();
// Output:
// State → ACTIVE
// [STOMP] Opening Web Socket...
// Broker connected, client.active = true
// Negotiated STOMP version: 1.2
```
```
--------------------------------
### client.configure(conf: StompConfig)
Source: https://context7.com/stomp-js/stompjs/llms.txt
Merges new configuration onto the client instance. This method can be called before or after `activate()`, and is useful for rotating credentials before each reconnect via `beforeConnect`.
```APIDOC
## `client.configure(conf: StompConfig)` — Update client configuration at runtime
Merges new configuration onto the client instance. Can be called before or after `activate()`. Useful for rotating credentials before each reconnect via `beforeConnect`.
```typescript
import { Client } from '@stomp/stompjs';
const client = new Client({ brokerURL: 'ws://localhost:15674/ws' });
// Dynamically refresh an auth token before every connect attempt
client.beforeConnect = async (c: Client) => {
const token = await fetch('/api/token').then(r => r.text());
c.configure({
connectHeaders: { login: 'app', passcode: token },
});
};
client.onConnect = () => console.log('Authenticated and connected');
client.activate();
```
```
--------------------------------
### Custom WebSocket Factory with SockJS
Source: https://context7.com/stomp-js/stompjs/llms.txt
Demonstrates how to use `webSocketFactory` to provide a custom WebSocket implementation, such as SockJS, for environments requiring non-standard WebSocket connections. The factory function must return a new socket instance on each call.
```APIDOC
## `client.webSocketFactory` — Custom WebSocket / SockJS factory
An alternative to `brokerURL` for environments that require a non-standard WebSocket (e.g., SockJS, or a custom wrapper). The factory function is called on every connection and reconnection attempt, so each call must return a fresh socket instance. Takes precedence over `brokerURL` when both are set.
```typescript
import { Client } from '@stomp/stompjs';
import SockJS from 'sockjs-client'; // npm install sockjs-client
const client = new Client({
// No brokerURL — use webSocketFactory instead
webSocketFactory: () => new SockJS('http://localhost:15674/stomp'),
connectHeaders: { login: 'guest', passcode: 'guest' },
onConnect: () => {
console.log('Connected via SockJS');
client.subscribe('/topic/demo', msg => console.log(msg.body));
client.publish({ destination: '/topic/demo', body: 'SockJS message' });
},
});
client.activate();
```
```
--------------------------------
### Configure RabbitMQ for Binary Frames
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Configures RabbitMQ to use binary frames for WebStomp. This is necessary for proper message handling.
```bash
echo 'web_stomp.ws_frame = binary' >> /etc/rabbitmq/rabbitmq.conf
```
--------------------------------
### Build Project Variants
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Builds the project to generate ES Modules and UMD variants. This command is part of the basic development workflow.
```bash
$ npm run build
```
--------------------------------
### Run Tests in NodeJS
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Executes the project's test suite within a NodeJS environment. This is a key step in the development workflow.
```bash
$ npm run test
```
--------------------------------
### client.subscribe(destination, callback, headers?)
Source: https://context7.com/stomp-js/stompjs/llms.txt
Subscribes to a destination by sending a STOMP SUBSCRIBE frame. A callback is registered to handle incoming messages. Returns a `StompSubscription` object with an `id` and an `unsubscribe()` method. An auto-generated ID is used if `headers.id` is not provided.
```APIDOC
## `client.subscribe(destination, callback, headers?)` — Subscribe to a destination
Sends a STOMP SUBSCRIBE frame and registers a callback invoked for every incoming message. Returns a `StompSubscription` with an `id` and an `unsubscribe()` method. An auto-generated subscription ID is used unless `headers.id` is provided.
```typescript
import { Client, IMessage, StompSubscription } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
// Auto-id subscription
const sub: StompSubscription = client.subscribe(
'/topic/prices',
(message: IMessage) => {
console.log('Headers:', message.headers);
console.log('Body:', message.body);
// Binary body: message.binaryBody (Uint8Array)
// Is binary: message.isBinaryBody
},
);
// Explicit subscription ID
const sub2 = client.subscribe(
'/queue/notifications',
(msg) => console.log('Notification:', msg.body),
{ id: 'my-notification-sub', ack: 'client' },
);
// Later: unsubscribe either way
setTimeout(() => {
sub.unsubscribe(); // preferred
client.unsubscribe(sub2.id); // equivalent
}, 30_000);
},
});
client.activate();
```
```
--------------------------------
### Run Tests in Browsers with Karma
Source: https://github.com/stomp-js/stompjs/blob/develop/Contribute.md
Executes the project's test suite in browsers using Karma. Be cautious when running this concurrently with NodeJS tests due to shared resource names.
```bash
$ npm run karma
```
--------------------------------
### Managing Subscriptions with StompSubscription
Source: https://context7.com/stomp-js/stompjs/llms.txt
Use `client.subscribe()` to receive messages. The returned `StompSubscription` object can be used to `unsubscribe()` later. Store subscriptions to manage them.
```typescript
import { Client, StompSubscription } from '@stomp/stompjs';
const subscriptions: Map = new Map();
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
const topics = ['/topic/alpha', '/topic/beta', '/topic/gamma'];
for (const topic of topics) {
const sub: StompSubscription = client.subscribe(topic, (msg) => {
console.log(`[${topic}] ${msg.body}`);
});
subscriptions.set(topic, sub);
console.log(`Subscribed to ${topic} with id: ${sub.id}`);
}
// Unsubscribe from one topic after 10 seconds
setTimeout(() => {
const sub = subscriptions.get('/topic/alpha');
if (sub) {
sub.unsubscribe();
subscriptions.delete('/topic/alpha');
console.log('Unsubscribed from /topic/alpha');
}
}, 10_000);
},
});
client.activate();
```
--------------------------------
### client.publish(params: IPublishParams)
Source: https://context7.com/stomp-js/stompjs/llms.txt
Sends a STOMP SEND frame to the specified destination. Supports text or binary payloads via `body` or `binaryBody` respectively. Custom STOMP headers can be provided. Throws `TypeError` if the client is not connected.
```APIDOC
## `client.publish(params: IPublishParams)` — Send a message to the broker
Sends a STOMP SEND frame to the specified destination. The `body` must be a `string`; use `binaryBody` (a `Uint8Array`) for binary payloads. Custom STOMP headers are passed via `headers`. Throws `TypeError` if the client is not connected.
```typescript
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
// 1. Simple text message
client.publish({
destination: '/queue/orders',
body: 'Hello, broker!',
});
// 2. JSON payload with custom headers
client.publish({
destination: '/topic/events',
headers: { priority: '9', 'content-type': 'application/json' },
body: JSON.stringify({ event: 'user.signup', userId: 42 }),
});
// 3. Binary payload
const pixels = new Uint8Array([0xff, 0xd8, 0xff, 0xe0]); // JPEG header
client.publish({
destination: '/queue/images',
binaryBody: pixels,
headers: { 'content-type': 'image/jpeg' },
});
// 4. Skip content-length header (e.g. for Spring-compatible brokers)
client.publish({
destination: '/queue/legacy',
body: 'plain text',
skipContentLengthHeader: true,
});
},
});
client.activate();
```
```
--------------------------------
### client.subscribe with manual acknowledgement
Source: https://context7.com/stomp-js/stompjs/llms.txt
When a subscription is created with `ack: 'client'` or `ack: 'client-individual'`, messages must be explicitly acknowledged. Call `message.ack()` on success or `message.nack()` to reject. The broker will redeliver unacknowledged messages according to its policy.
```APIDOC
## `client.subscribe` with manual acknowledgement — ACK / NACK messages
### Description
Messages must be explicitly acknowledged when a subscription is created with `ack: 'client'` or `ack: 'client-individual'`. Use `message.ack()` for successful processing or `message.nack()` to indicate failure, allowing the broker to redeliver messages.
### Usage
```typescript
client.subscribe(
'/queue/tasks',
async (message: IMessage) => {
try {
const task = JSON.parse(message.body);
await processTask(task); // application logic
message.ack(); // → STOMP ACK frame sent
console.log('Task processed and acknowledged');
} catch (err) {
console.error('Task failed, sending NACK:', err);
message.nack(); // → STOMP NACK frame sent; broker requeues
}
},
{ ack: 'client-individual' }, // each message acknowledged separately
);
```
### Parameters
- `destination` (string): The STOMP destination to subscribe to.
- `callback` (function): A function that will be called with the received `IMessage`.
- `headers` (object, optional): Headers for the SUBSCRIBE frame. Use `{ ack: 'client' }` or `{ ack: 'client-individual' }` for manual acknowledgements.
```
--------------------------------
### STOMP Protocol Version Constants
Source: https://context7.com/stomp-js/stompjs/llms.txt
Use the `Versions` class to access supported STOMP protocol version strings and generate correct WebSocket sub-protocol and CONNECT header values. Import `Versions` from '@stomp/stompjs'.
```typescript
import { Versions } from '@stomp/stompjs';
console.log(Versions.V1_0); // "1.0"
console.log(Versions.V1_1); // "1.1"
console.log(Versions.V1_2); // "1.2"
const v = new Versions([Versions.V1_2, Versions.V1_1]);
console.log(v.supportedVersions()); // "1.2,1.1" (used in CONNECT frame)
console.log(v.protocolVersions()); // ["v12.stomp", "v11.stomp"] (used as WS sub-protocols)
```
--------------------------------
### client.watchForReceipt(receiptId, callback)
Source: https://context7.com/stomp-js/stompjs/llms.txt
Registers a callback to be executed when the broker sends a RECEIPT frame matching the specified `receiptId`. This is used to confirm that operations like publish, subscribe, or unsubscribe have been processed by the broker.
```APIDOC
## `client.watchForReceipt(receiptId, callback)` — Wait for broker acknowledgement
### Description
Sets up a listener for a specific `receiptId`. When the broker processes an operation that includes this `receiptId` in its headers, it sends back a RECEIPT frame, triggering the provided callback.
### Usage
```typescript
const receiptId = `receipt-${Date.now()}`;
// Register the watcher BEFORE issuing the operation
client.watchForReceipt(receiptId, (frame: IFrame) => {
console.log('Broker confirmed message delivery, receipt frame:', frame.command);
// Output: Broker confirmed message delivery, receipt frame: RECEIPT
});
client.publish({
destination: '/queue/confirmed',
headers: { receipt: receiptId },
body: 'This message requires broker confirmation',
});
```
### Parameters
- `receiptId` (string): The unique identifier for the receipt to watch for.
- `callback` (function): A function to execute when the corresponding RECEIPT frame is received. It receives the `IFrame` object as an argument.
```
--------------------------------
### Heartbeat Configuration
Source: https://context7.com/stomp-js/stompjs/llms.txt
Configures heartbeat settings (`heartbeatIncoming`, `heartbeatOutgoing`, `heartbeatToleranceMultiplier`) to maintain connection liveness and detect broker failures. Heartbeats can be disabled by setting values to 0.
```APIDOC
## Heartbeat configuration — `heartbeatIncoming`, `heartbeatOutgoing`, `heartbeatToleranceMultiplier`
Heartbeats keep the connection alive and detect broker failures. `heartbeatOutgoing` controls the ping interval sent to the broker; `heartbeatIncoming` controls the expected ping interval from the broker. The tolerance window is `heartbeatIncoming * heartbeatToleranceMultiplier`. Both can be set to `0` to disable.
```typescript
import { Client, TickerStrategy } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
heartbeatOutgoing: 5_000, // send ping every 5s
heartbeatIncoming: 10_000, // expect ping from broker every 10s
heartbeatToleranceMultiplier: 2,// tolerate up to 20s before declaring failure
heartbeatStrategy: TickerStrategy.Worker, // use Web Worker (avoids tab throttling)
onHeartbeatReceived: () => {
console.log(`[${new Date().toISOString()}] Heartbeat received`);
},
onHeartbeatLost: () => {
console.error('Heartbeat lost — broker may be unreachable');
// The library will force-disconnect and attempt reconnection automatically
},
onConnect: () => console.log('Connected'),
});
client.activate();
```
```
--------------------------------
### Reconnection with Exponential Backoff
Source: https://context7.com/stomp-js/stompjs/llms.txt
Configures reconnection behavior using `reconnectTimeMode`, `reconnectDelay`, and `maxReconnectDelay`. The client can switch to exponential backoff for increasing delays between reconnection attempts, capped by `maxReconnectDelay`.
```APIDOC
## Reconnection with exponential backoff — `reconnectTimeMode`, `reconnectDelay`, `maxReconnectDelay`
By default the client uses linear reconnect delays. Switch to `ReconnectionTimeMode.EXPONENTIAL` to double the delay after each failed attempt, up to `maxReconnectDelay`.
```typescript
import { Client, ReconnectionTimeMode } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
reconnectDelay: 500, // initial delay: 0.5s
maxReconnectDelay: 30_000, // cap: 30s
reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
// Sequence: 500ms → 1000ms → 2000ms → 4000ms → 8000ms → 16000ms → 30000ms → 30000ms ...
onConnect: () => console.log('Reconnected successfully'),
onWebSocketClose: (evt) => {
console.warn(`WebSocket closed (code ${evt.code}), scheduling reconnect...`);
},
debug: (msg) => console.debug(msg),
});
client.activate();
```
```
--------------------------------
### STOMP Version Negotiation
Source: https://context7.com/stomp-js/stompjs/llms.txt
Allows control over which STOMP protocol versions are advertised during the connection handshake using `stompVersions`. This is useful for compatibility with brokers that support a limited set of versions.
```APIDOC
## `client.stompVersions` — Control STOMP protocol version negotiation
Controls which STOMP versions are advertised in the CONNECT frame. By default all three versions are offered (`1.2`, `1.1`, `1.0`) in preference order. Restrict this when connecting to brokers with limited protocol support.
```typescript
import { Client, Versions } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
// Only offer STOMP 1.1 and 1.0; do not negotiate 1.2
stompVersions: new Versions([Versions.V1_1, Versions.V1_0]),
onConnect: (frame) => {
console.log('Negotiated version:', client.connectedVersion);
// Output: Negotiated version: 1.1
},
});
client.activate();
```
```
--------------------------------
### Custom WebSocket Factory with SockJS
Source: https://context7.com/stomp-js/stompjs/llms.txt
Use `webSocketFactory` to provide a custom WebSocket implementation, such as SockJS. The factory function must return a new socket instance on each call. This option takes precedence over `brokerURL`.
```typescript
import { Client } from '@stomp/stompjs';
import SockJS from 'sockjs-client'; // npm install sockjs-client
const client = new Client({
// No brokerURL — use webSocketFactory instead
webSocketFactory: () => new SockJS('http://localhost:15674/stomp'),
connectHeaders: { login: 'guest', passcode: 'guest' },
onConnect: () => {
console.log('Connected via SockJS');
client.subscribe('/topic/demo', msg => console.log(msg.body));
client.publish({ destination: '/topic/demo', body: 'SockJS message' });
},
});
client.activate();
```
--------------------------------
### Wait for Receipt with client.watchForReceipt
Source: https://context7.com/stomp-js/stompjs/llms.txt
Use `client.watchForReceipt(receiptId, callback)` to execute a callback when the broker sends a RECEIPT frame matching the specified `receiptId`. This confirms operations like publish, subscribe, or unsubscribe.
```typescript
import { Client, IFrame } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: () => {
const receiptId = `receipt-${Date.now()}`;
// Register the watcher BEFORE issuing the operation
client.watchForReceipt(receiptId, (frame: IFrame) => {
console.log('Broker confirmed message delivery, receipt frame:', frame.command);
// Output: Broker confirmed message delivery, receipt frame: RECEIPT
});
client.publish({
destination: '/queue/confirmed',
headers: { receipt: receiptId },
body: 'This message requires broker confirmation',
});
},
});
client.activate();
```
--------------------------------
### STOMP Protocol Version Negotiation
Source: https://context7.com/stomp-js/stompjs/llms.txt
Control the STOMP versions offered during connection using `stompVersions`. This is important for brokers with limited protocol support. By default, `1.2`, `1.1`, and `1.0` are offered.
```typescript
import { Client, Versions } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
// Only offer STOMP 1.1 and 1.0; do not negotiate 1.2
stompVersions: new Versions([Versions.V1_1, Versions.V1_0]),
onConnect: (frame) => {
console.log('Negotiated version:', client.connectedVersion);
// Output: Negotiated version: 1.1
},
});
client.activate();
```
--------------------------------
### Gracefully Stop the Client
Source: https://context7.com/stomp-js/stompjs/llms.txt
Sends a STOMP DISCONNECT frame, waits for the WebSocket to close cleanly, then transitions to `ActivationState.INACTIVE`. Pass `{ force: true }` to skip the graceful shutdown sequence and immediately discard the socket.
```typescript
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
onConnect: async () => {
console.log('Connected');
// Do some work...
await new Promise(resolve => setTimeout(resolve, 2000));
// Graceful shutdown — waits for broker RECEIPT
await client.deactivate();
console.log('Deactivated gracefully, client.active =', client.active); // false
// -- OR -- forced shutdown (skips DISCONNECT handshake)
// await client.deactivate({ force: true });
},
});
client.activate();
```
--------------------------------
### Heartbeat Configuration for Connection Stability
Source: https://context7.com/stomp-js/stompjs/llms.txt
Configure `heartbeatIncoming`, `heartbeatOutgoing`, and `heartbeatToleranceMultiplier` to manage connection health and detect broker failures. Set to `0` to disable. `heartbeatStrategy: TickerStrategy.Worker` uses a Web Worker to avoid tab throttling.
```typescript
import { Client, TickerStrategy } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
heartbeatOutgoing: 5_000, // send ping every 5s
heartbeatIncoming: 10_000, // expect ping from broker every 10s
heartbeatToleranceMultiplier: 2,// tolerate up to 20s before declaring failure
heartbeatStrategy: TickerStrategy.Worker, // use Web Worker (avoids tab throttling)
onHeartbeatReceived: () => {
console.log(`[${new Date().toISOString()}] Heartbeat received`);
},
onHeartbeatLost: () => {
console.error('Heartbeat lost — broker may be unreachable');
// The library will force-disconnect and attempt reconnection automatically
},
onConnect: () => console.log('Connected'),
});
client.activate();
```
--------------------------------
### Exponential Backoff Reconnection Strategy
Source: https://context7.com/stomp-js/stompjs/llms.txt
Configure `reconnectTimeMode`, `reconnectDelay`, and `maxReconnectDelay` for exponential backoff reconnection. The delay doubles with each failed attempt, capped by `maxReconnectDelay`. The default is linear backoff.
```typescript
import { Client, ReconnectionTimeMode } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:15674/ws',
reconnectDelay: 500, // initial delay: 0.5s
maxReconnectDelay: 30_000, // cap: 30s
reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
// Sequence: 500ms → 1000ms → 2000ms → 4000ms → 8000ms → 16000ms → 30000ms → 30000ms ...
onConnect: () => console.log('Reconnected successfully'),
onWebSocketClose: (evt) => {
console.warn(`WebSocket closed (code ${evt.code}), scheduling reconnect...`);
},
debug: (msg) => console.debug(msg),
});
client.activate();
```