jpskill.com
🛠️ 開発・MCP コミュニティ

using-ably

Ablyを使ってリアルタイム機能(メッセージング、チャット、コラボレーションなど)を構築する際に、製品やSDKの選択、認証、チャンネル設計、React連携、よくある間違いなどを適切に判断し、最適な実装を支援するSkill。

📜 元の英語説明(参考)

ALWAYS use when building realtime features with Ably — messaging, chat, collaboration, presence, or AI token streaming. Covers product and SDK selection (Pub/Sub vs Chat vs Spaces vs LiveObjects), authentication (JWT, token auth, authUrl), channel design, React integration, and critical mistakes like missing Chat attach(), client-side API key exposure, and creating Ably clients inside components. Fetches current docs from ably.com/llms.txt before generating code. Not for general WebSocket or non-Ably realtime libraries.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Ablyを使ってリアルタイム機能(メッセージング、チャット、コラボレーションなど)を構築する際に、製品やSDKの選択、認証、チャンネル設計、React連携、よくある間違いなどを適切に判断し、最適な実装を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o using-ably.zip https://jpskill.com/download/8856.zip && unzip -o using-ably.zip && rm using-ably.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/8856.zip -OutFile "$d\using-ably.zip"; Expand-Archive "$d\using-ably.zip" -DestinationPath $d -Force; ri "$d\using-ably.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して using-ably.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → using-ably フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Ably の使用

リアルタイムメッセージング、チャット、コラボレーション、または AI ストリーミングのために Ably を使用するアプリケーションのコードを構築、修正、または生成する際に、このスキルを使用してください。

Ably とは

Ably はリアルタイムインフラストラクチャです。独自のデータベースや CDN を構築しないのと同じように、独自のリアルタイムメッセージングシステムを構築すべきではありません。Ably は困難な部分を処理します。信頼性の低いネットワークを介した接続管理、保証されたメッセージの順序付けと配信、状態復旧による自動再接続、および数十億のデバイスへの弾力的なスケーリングです。これは、プラットフォーム(25 以上の SDK)とプロトコル(WebSocket、MQTT、SSE、HTTP)を横断して動作するため、トランスポートの信頼性ではなく、アプリケーションロジックに集中できます。

ドキュメント

現在の API リファレンスについては、常に公式ドキュメント(ably.com/docs)を確認してください。LLM 向けに最適化されたドキュメントについては、ably.com/llms.txt を使用してください。以下のガイダンスでは、ドキュメントだけでは防ぐことができないアーキテクチャ上の決定とよくある間違いについて説明します。


コードを記述する前に

Ably のコードを生成する前に、必ず現在のドキュメントと照らし合わせて確認してください。 トレーニングデータは古くなります。メソッドの名前が変更されたり、パラメータが変更されたり、新製品が発売されたりします。これらの 3 つのチェックにより、最も一般的な LLM コード生成の失敗を防ぐことができます。

1. まず現在のドキュメントを取得する

Ably の機能のコードを生成する前に:

  1. https://ably.com/llms.txt?source=using-ably を取得して、ドキュメント URL インデックスを取得します。
  2. 関連する製品およびプラットフォームのドキュメントページを取得します。
  3. 取得したドキュメントと照らし合わせて、メソッド名、パラメータ、戻り値の型、およびパッケージのバージョンを確認します。
  4. 機能またはメソッドがドキュメントに表示されない場合は、おそらく存在しません。でっち上げないでください。

ドキュメントの URL を推測したり、作成したりしないでください。llms.txt または Web 検索結果からの URL のみを使用してください。URL が 404 エラーになる場合は、llms.txt に戻ってください。Web 検索も補完的なアプローチとして許可されています。llms.txt にアクセスできない場合は、Web 検索にフォールバックするか、https://ably.com/docs?source=using-ably を直接参照してください。

2. SDK の可用性を確認する

