Metadata

Metadata provides an elegant mechanism for expressing and synchronizing contextual information about conversations. This is implemented as a free-form structure of string key-value pairs that is automatically synchronized among the participants in a conversation. Example use cases of metadata include:

  • Setting a conversation title.
  • Attaching dates or tags to the conversation.
  • Storing a reference to a background image URL for the conversation.

Setting Metadata

The following demonstrates setting metadata on a Conversation. Assume we have an initial metadata of:

{
  "title": "Frodo is indeed a Dodo"
}

And then run:

conversation.setMetadataProperties({
  theme: {
    background_color: '333333',
    text_color: 'F8F8EC',
    link_color: '21AAE1'
  }
});

This would update metadata to

{
  "title": "Frodo is indeed a Dodo",
  "theme": {
    "background_color": "333333",
    "text_color": "F8F8EC",
    "link_color": "21AAE1"
  }
}

In other words: setMetadataProperties only sets the properties you specifiy (theme in this example), and leaves the rest of your metadata untouched.

Your metadata can contain any set of keys and values you want – as long as the values are either strings or sub-objects. The metadata names we use in these examples have no meaning other than what you assign to them.

Individual properties can be updated:

conversation.setMetadataProperties({
  'title': 'This is a really good conversation'
});

Subproperties can be updated with . separated paths:

conversation.setMetadataProperties({
  'theme.text_color': '000000'
});

Deleting Metadata

A metadata key can be removed entirely from the metadata structure using deleteMetadataProperties. The following command removes ‘metadata.key2’ and the subproperty of ‘metadata.key3’ named ‘key5’:

conversation.deleteMetadataProperties(['key2', 'key3.key5']);

Accessing Metadata

You can directly access the metadata property as a read-only object:

function renderConversation(conversation) {
  return '<div class="conversation">' + conversation.metadata.title + '</div>';
}

Monitor for changes to Metadata

To receive notifications of changes to conversation metadata, we can use the conversations:change event handler. This will trigger for both local and remote changes to the metadata value.

conversation.on('conversations:change', function(evt) {
    // Get only the metadata changes
    var metadataChanges = evt.getChangesFor('metadata');

    // Log each metadata change
    metadataChanges.forEach(function(change) {
        console.log('Metadata was changed from ' +
            JSON.stringify(change.oldValue) + ' to ' +
            JSON.stringify(change.newValue));
    });
});

More often, you may prefer to subscribe to metadata changes for all of the Conversations in a Query:

query.on('change', function(evt) {
    if (evt.type === 'property') {
        var changedConversation = evt.target;
        var metadataChanges = evt.getChangesFor('metadata');
        // Log each metadata change
        metadataChanges.forEach(function(change) {
            console.log('Metadata for ' + changedConversation.id + ' was changed from ' +
                JSON.stringify(change.oldValue) + ' to ' +
                JSON.stringify(change.newValue));
        });
    }
});

Warning

While this feature is both powerful and convenient, it is not designed to serve as a general purpose data store. It’s important to understand the intended use cases and limitations associated with the feature to ensure an ideal user experience. In particular, keep in mind that:

  • Metadata is implemented with “last writer wins” semantics on a per key basis. This means that multiple mutations by independent users to a given key will result in a single stored value. No locking or other coordination is performed across participants.
  • Metadata is automatically synchronized by each participant in the conversation. While Layer has gone to great lengths to implement metadata in a way that maximizes efficiency on the wire, it is important that the amount of data stored in metadata is kept to a minimum to ensure the quickest synchronization possible.
  • Metadata values must be represented as strings. To ensure a satisfying user experience developers are strongly discouraged from storing any sort of binary data representation (including thumbnail images) via metadata. Instead, consider storing a URL or other reference to data that is transmitted out of band from synchronization.
  • Metadata is limited to the storage of a maximum of 2KB of data under each key. Keys must be alphanumeric and may include hyphens and underscores, but cannot contain spaces. If your metadata key contains space you may run into issues if you try to query them. Nested structures may be used to facilitate efficient namespacing of content.
  • There is not currently any limit enforced on the number of keys stored into the metadata structure. Because mutations are performed on a per key basis, it is advantageous to structure your data in such a way that smaller amounts of data are stored under a larger number of keys. Note that we may introduce a key limit in future versions.
  • Mutable Conversation metadata should only be used to store information associated with the Conversation itself – not individual messages. As the number of metadata keys grow synchronization will take longer to complete. Because Conversations can be very long lived, performance can be severely impacted if dynamically computed keys (such as those built from message identifiers) are utilized.
Typing indicators Synchronization