---
name: ably
description: Implements real-time pub/sub messaging with Ably's edge infrastructure. Use when building real-time features requiring enterprise reliability, presence, message history, and global low-latency delivery.
---
# Ably Pub/Sub
Enterprise-grade real-time messaging platform with global edge network. Supports pub/sub, presence, message history, and push notifications.
## Quick Start
```bash
npm install ably
```
### Client (Realtime)
```javascript
import * as Ably from 'ably';
const ably = new Ably.Realtime({
key: 'YOUR_API_KEY', // Use token auth in production
clientId: 'user-123'
});
// Wait for connection
await ably.connection.once('connected');
// Get a channel
const channel = ably.channels.get('my-channel');
// Subscribe to messages
await channel.subscribe('greeting', (message) => {
console.log('Received:', message.data);
});
// Publish a message
await channel.publish('greeting', 'Hello World!');
```
### Server (REST)
```javascript
import * as Ably from 'ably';
const ably = new Ably.Rest({ key: 'YOUR_API_KEY' });
// Publish without maintaining connection
const channel = ably.channels.get('notifications');
await channel.publish('alert', { message: 'Server notification' });
```
## Authentication
### Token Auth (Recommended for Production)
```javascript
// Client with auth endpoint
const ably = new Ably.Realtime({
authUrl: '/api/ably-token',
clientId: 'user-123'
});
// Server endpoint (Next.js example)
// app/api/ably-token/route.ts
import * as Ably from 'ably';
export async function GET(req: Request) {
const ably = new Ably.Rest({ key: process.env.ABLY_API_KEY });
const tokenParams = {
clientId: 'user-123', // Get from session
capability: { '*': ['publish', 'subscribe', 'presence'] }
};
const tokenRequest = await ably.auth.createTokenRequest(tokenParams);
return Response.json(tokenRequest);
}
```
### Token Capabilities
```javascript
const tokenParams = {
clientId: 'user-123',
capability: {
'public-*': ['subscribe'], // Subscribe to public channels
'private-user-123': ['*'], // Full access to own channel
'chat-room-*': ['publish', 'subscribe', 'presence']
}
};
```
## Channels
### Subscribe & Publish
```javascript
const channel = ably.channels.get('chat');
// Subscribe to all messages
await channel.subscribe((message) => {
console.log(message.name, message.data);
});
// Subscribe to specific event
await channel.subscribe('message', (message) => {
console.log('Chat message:', message.data);
});
// Publish
await channel.publish('message', {
text: 'Hello!',
author: 'Alice'
});
// Publish multiple
await channel.publish([
{ name: 'message', data: 'First' },
{ name: 'message', data: 'Second' }
]);
// Unsubscribe
channel.unsubscribe('message', myHandler);
channel.unsubscribe(); // All handlers
```
### Channel States
```javascript
channel.on('attached', () => console.log('Channel attached'));
channel.on('detached', () => console.log('Channel detached'));
channel.on('failed', (err) => console.error('Channel failed:', err));
// Check state
console.log(channel.state); // initialized, attaching, attached, detaching, detached, failed
```
## Presence
Track who's online in a channel.
```javascript
const channel = ably.channels.get('room-1');
// Enter presence
await channel.presence.enter({ status: 'online', name: 'Alice' });
// Update presence data
await channel.presence.update({ status: 'away' });
// Leave presence
await channel.presence.leave();
// Get current members
const members = await channel.presence.get();
members.forEach((member) => {
console.log(member.clientId, member.data);
});
// Subscribe to presence events
await channel.presence.subscribe('enter', (member) => {
console.log(member.clientId, 'entered');
});
await channel.presence.subscribe('leave', (member) => {
console.log(member.clientId, 'left');
});
await channel.presence.subscribe('update', (member) => {
console.log(member.clientId, 'updated:', member.data);
});
// Subscribe to all presence events
await channel.presence.subscribe((member) => {
console.log(member.action, member.clientId, member.data);
});
```
## Message History
```javascript
const channel = ably.channels.get('chat');
// Get last 100 messages
const history = await channel.history({ limit: 100 });
history.items.forEach((message) => {
console.log(message.timestamp, message.name, message.data);
});
// Paginate through history
let page = await channel.history({ limit: 50 });
while (page) {
page.items.forEach(console.log);
page = await page.next(); // null when no more pages
}
// Get messages from specific time
const history = await channel.history({
start: Date.now() - 60000, // Last minute
direction: 'forwards'
});
```
## Connection Management
```javascript
// Connection events
ably.connection.on('connected', () => {
console.log('Connected!');
});
ably.connection.on('disconnected', () => {
console.log('Disconnected - will auto-reconnect');
});
ably.connection.on('suspended', () => {
console.log('Connection suspended');
});
ably.connection.on('failed', (err) => {
console.error('Connection failed:', err);
});
// Connection state
console.log(ably.connection.state);
// States: initialized, connecting, connected, disconnected, suspended, closing, closed, failed
// Manual control
ably.connection.close();
ably.connection.connect();
// Get connection ID
console.log(ably.connection.id);
```
## React Integration
```jsx
import * as Ably from 'ably';
import { AblyProvider, useChannel, usePresence } from 'ably/react';
// Setup client
const client = new Ably.Realtime({
authUrl: '/api/ably-token'
});
function App() {
return (