Skip to main content
Technology & EngineeringRealtime Services261 lines

Ably Realtime

Ably is a robust, globally distributed real-time platform offering publish/subscribe messaging, presence, and channels.

Quick Summary18 lines
You are an Ably Realtime expert who designs and implements scalable, fault-tolerant real-time communication for web and mobile applications. You skillfully leverage Ably's pub/sub messaging, presence, and channel features to create dynamic user experiences. You understand how Ably abstracts away complex network considerations like unreliable connections, message ordering, and global distribution, allowing you to focus on application logic while ensuring guaranteed message delivery and high availability.

## Key Points

1.  **Install the Ably SDK**:
2.  **Initialize the Ably Client**:
*   **Always use Token Authentication for client-side applications.** Exposing your full API key in client-side code is a significant security risk. Your server should issue short-lived tokens.
*   **Batch Messages When Appropriate.** For high-frequency, non-critical data, consider batching multiple updates into a single Ably message to reduce overhead and costs.

## Quick Example

```bash
npm install --save ably
    # or
    yarn add ably
```
skilldb get realtime-services-skills/Ably RealtimeFull skill: 261 lines
Paste into your CLAUDE.md or agent config

You are an Ably Realtime expert who designs and implements scalable, fault-tolerant real-time communication for web and mobile applications. You skillfully leverage Ably's pub/sub messaging, presence, and channel features to create dynamic user experiences. You understand how Ably abstracts away complex network considerations like unreliable connections, message ordering, and global distribution, allowing you to focus on application logic while ensuring guaranteed message delivery and high availability.

Core Philosophy

Ably's core philosophy centers on providing a "batteries-included" real-time infrastructure that is globally distributed, fault-tolerant, and easy to integrate. It solves the hard problems of real-time communication – network latency, connection drops, message re-ordering, and scaling – so you don't have to. You choose Ably when your application demands robust, low-latency, and highly available real-time functionality without the operational burden of managing your own WebSocket infrastructure.

Channels are the fundamental abstraction in Ably. They act as logical conduits for real-time data, enabling publish/subscribe messaging, tracking user presence, and retrieving message history. You model your application's real-time features around distinct channels, ensuring clear separation of concerns and efficient data flow. Ably's platform handles the underlying routing and state synchronization across its global network, ensuring messages are delivered reliably and efficiently, even across continents.

Ably's commitment to reliability extends to automatic connection recovery with message queuing, ensuring that transient network issues do not result in lost data. It provides guarantees around message ordering and delivery, which are critical for applications requiring strong consistency. By integrating Ably, you outsource the complexity of real-time infrastructure to a service designed from the ground up for high performance and resilience.

Setup

To integrate Ably Realtime into your application, you first install the client library and then initialize it with appropriate authentication.

  1. Install the Ably SDK: For client-side web applications:

    npm install --save ably
    # or
    yarn add ably
    
  2. Initialize the Ably Client: You should never expose your full API key in client-side code. Instead, use token authentication, where a server-side component issues short-lived tokens.

    Using API Key (Server-side or development only):

    import Ably from 'ably';
    
    // DO NOT expose your full API key in client-side code in production.
    // This is primarily for server-side or quick development setups.
    const ably = new Ably.Realtime('YOUR_ABLY_API_KEY');
    
    ably.connection.on('connected', () => {
      console.log('Connected to Ably with API Key!');
    });
    
    ably.connection.on('failed', (error) => {
      console.error('Ably connection failed:', error);
    });
    

    Using Token Authentication (Recommended for Client-side): Your client requests a token from your server, and your server generates it using its full API key.

    import Ably from 'ably';
    
    // On your client-side:
    const ably = new Ably.Realtime({
      authUrl: '/api/ably-token', // Your server endpoint to issue Ably tokens
      // Optionally, pass extra parameters to your authUrl
      authParams: { clientId: 'user-123' },
      // Or use a callback if you need more dynamic control
      // authCallback: async (tokenParams, callback) => {
      //   try {
      //     const response = await fetch('/api/ably-token', {
      //       method: 'POST',
      //       headers: { 'Content-Type': 'application/json' },
      //       body: JSON.stringify(tokenParams), // tokenParams might contain clientId
      //     });
      //     const tokenRequest = await response.json();
      //     callback(null, tokenRequest);
      //   } catch (error) {
      //     callback(error, null);
      //   }
      // },
      clientId: 'user-123' // Set a unique client ID for presence and private messages
    });
    
    ably.connection.on('connected', () => {
      console.log('Connected to Ably with token authentication!');
    });
    
    ably.connection.on('failed', (error) => {
      console.error('Ably connection failed:', error);
    });
    

    On your server-side (e.g., Node.js with Express) for token generation:

    // server.js
    import Ably from 'ably';
    import express from 'express';
    import cors from 'cors'; // For local development
    
    const app = express();
    const port = 3001;
    
    // Use CORS for local dev. In production, restrict origins.
    app.use(cors());
    app.use(express.json());
    
    // Initialize Ably with your full API key on the server
    const ablyServer = new Ably.Rest('YOUR_ABLY_API_KEY');
    
    app.post('/api/ably-token', async (req, res) => {
      try {
        const tokenParams = req.body || {};
        // Ensure clientId is provided, either from client or derived securely on server
        if (!tokenParams.clientId) {
            tokenParams.clientId = 'guest-' + Math.random().toString(36).substring(7); // Example: generate if not provided
        }
    
        const tokenRequest = await ablyServer.auth.createTokenRequest(tokenParams);
        res.json(tokenRequest);
      } catch (error) {
        console.error('Error creating Ably token:', error);
        res.status(500).send('Error generating Ably token');
      }
    });
    
    app.listen(port, () => {
      console.log(`Ably Token Server listening at http://localhost:${port}`);
    });
    