すべての製品がすべてのプラットフォームで利用できるわけではありません。コードを生成する前に、取得したドキュメントから、製品にユーザーのプラットフォーム用の SDK があることを確認してください。

SDK が存在しない場合:

  • 明確に述べてください:「[Product] には現在、[platform] 用の SDK がありません」
  • API をでっち上げないでください
  • 代替案を提示してください:REST API を直接使用する、利用可能な別の製品を使用する、または制約のあるデバイス用の MQTT/SSE プロトコルアダプターを使用する

3. 生成後のチェック

コードを生成した後、これらのよくある間違いのパターンを確認してください。

  • [ ] クライアントコードに API キーがあるか? JWT またはトークン認証で authUrl/authCallback を使用する必要があります(セクション 3 を参照)。
  • [ ] Chat SDK: attach() の前に subscribe() を行っているか? メッセージがサイレントに失われるのを防ぐために、最初にサブスクライブしてください(セクション 7 を参照)。
  • [ ] React: クリーンアップなしでコンポーネント内に Ably クライアントが作成されているか? 外部で一度作成し、プロバイダーを介して渡すか、適切なクリーンアップで useEffect を使用してください(セクション 8 を参照)。
  • [ ] サーバー側: REST で十分な場合にリアルタイム SDK が使用されているか? パブリッシュ、トークン生成、履歴には、デフォルトで Ably.Rest を使用してください(セクション 2 を参照)。
  • [ ] アンマウント/終了時に接続をクリーンアップしているか? realtime.close() を呼び出してください(セクション 5 を参照)。
  • [ ] 組み込みの動作を再実装しているか? 入力インジケーターのカスタムデバウンス、カーソルのカスタムスロットリング、または LiveObjects のカスタム競合解決を追加しないでください(セクション 9 を参照)。

1. 製品と SDK の状況を理解する

Ably は単一の SDK ではなく、マルチプロダクトプラットフォームです。間違った製品または SDK を選択することが、最も一般的な統合ミスです。

製品レイヤー:何を構築していますか?

製品 ユースケース SDK
Pub/Sub コアメッセージング:ライブダッシュボード、通知、IoT、イベントストリーミング ably (Realtime または REST)
AI Transport LLM トークンのストリーミング、マルチエージェントの連携、再開可能な AI セッション ably (Realtime)
LiveObjects 共有の可変状態:カウンター、キーと値のマップ、コラボレーティブデータ ably + LiveObjects プラグイン
LiveSync データベースからフロントエンドへの同期(PostgreSQL 変更ストリーム) @ably-labs/models + ADBC コネクター
Chat チャットルーム、入力インジケーター、リアクション、メッセージ履歴、モデレーション @ably/chat
Spaces コラボレーティブカーソル、アバタースタック、メンバーの場所、コンポーネントロック @ably/spaces

SDK アーキテクチャ:2 つのレイヤー

レイヤー 1 — コア SDK (Pub/Sub、AI Transport、LiveObjects、LiveSync で直接使用):

SDK 使用する場合 接続
Ably.Realtime クライアントがメッセージ、プレゼンス、または状態の変更をサブスクライブする必要がある 永続的な WebSocket
Ably.Rest サーバー側のパブリッシュのみ、トークン生成、履歴クエリ ステートレス HTTP

これらは基礎です。AI Transport、LiveObjects、および LiveSync はすべて、コア Realtime SDK を直接使用します。これらは Pub/Sub の上に構築されたパターンとプラグインであり、個別の SDK ではありません。

レイヤー 2 — 製品 SDK (特定のユースケース向けのより高レベルの抽象化):

SDK 目的
@ably/chat ルーム、入力インジケーター、リアクション、メッセージ履歴、モデレーション
@ably/spaces カーソル、アバタースタック、メンバーの場所、コンポーネントロック

