Retrieving Message History

Ably’s history feature enables you to store messages published on channels that can later be retrieved using the channel history API.

By default, channels will only store messages in memory for up to two minutes. However, using channel rules, you can configure messages published on matching channels to be persisted to disk for typically 24 – 72 hours. Those messages will then be immediately available for retrieval via our Realtime and REST API clients for as long as the message is stored on disk.

Using our history API is trivial. Let’s get started.

You can now persist the last realtime message on a channel for 365 days. Persist last message allows you to instantly retrieve realtime messages sent in the past, helping with long-term state synchronization. Read how to enable persist last message.

Step 1 – Create your Ably app and API key

To follow this tutorial, you will need an Ably account. Sign up for a free account if you don’t already have one.

Access to the Ably global messaging platform requires an API key for authentication. API keys exist within the context of an Ably application and each application can have multiple API keys so that you can assign different capabilities and manage access to channels and queues.

You can either create a new application for this tutorial, or use an existing one.

To create a new application and generate an API key:

  1. Log in to your Ably account dashboard
  2. Click the “Create New App” button
  3. Give it a name and click “Create app”
  4. Copy your private API key and store it somewhere. You will need it for this tutorial.

To use an existing application and API key:

  1. Select an application from “Your apps” in the dashboard
  2. In the API keys tab, choose an API key to use for this tutorial. The default “Root” API key has full access to capabilities and channels.
  3. Copy the Root API key and store it somewhere. You will need it for this tutorial.

    Copy API Key screenshot

Step 2 – Configure message persistence

Channels can be named using any unicode string characters with the only restriction that they cannot start with a [ or : character as these are used as “special” characters. A colon : is used to delimit channel namespaces in a format such as namespace:channel. Namespaces provide a flexible means to group channels together. Channel grouping can be useful when, for example, configuring permissions (capabilities) for a set of channels within a client token or setting up rules to apply to one or more channels.

We will be using channel rules in this tutorial to ensure all channels in the persisted namespace are configured to persist messages to disk i.e. we will explicitly enable the history feature. Follow these steps:

  1. Visit your account dashboard, navigate to the same app you chose in Step 1 when obtaining your API key earlier
  2. Click on the Settings tab and scroll down to the “Channel rules” section
  3. Click the “Add new rule” button (see below)

    Add new channel rule screenshot
  4. Once the modal has opened, enter “persisted” for the namespace, check the Persisted check box to enable history, and click the “Create channel rule” button (see below)

    Create channel rule screenshot

You have now enabled history for all channels in the persisted namespace i.e. any channel with a name matching the pattern persisted:* will store published messages to disk.

Step 3 – Install AblyStep 3 – Setup an Xcode project and install AblyStep 3 – Set up environment and install Ably

To start using Ably in your JRE application, you need to include the Ably Client library. We recommend that you include the latest client library via Gradle in your project’s gradle.build file.

apply plugin: 'application'
mainClassName = 'io.ably.tutorial.Example'

repositories {
  jcenter()
}

dependencies {
    compile 'io.ably:ably-java:1.2.0'
}

In the above example a specific version of the library is referenced, however we recommend you check which is the latest stable version and always use that. Follow link to get the latest stable release for Java.

After you add necessary dependencies, you can import AblyRest class into your code and initialize it.

import io.ably.lib.rest.AblyRest;

public class Example {
  private final static String API_KEY = "INSERT-YOUR-API-KEY-HERE";

  public static void main(String[] args) {
      try {
        initAbly();
      } catch (AblyException e) {
        e.printStackTrace();
      }
  }

  private static void initAbly() throws AblyException {
      AblyRest ablyRest = new AblyRest(API_KEY);
  }
}

See this step in Github

To build your own Android Project, please visit Android Developers website and get familiar with steps necessary to set up your own application.
To start using Ably in your Android app, you need to include the Ably Client library. We recommend that you include the latest client library via Gradle in your module-level gradle.build file.

apply plugin: 'com.android.application'
...
dependencies {
    ...
    compile 'io.ably:ably-android:1.2.0'
}

In the above example a specific version of the library is referenced, however we recommend you check which is the latest stable version and always use that. Follow link to get the latest stable release for Android.

After you add necessary dependencies, you can import AblyRealtime class into your code and initialize it.

import io.ably.lib.realtime.AblyRealtime;

public class ExampleActivity extends AppCompatActivity {
  private final static String API_KEY = "INSERT-YOUR-API-KEY-HERE";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_example);
      try {
          initAbly();
      } catch (AblyException e) {
          e.printStackTrace();
      }
  }

  private void initAbly() throws AblyException {
      AblyRealtime ablyRealtime = new AblyRealtime(API_KEY);
  }
}