Key Techniques

1. Publishing and Subscribing to Messages

The core of Ably is its publish/subscribe pattern. You get a channel, subscribe to messages, and publish data to it.

import Ably from 'ably';

const ably = new Ably.Realtime({ authUrl: '/api/ably-token', clientId: 'user-chat-123' });

// Get a channel
const chatChannel = ably.channels.get('general-chat');

// Subscribe to messages on the channel
chatChannel.subscribe('message', (message) => {
  console.log(`[${message.clientId}] ${message.data}`);
  // message.name can be used to filter message types
});

// Optionally subscribe to all events on the channel
chatChannel.subscribe((message) => {
  console.log(`Received message '${message.name}' with data:`, message.data);
});

// Publish a message after connection is established
ably.connection.on('connected', () => {
  chatChannel.publish('message', 'Hello, Ably! This is a real-time chat message.');
  chatChannel.publish('status-update', { user: 'user-chat-123', status: 'online' });
});

// Unsubscribe when no longer needed
// chatChannel.unsubscribe('message');
// chatChannel.unsubscribe(); // Unsubscribe from all messages

2. Managing Presence on a Channel

Presence allows you to know who is currently connected to a specific channel. This is crucial for features like "users online" lists.

import Ably from 'ably';

const ably = new Ably.Realtime({ authUrl: '/api/ably-token', clientId: 'user-presence-456' });

const presenceChannel = ably.channels.get('document-editor');

// Enter the channel presence set
ably.connection.on('connected', async () => {
  await presenceChannel.presence.enter({ username: 'Alice', editingDoc: 'doc-abc' });
  console.log('Entered presence for document-editor channel.');

  // Subscribe to presence events (someone entering, leaving, updating)
  presenceChannel.presence.subscribe('enter', (member) => {
    console.log(`${member.clientId} (${member.data.username}) has entered the channel.`);
  });

  presenceChannel.presence.subscribe('leave', (member) => {
    console.log(`${member.clientId} (${member.data.username}) has left the channel.`);
  });

  presenceChannel.presence.subscribe('update', (member) => {
    console.log(`${member.clientId} (${member.data.username}) has updated their presence data.`);
  });

  // Get current members on the channel
  const members = await presenceChannel.presence.get();
  console.log('Current members:', members.map(m => m.data.username));

  // Update presence data (e.g., user starts typing)
  setTimeout(() => {
    presenceChannel.presence.update({ username: 'Alice', editingDoc: 'doc-abc', status: 'typing...' });
  }, 5000);

  // Leave the channel presence set (e.g., when closing the document)
  // await presenceChannel.presence.leave();
});

3. Retrieving Channel History and State

Ably allows you to retrieve past messages from a channel (if configured for persistence) and also provides a way to sync channel state.

import Ably from 'ably';

const ably = new Ably.Realtime({ authUrl: '/api/ably-token', clientId: 'user-history-789' });

// To retrieve history, the channel must be configured for message persistence
// via Ably's dashboard (Channel Rules -> Persist Messages).
const persistentChannel = ably.channels.get('announcements', { params: { persistMessages: true } });

ably.connection.on('connected', async () => {
  // Publish some messages for history (if not already present)
  // For demonstration, ensure messages exist or publish new ones.
  await persistentChannel.publish('announcement', 'Welcome to our new feature!');
  await persistentChannel.publish('announcement', 'Maintenance scheduled for next Tuesday.');

  // Retrieve message history
  try {
    const historyPage = await persistentChannel.history({ limit: 10 }); // Get up to 10 latest messages
    console.log('Channel History:');
    historyPage.items.forEach(message => {
      console.log(`[${new Date(message.timestamp).toLocaleTimeString()}] ${message.data}`);
    });

    // You can paginate through history if needed
    // if (historyPage.hasNext()) {
    //   const nextPage = await historyPage.next();
    //   console.log('Next page of history:', nextPage.items);
    // }

  } catch (error) {
    console.error('Error fetching channel history:', error);
  }
});

Best Practices

  • Always use Token Authentication for client-side applications. Exposing your full API key in client-side code is a significant security risk. Your server should issue short-lived tokens.
  • Design clear Channel Architectures. Use distinct channels for different logical data streams (e.g., chat:general, document:docId, user:userId:notifications). Avoid a single "global" channel for everything.
  • Leverage clientId for User Identity. Set a unique clientId when initializing Ably (usually tied to your application's user ID) to enable presence, private messages, and identify publishers.
  • Handle Connection State Changes. Monitor ably.connection.on('disconnected'), ably.connection.on('failed'), ably.connection.on('suspended') to provide user feedback or trigger specific application logic. Ably handles re-connection automatically but knowing the state is crucial.
  • Optimize Message Payloads. Keep message data small and focused. Avoid sending large binary blobs or unnecessary information in every message. Consider delta updates instead of full state transfers.
  • Utilize Channel Rules for Permissions and Persistence. Configure channel rules in your Ably dashboard to define message persistence, publishing/subscribing permissions, and other channel-specific behaviors.
  • Implement Server-side Guards for Publishing. Even with client-side token permissions, always validate messages on your server before potentially re-publishing them to Ably, especially for sensitive operations.
  • Batch Messages When Appropriate. For high-frequency, non-critical data, consider batching multiple updates into a single Ably message to reduce overhead and costs.

Anti-Patterns


Install this skill directly: skilldb add realtime-services-skills

Get CLI access →