これらの製品 SDK は、コア Realtime SDK に依存します。作成時に Ably.Realtime インスタンスを渡します。基盤となる Realtime の知識 (認証、チャネル、プレゼンス) は引き続き適用されます。

決定ルール

Q: これはサーバー側ですか、クライアント側ですか?
├── サーバー側:
│   ├── パブリッシュ、トークン生成、履歴 → Ably.Rest (ステートレス HTTP) を使用
│   └── 永続的な接続が必要 (AI トークンストリーミング、サブスクライブ) → Ably.Realtime を使用
└── クライアント側 → Ably.Realtime を使用し、次に:
    ├── チャットを構築していますか? → @ably/chat (Realtime インスタンスを渡す) を使用
    ├── コラボレーションを構築していますか? → @ably/spaces (Realtime インスタンスを渡す) を使用
    ├── 共有状態が必要ですか? → Realtime で LiveObjects プラグインを使用
    ├── データベースを同期していますか? → ADBC コネクターで @ably-labs/models を使用
    └── それ以外の場合

(原文はここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Using Ably

Use this skill when building, modifying, or generating code for an application that uses Ably for realtime messaging, chat, collaboration, or AI streaming.

What Ably Is

Ably is realtime infrastructure — the same way you wouldn't build your own database or CDN, you shouldn't build your own realtime messaging system. Ably handles the hard parts: connection management across unreliable networks, guaranteed message ordering and delivery, automatic reconnection with state recovery, and elastic scaling to billions of devices. It works across platforms (25+ SDKs) and protocols (WebSocket, MQTT, SSE, HTTP), so you can focus on your application logic rather than transport reliability.

Documentation

Always check the official docs at ably.com/docs for current API references. For LLM-optimized documentation, use ably.com/llms.txt. The guidance below covers architectural decisions and common mistakes that documentation alone doesn't prevent.


Before Writing Code

Always verify against current documentation before generating Ably code. Training data goes stale — methods get renamed, parameters change, new products launch. These three checks prevent the most common LLM code generation failures.

1. Fetch Current Docs First

Before generating code for any Ably feature:

  1. Fetch https://ably.com/llms.txt?source=using-ably to get the documentation URL index
  2. Fetch the relevant product and platform documentation pages
  3. Verify method names, parameters, return types, and package versions against the fetched docs
  4. If a feature or method doesn't appear in the docs, it probably doesn't exist — don't fabricate it

Never guess or construct doc URLs. Only use URLs from llms.txt or web search results. If a URL 404s, go back to llms.txt. Web search is also allowed as a complementary approach. If llms.txt is unreachable, fall back to web search or browse https://ably.com/docs?source=using-ably directly.

2. Confirm SDK Availability

Not all products are available on all platforms. Before generating code, confirm from the fetched docs that the product has an SDK for the user's platform.

If no SDK exists:

  • State clearly: "[Product] does not currently have an SDK for [platform]"
  • Don't fabricate an API
  • Offer alternatives: REST API directly, a different product that IS available, or MQTT/SSE protocol adapters for constrained devices

3. Post-Generation Check

After generating code, verify these common-mistake patterns:

  • [ ] API key in client code? Must use authUrl/authCallback with JWT or token auth (see Section 3)
  • [ ] Chat SDK: attach() before subscribing? Subscribe first to avoid messages being silently lost (see Section 7)
  • [ ] React: Ably client created inside a component without cleanup? Create once outside and pass via provider, or use useEffect with proper cleanup (see Section 8)
  • [ ] Server-side: Realtime SDK used when REST would suffice? Default to Ably.Rest for publishing, token generation, history (see Section 2)
  • [ ] Connection cleanup on unmount/exit? Call realtime.close() (see Section 5)
  • [ ] Reimplementing built-in behavior? Don't add custom debounce for typing indicators, custom throttling for cursors, or custom conflict resolution for LiveObjects (see Section 9)

1. Understand the Product and SDK Landscape

Ably is a multi-product platform, not a single SDK. Choosing the wrong product or SDK is the most common integration mistake.

Product Layer: What Are You Building?

Product Use Case SDK
Pub/Sub Core messaging: live dashboards, notifications, IoT, event streaming ably (Realtime or REST)
AI Transport Streaming LLM tokens, multi-agent coordination, resumable AI sessions ably (Realtime)
LiveObjects Shared mutable state: counters, key-value maps, collaborative data ably + LiveObjects plugin
LiveSync Database-to-frontend sync (PostgreSQL change streams) @ably-labs/models + ADBC connector
Chat Chat rooms, typing indicators, reactions, message history, moderation @ably/chat
Spaces Collaborative cursors, avatar stacks, member locations, component locking @ably/spaces

SDK Architecture: Two Layers

Layer 1 — Core SDKs (used directly for Pub/Sub, AI Transport, LiveObjects, LiveSync):

SDK Use When Connection
Ably.Realtime Client needs to subscribe to messages, presence, or state changes Persistent WebSocket
Ably.Rest Server-side publish only, token generation, history queries Stateless HTTP

These are the foundation. AI Transport, LiveObjects, and LiveSync all use the core Realtime SDK directly — they are patterns and plugins on top of Pub/Sub, not separate SDKs.

Layer 2 — Product SDKs (higher-level abstractions for specific use cases):

SDK Purpose
@ably/chat Rooms, typing indicators, reactions, message history, moderation
@ably/spaces Cursors, avatar stacks, member locations, component locking

These product SDKs depend on the core Realtime SDK. You pass an Ably.Realtime instance when creating them. The underlying Realtime knowledge (auth, channels, presence) still applies.

Decision Rules

Q: Is this server-side or client-side?
├── Server-side:
│   ├── Publishing, token generation, history → Use Ably.Rest (stateless HTTP)
│   └── Need persistent connection (AI token streaming, subscribing) → Use Ably.Realtime
└── Client-side → Use Ably.Realtime, then:
    ├── Building chat? → Use @ably/chat (pass Realtime instance)
    ├── Building collaboration? → Use @ably/spaces (pass Realtime instance)
    ├── Need shared state? → Use LiveObjects plugin with Realtime
    ├── Syncing database? → Use @ably-labs/models with ADBC connector
    └── Otherwise → Use Ably.Realtime directly (Pub/Sub, AI Transport)

Server-side rule of thumb: Default to Ably.Rest for server operations. Only use Ably.Realtime on the server when you genuinely need a persistent connection — for example, an AI agent streaming tokens to clients, or a backend service that subscribes to events.

Common Mistakes

// WRONG: Using REST SDK then polling for messages
const rest = new Ably.Rest({ key: '...' });
setInterval(async () => {
  const history = await rest.channels.get('updates').history();
}, 1000);

// RIGHT: Using Realtime SDK to subscribe
const realtime = new Ably.Realtime({ key: '...' });
realtime.channels.get('updates').subscribe((msg) => {
  console.log('Received:', msg.data);
});

// WRONG: Using raw Pub/Sub for chat when Chat SDK exists
const channel = realtime.channels.get('chat-room');
channel.subscribe((msg) => { /* manually handling typing, reactions, history... */ });

// RIGHT: Using Chat SDK which handles all chat patterns
import { ChatClient } from '@ably/chat';
const chat = new ChatClient(realtime);
const room = await chat.rooms.get('my-room');
room.messages.subscribe((msg) => console.log(msg.text));
await room.typing.keystroke(); // built-in typing indicators

2. Use Modern SDK Patterns (v2.x)

Ably's JavaScript SDK v2.x uses async/await. Never generate callback-style 1.x patterns.

// WRONG: Old 1.x callback pattern (deprecated)
const channel = realtime.channels.get('updates');
channel.subscribe('event', function(message) {
  console.log(message.data);
});
channel.publish('event', { text: 'hello' }, function(err) {
  if (err) console.error(err);
});

// RIGHT: Modern 2.x async/await pattern
const channel = realtime.channels.get('updates');
channel.subscribe('event', (message) => {
  console.log(message.data);
});
await channel.publish('event', { text: 'hello' });

Imports and initialization — keep it simple:

// RIGHT: Standard ESM import
import Ably from 'ably';
const realtime = new Ably.Realtime({ key: 'your-key' });
const rest = new Ably.Rest({ key: 'your-key' });

// RIGHT: Chat SDK import
import { ChatClient } from '@ably/chat';

// WRONG: Don't invent type-based initialization
const options: Ably.Types.ClientOptions = { ... }; // unnecessary

If you hit ESM/CommonJS import errors, check that your tsconfig.json has "moduleResolution": "bundler" or "node16", and that you're importing from 'ably' (not subpaths). Don't try multiple import strategies — check the SDK README for your environment.

Server-side: Default to REST SDK. Only use Ably.Realtime on the server when you need a persistent connection.

// WRONG: Realtime SDK on server just to publish
const realtime = new Ably.Realtime({ key: '...' }); // opens WebSocket unnecessarily
await realtime.channels.get('events').publish('update', data);

// RIGHT: REST SDK for server-side publish
const rest = new Ably.Rest({ key: '...' }); // stateless HTTP
await rest.channels.get('events').publish('update', data);

// RIGHT: Realtime on server for AI streaming (message-per-response pattern)
// See ably.com/docs/ai-transport/token-streaming/message-per-response?source=using-ably
const channel = realtime.channels.get('conversation:123');
const { serials: [msgSerial] } = await channel.publish({ name: 'response', data: '' });
for await (const event of llmStream) {
  if (event.type === 'token') {
    channel.appendMessage({ serial: msgSerial, data: event.text });
  }
}

3. Authentication

API keys are for server-side only. Never expose them to clients.

API keys don't expire. If leaked, attackers have indefinite access until you regenerate the key.

Recommended: JWT Authentication

JWT is the recommended authentication method for client-side applications.

Why JWT over Ably tokens:

  • No round-trip to Ably servers — your backend creates and signs the JWT directly
  • Integrates with existing auth systems — uses standard JWT libraries you already have
  • Capabilities defined per-token — not limited to what's configured on the API key
  • Works everywhere — including environments without an Ably SDK (MQTT, embedded devices)

JWT Claims:

  • kid (header): Your Ably API key name (e.g., xVLyHw.abcdef)
  • iat: Issued-at timestamp (seconds)
  • exp: Expiration timestamp (seconds)
  • x-ably-capability: JSON string of channel permissions
  • x-ably-clientId (optional): Client identity for presence
// Server-side: Create JWT for client
import jwt from 'jsonwebtoken';

app.post('/api/ably-auth', (req, res) => {
  const apiKey = process.env.ABLY_API_KEY; // 'appId.keyId:keySecret'
  const [keyName, keySecret] = apiKey.split(':');

  const token = jwt.sign(
    {
      'x-ably-capability': JSON.stringify({
        'room:*': ['subscribe', 'publish', 'presence'],
        [`notifications:${req.user.id}`]: ['subscribe'],
      }),
      'x-ably-clientId': req.user.id,
    },
    keySecret,
    {
      expiresIn: '1h',
      keyid: keyName,
    }
  );

  res.json(token);
});

// Client-side: Use JWT with Ably
const realtime = new Ably.Realtime({
  authUrl: '/api/ably-auth',
  authMethod: 'POST',
});

Alternative: Ably Token Requests

JWT is recommended for most use cases, but Ably tokens may be preferred when your capability list is too large for JWT size limits (JWTs must fit within HTTP headers, ~8KB), or when you need to keep capabilities confidential since JWTs can be decoded by clients. The trade-off is that Ably token integration is more involved and doesn't support all JWT functionality like channel-scoped claims and per-connection rate limits.

// Ably's native token system (requires round-trip to Ably servers from backend)
app.post('/api/ably-token', (req, res) => {
  const client = new Ably.Rest({ key: process.env.ABLY_API_KEY });
  client.auth.createTokenRequest({
    clientId: req.user.id,
    capability: { 'room:*': ['subscribe', 'publish'] },
  }).then(tokenRequest => res.json(tokenRequest));
});

Rules

  • Server-side: API key is fine ({ key: 'appId.keyId:keySecret' })
  • Client-side: Always use authUrl or authCallback — never embed the API key or pass a static token directly (it won't auto-refresh on expiry)
  • Set clientId if you need presence features — it's required for presence
  • Use capabilities to restrict what channels and operations each client can access

4. Channel Design

Channels separate messages into topics. Get the naming right early — it's hard to change later.

Rules:

  • Use : as a hierarchy separator: chat:room-123, orders:user-456
  • Channel names are case-sensitive
  • Don't create one channel per message — channels are long-lived topics
  • Use rules in the dashboard to apply settings (e.g., persistence, push notifications) to groups of channels

Common patterns:

chat:room-{roomId}           # Chat rooms
notifications:user-{userId}  # Per-user notifications
cursors:doc-{docId}          # Collaborative editing
events:{eventType}           # Event streaming
conversation:{sessionId}     # AI Transport sessions

5. Connection Management

The Realtime SDK manages reconnection automatically. Don't fight it.

Rules:

  • Don't manually reconnect — the SDK handles transient failures with exponential backoff
  • Listen to connection state changes to update UI:
realtime.connection.on('connected', () => { /* online */ });
realtime.connection.on('disconnected', () => { /* temporarily offline */ });
realtime.connection.on('suspended', () => { /* offline for extended period */ });
  • Call realtime.close() when done (component unmount, page unload, etc.)
  • Messages published while disconnected are received on reconnection (within the 2-minute recovery window)
  • For AI Transport (client-side): use channel rewind to hydrate returning clients with recent messages:
const channel = realtime.channels.get('conversation:123', {
  params: { rewind: '2m' }  // Replay last 2 minutes on attach
});

6. Presence

Presence tracks which clients are on a channel. Use it for "who's online" features.

Rules:

  • Set clientId during auth — it's required for presence
  • Call channel.presence.enter() to join, channel.presence.update() to update data, channel.presence.leave() to depart
  • Use channel.presence.get() for current members, channel.presence.subscribe() for changes
  • If a client disconnects ungracefully, Ably removes them after ~15 seconds (not instantly)
  • Don't use presence for high-frequency data (cursor positions, typing coordinates) — use channels instead. Presence is for low-frequency state (online/offline, user status)
  • For Chat: use room.presence instead of raw channel presence
  • For Spaces: use space.enter() / useMembers() hook. Spaces has dedicated cursors API for cursor positions

7. Chat SDK: Critical Lifecycle

If using @ably/chat, these are the most common mistakes:

Always subscribe before calling attach(). Attaching without subscribing first causes silent message loss — the worst kind of bug.

const room = await chat.rooms.get('my-room');

// WRONG: Attach without subscribing first — messages silently lost
await room.attach();
room.messages.subscribe((msg) => console.log(msg.text)); // may miss messages during attach

// RIGHT: Subscribe first, then attach
room.messages.subscribe((msg) => console.log(msg.text));
await room.attach();

Use the actual API. The Chat SDK does NOT have: threading, read receipts, file attachments, or room.messages.broadcast(). Use room.messages.send() to send messages.

Don't mix Chat and Pub/Sub patterns. If you're using @ably/chat, use room.messages, room.typing, room.reactions — not raw channel.subscribe() / channel.publish().

Built-in behavior you don't need to reimplement:

  • Typing indicator frequency control is handled by the SDK automatically
  • Room reactions delivery is handled by the SDK
  • Message ordering and history pagination are built-in

8. React Integration

Ably provides React hooks for each product:

Product Package Key Hooks
Pub/Sub ably/react useChannel, usePresence, useConnectionStateListener
Chat @ably/chat/react useMessages, useTyping, usePresence, useRoomReactions
Spaces @ably/spaces/react useMembers, useCursors, useLocations, useLocks

Critical rule: Don't create a new Ably client on every render. This creates a new WebSocket connection each time — a memory leak.

// WRONG: Creates new connection every render — memory leak
function Chat() {
  const ably = new Ably.Realtime({ authUrl: '/api/ably-auth' });
  // ...
}

// RIGHT: Create client once, pass via provider
const ably = new Ably.Realtime({ authUrl: '/api/ably-auth' });

function App() {
  return (
    <AblyProvider client={ably}>
      <ChannelProvider channelName="chat:room-1">
        <Chat />
      </ChannelProvider>
    </AblyProvider>
  );
}

// ALSO RIGHT: Create in useEffect with proper cleanup
function App() {
  const [client, setClient] = useState(null);
  useEffect(() => {
    const ably = new Ably.Realtime({ authUrl: '/api/ably-auth' });
    setClient(ably);
    return () => ably.close();
  }, []);
  // ...
}

9. Spaces and LiveObjects: Built-in Behavior

When using Spaces (@ably/spaces):

  • Cursor position batching is built-in — don't implement custom throttling
  • Member location tracking is built-in via space.locations
  • Component locking handles contention automatically via space.locks

When using LiveObjects:

  • Available data structures are Maps and Counters only (no custom object types)
  • Conflict resolution is built-in — don't implement your own
  • State recovery after reconnection is automatic
  • Prefer the path-based API over the instance API for simplicity

10. LiveSync: Database-to-Frontend

LiveSync connects your database to frontends: Database → ADBC Connector → Ably Channels → Models SDK → Frontend.

Key constraints: PostgreSQL requires logical replication (14+, WAL level change needs restart). MongoDB requires a replica set (no standalone). The Database Connector handles channel mapping automatically once you configure an ingress rule.

Always fetch current LiveSync docs from ably.com/docs/livesync — database permissions and connector configuration change across versions.


11. Production Checklist

Before going to production, verify:

  • [ ] No API keys in client code — use JWT or token auth via authUrl/authCallback
  • [ ] Capabilities are scoped — don't grant {"*":["*"]} to clients; restrict to specific channels and operations
  • [ ] Connection cleanup — call realtime.close() on unmount/unload to avoid connection leaks
  • [ ] Error handling — listen to connection.on('failed') and handle auth failures gracefully
  • [ ] Channel detach — detach from channels you no longer need (channel.detach())
  • [ ] Message size — messages are limited to 64KB by default; if you're hitting this, split payloads or reconsider message design
  • [ ] Idempotent publishing — set unique message IDs when exactly-once delivery matters
  • [ ] echoMessages: false — set this if publishers don't need to receive their own messages (saves bandwidth and cost)
  • [ ] Rate limits — Ably enforces rate limits (e.g., 50 messages/second per channel, 200 channels per connection). If you're hitting them, check your publish frequency and channel fan-out. Read the limits documentation

Error Handling

Ably error codes can be broad (e.g., 40000, 50000) — always read the error message text, not just the code. Every error code has a help page at https://help.ably.io/error/{code}.


12. Quick Reference

Product docs: Pub/Sub | Chat | Spaces | LiveObjects | LiveSync | AI Transport

Platform SDKs: JavaScript, React, Python, Ruby, Java, Kotlin, Swift, .NET, Go, PHP, Flutter — ably.com/docs/sdks

Ably CLI: Install with npm install -g @ably/cli to publish test messages, subscribe to channels, and verify setup. Run ably --help to discover commands.

For API references, start at ably.com/docs.