See this step in Github

Create a blank HTML page called example.html, to host your web app:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Ably History</title>
  </head>
  <body>
  </body>
</html>

To start using Ably in your web app, you first need to include the Ably client library. In this example, we recommend that you include the latest client library from our CDN using a simple <script> tag. You should then instantiate the client library with the API key you copied in Step 1.

Note: in production, Ably recommends that you always use the token authentication scheme for browser clients, however in this example you will use an API key for simplicity.

Include the code below just before your closing </html> tag.

<script src="https://cdn.ably.com/lib/ably.min-1.js"></script>
<script>
  const apiKey = "YOUR_ABLY_API_KEY"; // Replace with your API key
  const realtime = new Ably.Realtime.Promise({
    key: apiKey
  });
</script>

This code uses the Promise-based version of the Ably client library (Ably.Realtime.Promise) that enables you to use the much tidier await/async syntax, instead of relying on callbacks. It generates a random clientID that will be used to identify this particular client in the presence set.

Below the line that instantiates the Ably client library, create an async function called doHistory() and call it. This is where you will connect to Ably. It is also where you will write the code for the subsequent steps in this tutorial.

<script>
  ...

  async function doHistory() {
    // Connect to Ably
    await realtime.connection.once("connected");
    console.log("Connected to Ably!");
    // Your code goes here
  }
  doHistory();
</script>

To start using Ably you first need to install the Ably RubyGem. The RubyGem can be installed as follows:

gem install ably

Or if using bundler, simply add the following to your Gemfile and run bundle install:

gem 'ably'

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

As we do not need asynchronous access to the realtime API for this tutorial, we’ll be using the simpler REST client library. However, in some cases where users want to subscribe to events asynchronously from Ruby, we recommend the use of the Realtime client library.

require 'ably'
ably = Ably::Rest.new(key: api_key)

See this step in Github

The REST library for Python is hosted on Github and is published on PyPI and can be installed as follows:

pip install ably

Then it can be imported and instantiated as follows:

from ably import AblyRest
client = AblyRest(api_key)

For the purpose of this tutorial let’s create history.py file with the code above, we’ll be using this file as base later on.

Note on string encodings

