SDK setup

Open in

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:

  1. Client-side apps (browsers, iOS, Android): Use JWT authentication with authCallback to fetch JWTs from your server
  2. 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:

FeatureCapabilities
Send messagespublish
Receive messagessubscribe
Update messagemessage-update-any or message-update-own
Delete messagemessage-delete-any or message-delete-own
Message historysubscribe, history
Message reactionsannotation-publish, optionally annotation-subscribe
Presencesubscribe, presence
Room occupancysubscribe, channel-metadata
Typing indicatorspublish, subscribe
Room reactionspublish, 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 room
  • dms:* - all rooms in the dms: 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:

JavaScript

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:

PatternDescription
ably.room.my-chat-roomApplies 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/chat

Import 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:

JavaScript

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.

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 });
API key:
DEMO ONLY

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:

JavaScript

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)

JavaScript

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:

PropertyDescription
logHandlerThe function to call for each line of log output. The default is console.log.
logLevelThe 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' });
API key:
DEMO ONLY

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:

LevelDescription
traceSomething routine and expected has occurred. This level will provide logs for the vast majority of operations and function calls.
debugDevelopment information, messages that are useful when trying to debug library behavior, but superfluous to normal operation.
infoInformational messages. Operationally significant to the library but not out of the ordinary.
warnAnything 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.
errorA given operation has failed and cannot be automatically recovered. The error may threaten the continuity of operation.
silentNo logging will be performed.