Use these instructions to install, authenticate and instantiate the Chat SDK.
Authentication
Chat requires an authenticated client with a clientId to identify users. The recommended approach is:
- Client-side apps (browsers, iOS, Android): Use JWT authentication with
authCallbackto fetch JWTs from your server - Server-side apps (Node.js, Python, etc.): Use your API key directly
Sign up to Ably to create an API key in the dashboard or use the Control API to create an API key programmatically. Your server will use this key to issue tokens to clients.
API keys and tokens have a set of capabilities assigned to them that specify which operations, such as subscribe or publish can be performed on which resources. To use the Chat SDK, the API key requires the following capabilities depending on which features are being used:
| Feature | Capabilities |
|---|---|
| Send messages | publish |
| Receive messages | subscribe |
| Update message | message-update-any or message-update-own |
| Delete message | message-delete-any or message-delete-own |
| Message history | subscribe, history |
| Message reactions | annotation-publish, optionally annotation-subscribe |
| Presence | subscribe, presence |
| Room occupancy | subscribe, channel-metadata |
| Typing indicators | publish, subscribe |
| Room reactions | publish, subscribe |
When setting the capabilities for Chat, you can apply them to specific chat rooms, a group of chat rooms in a common namespace, or all chat rooms:
my-chat-room- a specific roomdms:*- all rooms in thedms:namespace*- all chat rooms
For more guidance, see the capabilities documentation and Chat authentication for room-scoped examples.
Client identification
Every Chat client must have a clientId - this is a hard requirement. The Chat SDK uses the clientId to identify who sends messages, who is present in a room, and who is typing.
Your auth server sets the clientId when creating tokens. This ensures users can't impersonate each other - the identity is controlled server-side, not by the client.
If you try to connect without a clientId, the connection will fail.
User claims
User claims enable you to attach server-signed metadata to a user's authentication token that is automatically included on all events they produce in a chat room. This metadata is set server-side via JWT claims and cannot be modified by clients, making it suitable for trusted information such as display names, roles, or custom attributes.
User claims are scoped to individual chat rooms using the ably.room.<roomName> key in the JWT payload. The value is an arbitrary string, commonly a JSON-encoded object. When a user publishes a message, enters presence, sends a typing indicator, or sends a reaction in a matching room, the claim is automatically copied by Ably servers into the userClaim field of the event.
Set user claims in your JWT
Include an ably.room.<roomName> key in your JWT claims when generating tokens on your server:
1
2
3
4
5
6
7
const claims = {
'x-ably-capability': JSON.stringify({ '*': ['*'] }),
'x-ably-clientId': 'user-123',
'ably.room.my-chat-room': JSON.stringify({ display_name: 'Alice', role: 'moderator' }),
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600,
};You can also use wildcard patterns to apply claims across multiple rooms:
| Pattern | Description |
|---|---|
ably.room.my-chat-room | Applies to the my-chat-room room only. |
ably.room.support:* | Applies to all rooms in the support namespace. |
ably.room.* | Applies to all rooms. |
When multiple patterns match a room, the most specific claim is used.
Read user claims from events
The userClaim field is available on messages, presence members, typing events, room reactions, and message reactions. For example, to read the claim from a message:
1
2
3
4
5
6
7
room.messages.subscribe((event) => {
const { userClaim } = event.message;
if (userClaim) {
const parsed = JSON.parse(userClaim);
console.log(`Message from ${parsed.display_name} (${parsed.role})`);
}
});Install
The Chat SDK is built on top of the Ably Pub/Sub SDK and uses that to establish a connection with Ably.
NPM
Install the Pub/Sub SDK and the Chat SDK:
npm install ably @ably/chatImport the SDKs into your project:
1
2
import * as Ably from 'ably';
import { ChatClient } from '@ably/chat';CDN
Reference the Pub/Sub SDK and the Chat SDK within your HTML file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script src="https://cdn.ably.com/lib/ably.min-2.js"></script>
<script src="https://cdn.ably.com/lib/ably-chat.umd.cjs-0.js"></script>
<script>
// Client-side: Use token authentication (recommended)
const realtime = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-token');
const token = await response.text();
callback(null, token);
} catch (error) {
callback(error, null);
}
},
});
const chatClient = new AblyChat.ChatClient(realtime);
</script>Instantiate a client
Authentication is configured on the Ably Pub/Sub client, which the Chat client wraps. The Chat SDK itself doesn't handle authentication directly - it uses the authenticated connection from the underlying Pub/Sub client.
Instantiate a realtime client using the Pub/Sub SDK and pass the generated client into the Chat constructor.
Client-side authentication (recommended)
Use token authentication for browsers and mobile apps. Your auth server endpoint validates the user and returns an Ably token with the appropriate clientId:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Client-side: Token authentication (recommended for browsers)
import { LogLevel } from '@ably/chat'
const realtimeClient = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-token');
const token = await response.text();
callback(null, token);
} catch (error) {
callback(error, null);
}
},
});
const chatClient = new ChatClient(realtimeClient, { logLevel: LogLevel.Error });Your auth server endpoint (/api/ably-token) should authenticate the user and return a token. See the token authentication documentation for server implementation examples.
Server-side authentication
For server-side applications or local development, you can use an API key directly:
1
2
3
4
5
6
7
8
9
// Server-side only: API key authentication
// WARNING: Never use this in client-side code (browsers, mobile apps)
import { LogLevel } from '@ably/chat'
const realtimeClient = new Ably.Realtime({
key: process.env.ABLY_API_KEY,
clientId: 'server-process-1',
});
const chatClient = new ChatClient(realtimeClient, { logLevel: LogLevel.Error });A ClientOptions object may be passed to the Pub/Sub SDK instance to further customize the connection. When using token authentication, the clientId is set by your auth server. When using API key authentication server-side, you must provide a clientId to ensure that the client is identified.
Using Ably JWT (alternative)
If you have existing JWT-based authentication infrastructure (Auth0, Firebase, Cognito, or custom), you can create Ably JWTs directly without using the Ably SDK on your server:
Server (no Ably SDK required)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import jwt from 'jsonwebtoken';
const [keyName, keySecret] = process.env.ABLY_API_KEY.split(':');
app.get('/api/ably-jwt', async (req, res) => {
// Your existing auth middleware validates the user
const userId = req.user.id;
const ablyJwt = jwt.sign(
{
'x-ably-capability': JSON.stringify({
'*': ['publish', 'subscribe', 'presence', 'history'],
}),
'x-ably-clientId': userId,
},
keySecret,
{ algorithm: 'HS256', keyid: keyName, expiresIn: '1h' }
);
res.send(ablyJwt);
});Client
1
2
3
4
5
6
7
8
9
10
11
12
const realtimeClient = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
try {
const response = await fetch('/api/ably-jwt');
const jwt = await response.text();
callback(null, jwt);
} catch (error) {
callback(error, null);
}
},
});
const chatClient = new ChatClient(realtimeClient);Why choose JWT for Chat?
- No Ably SDK required on your server
- Integrates with existing Auth0/Firebase/Cognito flows
- Supports channel-scoped claims for user roles in chat rooms
- Eliminates client round-trip to Ably
See Token authentication for detailed guidance on when to use JWT vs Ably Tokens.
Additional options can also be passed to the Chat client to customize the following properties:
| Property | Description |
|---|---|
logHandler | The function to call for each line of log output. The default is console.log. |
logLevel | The verbosity of the log output. Options are; trace, debug, info, warn, error or silent. The default is error. |
Logging
Set the logHandler and logLevel properties when instantiating a client to configure your log handler:
1
2
3
4
5
6
7
8
// Using token authentication (recommended for client-side)
const ably = new Ably.Realtime({
authCallback: async (tokenParams, callback) => {
const response = await fetch('/api/ably-token');
callback(null, await response.text());
},
});
const chatClient = new ChatClient(ably, {logHandler: logWriteFunc, logLevel: 'debug' });The logHandler property is your own function that will be called for each line of log output generated by the Chat SDK.
The logLevel sets the verbosity of logs that will be output by the SDK. The following log levels are available to set:
| Level | Description |
|---|---|
trace | Something routine and expected has occurred. This level will provide logs for the vast majority of operations and function calls. |
debug | Development information, messages that are useful when trying to debug library behavior, but superfluous to normal operation. |
info | Informational messages. Operationally significant to the library but not out of the ordinary. |
warn | Anything that is not immediately an error, but could cause unexpected behavior in the future. For example, passing an invalid value to an option. Indicates that some action should be taken to prevent future errors. |
error | A given operation has failed and cannot be automatically recovered. The error may threaten the continuity of operation. |
silent | No logging will be performed. |