Since Ably supports both string and binary payloads, to avoid ambiguity, we recommend that strings passed to the library for publishing to Ably (eg as an event name or payload data) should be unicode strings. In Python 3 this is the normal string type, but in Python 2 it is not, so we suggest you prefix string literals with u prefix (eg u'eventname' – or alternatively, use from __future__ import unicode_literals, which will make this automatic), and to explicitly decode any user input (eg raw_input().decode(sys.stdin.encoding).

See this step in Github

To start using Ably you first need to install composer package on packagist into your composer.

composer require ably/ably-php --update-no-dev

The client library must be instantiated with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

Add the following to a file named history.php to instantiate the Ably library inside your php script:

require_once __DIR__ . '/../vendor/autoload.php';
$ably = new \Ably\AblyRest("{{ApiKey}}");

See this step in Github

We will start by creating an Xcode project for this tutorial. To build your own Xcode Project in Swift visit Apple developer website and get familiar with steps necessary to setup your own application.
When you setup your application delete the default ViewController.swift add new File → New → File… and choose Cocoa Touch Class.

Create new Cocoa Touch Class

Name your new class “ExampleViewController” and choose Swift as language:

Name new Cocoa Touch Class

After that navigate to Main.storyboard in your project, click on the ViewController that has already been added by default during project creation and from the Utilities that are located on the right choose Identity Inspector. Find the field labeled “Class” and select “ExampleViewController”.

Interface design

See this step in Github

To start using Ably you first need to install the Ably pod via CocoaPods. You need to add a Podfile to your project directory:

touch Podfile

Then add this line to your application’s Podfile:

pod 'Ably'

Install it with:

pod install

To learn more about using CocoaPods in your project visit official CocoaPods guide.

Then in your files in which you will be using Ably import:

import Ably

To connect to Ably, you need to instantiate the client library with the API key you copied in Step 1. API keys used with basic authentication for your own servers is generally preferred, however clients running on insecure devices should always use the token authentication scheme instead. In this example, we use an API key for simplicity.

Add the following to the file in which you imported the Ably library:

let API_KEY = "INSERT-YOUR-API-KEY-HERE"
let client = ARTRealtime(key: API_KEY)

See this step in Github

Step 4 – Publish messages

Before we can use the history API to retrieve previously published messages, we need to publish some messages to a channel. In the example code below, we publish three messages to the channel.

Channel channel = ablyRest.channels.get("persisted:sounds");

/* Publish three messages, specify event name first, then payload */
channel.publish("play", "bark");
channel.publish("play", "meow");
channel.publish("play", "cluck");

See this step in Github

public class ExampleActivity extends AppCompatActivity {
  ...
  private Channel channel;
  ...
  private void initAbly() throws AblyException {
      ...
      channel = ablyRealtime.channels.get("persisted:sounds");
  }

  private void publishMessages() throws AblyException {
      channel.publish("play", "bark");
      channel.publish("play", "meow");
      channel.publish("play", "cluck");
  }
  ...
}

See this step in Github

const channel = realtime.channels.get("persisted:sounds");
channel.publish("play", "bark");
channel.publish("play", "meow");
channel.publish("play", "cluck");
channel = ably.channels.get('persisted:sounds')
channel.publish 'play', 'bark'
channel.publish 'play', 'meow'
channel.publish 'play', 'cluck'

See this step in Github

$channel = $ably->channels->get("persisted:sounds");
$channel->publish("play", "bark");
$channel->publish("play", "meow");
$channel->publish("play", "cluck");

Now you can check how it works by running php history.php in console.

See this step in Github

channel = client.channels.get('persisted:sounds')
channel.publish('play', 'bark')
channel.publish('play', 'meow')
channel.publish('play', 'cluck')

If you would like to try running this now, you can do so with python history.py.

See this step in Github

If you have not previously had a chance to build a basic user interface in Xcode, please refer to Apple developer guide on how to build a simple UI and also learn more about adding IBOutlets and IBActions.
To be able to subscribe to a channel and send some initial messages add a button that will do that. Go to your ExampleViewController and add an UIButton from Object library. Name the action “publishAction”.

Binding UI objects

Add this code to previously added IBAction:

let channel = client.channels.get("persisted:sounds")
channel.publish("play", data: "bark")
channel.publish("play", data: "meow")
channel.publish("play", data: "cluck")
See this step in Github

Step 5 – Retrieve messages from history

Now that we have published messages on a channel that is configured to store messages on disk, we can retrieve them using the history method of the channel object.

/* Fetch historical messages from channel, you can customize history query with
parameters, when no parameters are needed just pass null */
Message[] historicMessages = channel.history(null).items();
for (Message message : historicMessages) {
    System.out.println("message: " + message.id + " - " + message.data);
}

See this step in Github

private void fetchHistory() throws AblyException {
    Message[] historicMessages = channel.history(null).items();
    for (Message message : historicMessages) {
        Toast.makeText(getBaseContext(), "message: "
              + message.id + " - " + message.data), Toast.LENGHT_SHORT).show();
    }
}

See this step in Github

...
channel.history((err, resultPage) => {
  // display last message published
  const [lastMessage] = resultPage.items;
  console.log("Last message published:", lastMessage.data);

  // list all history items
  console.table(resultPage.items);
});
...
channel = ably.channels.get('persisted:sounds')
result_page = channel.history
puts "Last message published: #{result_page.items.first.data}"

See this step in Github

channel = client.channels.get('persisted:sounds')
paginatedResult = channel.history()
for message in paginatedResult.items:
    print('Last message published: {}'.format(message.data))

If you would like to try running this now, you can do so with python history.py.

See this step in Github

$channel = $ably->channels->get("persisted:sounds");
$paginatedResult = $channel->history();
foreach ($paginatedResult->items as $message) {
  echo sprintf(
    "Latest message published: %s\n",
    $message->data
  );
}

Run php history.php to see messages retrieved from channel history.

See this step in Github

We want the retrieved history to show in our ExampleViewController. In this tutorial we will load retrieved messages to a table view. Add UITableView from Object library to your view and bind it in code as “tableView” also remember to change:

class ExampleViewController: UIViewController {

To:

class ExampleViewController: UIViewController, UITableViewDataSource {

Our class has to become a delegate for the dataSource. In viewDidLoad() add this line:

tableView.dataSource = self

We will store all the messages retrieved from Ably history in array named “historyMessages”.

private var historyMessages: [String] = []

Retrieved messages will be shown in table view cells. In Interface Builder choose your tableView in Attributes Inspector find Prototype Cells and change it to 1.

Add prototype cell

Choose your prototype cell in Attributes Inspector find Style and pick “Basic” then find Identifier and change it to “Cell”.

Change cell style

Navigate to Size Inspector to find Row Height and change it’s value to 40.

Change cell height

Your class has to confirm to UITableViewDataSource protocol. To achieve that simply add these three methods to your code:

  func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      return 1
  }

  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return historyMessages.count
  }

  func tableView(tableView: UITableView, cellForRowAtIndexPath
                 indexPath: NSIndexPath) -> UITableViewCell {

      let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

      let row = indexPath.row
      cell.textLabel?.text = historyMessages[row]

      return cell
}

Your view should now look similar to this:

ExampleViewController view

To read more about using UITableView visit Apple developer guide

Now add another UIButton and bind it to an action named “retrieveHistoryAction”.
Add this code to previously added IBAction:

channel = client.channels.get("persisted:sounds")
historyMessages = []

channel.history() { (messages, error) in
    guard error == nil else {
        return self.showAlert("Error", message: "There was a an error retrieving messages history.")
    }

    let historyMessages = messages?.items as? [ARTMessage] ?? [ARTMessage]()
    historyMessages.forEach { message in
      self.historyMessages.append("\(message.data)")
    }
    self.tableView.reloadData()
  }

See this step in Github

We’re done, it’s that simple. We have now shown you how to set up a channel to use persisted history using channel rules, then we published some messages on that channel, and later retrieved them using the history API.

Download tutorial source code

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-java

Then you can run project inside your console. Be sure to switch into project’s directory and then use these commands in your terminal:

./gradlew assemble
./gradlew run

Don’t forget to replace your ExampleActivity#API_KEY field with Ably API key.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-android

And then run the demo on your Android device. Check Android Developers website if you are not familiar on how to run an Android Project. Don’t forget to replace your ExampleActivity#API_KEY field with Ably API key.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-javascript

And then run the demo locally by adding your Ably API key to example.html and opening the page in your browser.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-ruby

And then run the demo locally by adding your Ably API key to example.rb and running the demo bundle exec ruby example.rb

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-php

And then run the demo locally by adding your Ably API key to history.php, install the composer dependencies with:

composer install

and run this script with php history.php.

The complete source code for each step of this tutorial is available on Github.

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-python

And then run the demo locally by adding your Ably API key to history.py, install the required libraries with:

pip install ably

and run this script with python history.py.

The complete source code for each step of this tutorial is available on Github

We recommend that you clone the repo locally:

git clone https://github.com/ably/tutorials.git

Checkout the tutorial branch:

git checkout history-swift

In the project directory simply run:

pod install

Open example.xcworkspace and build the demo on your preferred iPhone simulator or device. Don’t forget to replace your ExampleViewController#API_KEY field by adding your Ably API key to ExampleViewController.swift.

Next steps

1. If you would like to find out more about how to use the history API from your devices and apps, see the Realtime history documentation. Typically on servers customers prefer to use the REST history API
2. Learn more about Ably features by stepping through our other Ably tutorials
3. Gain a good technical overview of how the Ably realtime platform works
4. Get in touch if you need help