Message objects represent individual messages. They belong to a conversation and consist of one or more pieces of content, known as Message Parts.

Push notification previews and sounds are set when you create each message. Each message keeps track of its delivery and read state for every participant in a conversation.

Creating a message

LYRMessage objects are initialized by calling newMessageWithParts:options:error: on LYRClient. This creates a LYRMessage object that is ready to be sent. The fields are as follows:

  • messageParts (Required, Set of LYRMessagePart): The message parts that make up this message (see below)
  • options (Optional, LYRMessageOptions): The option key used in the Message initializer options to specify the APNS configuration. The value given for this key must be an instance of LYRPushNotificationConfiguration.
  • error (Optional, pointer to NSError): An optional pointer to an error object whose value will be set if an error occurs
// Creates and returns a new message object with the given conversation and array of message parts
NSError *error = nil;
LYRMessage *message = [layerClient newMessageWithParts:[NSSet setWithObject:messagePart] options:nil error:&error];

Message Parts

A message is comprised of one or more parts. You may use a multi-part message to send a photo along with a description, for example, or to send a message with a location.

You can send any type of data through Layer. To support this, Message Parts consist of a data blob for the value
and a MIME type string for the type. Each Message Part can be up to 2GB. The MIME type string simply describes the type of content.


Message Parts that are 2KB or smaller are sent inline (the content is sent with the Message Part instance). Larger Message Parts have their content uploaded to dedicated storage using the Rich Content APIs.

// MIME type declarations
static NSString *const MIMETypeTextPlain = @"text/plain";
static NSString *const MIMETypeImagePNG = @"image/png";

// Creates a message part with a string of text and text/plain MIMEtype.
NSData *messageData = [@"Hi, how are you?" dataUsingEncoding:NSUTF8StringEncoding];
LYRMessagePart *messagePart = [LYRMessagePart messagePartWithMIMEType:MIMETypeTextPlain data:messageData];

// Creates a message part with an image
UIImage *image = [UIImage imageNamed:@"awesomeImage.png"];
NSData *imageData = UIImagePNGRepresentation(image);
LYRMessagePart *imagePart = [LYRMessagePart messagePartWithMIMEType:MIMETypeImagePNG data:imageData];

LYRMessagePart also declares a convenience method for creating a plain text (text/plain MIME type) message part:

LYRMessagePart *part = [LYRMessagePart messagePartWithText:@"Hi, how are you?"];


While Layer does not place any restrictions on the MIME Type, Google and Apple dictate that the MIME Type string MUST conform to a */* convention. If the MIME Type does not contain a forward slash (/) you may have issues sending messages. For a comprehensive list of MIME Type values check out the IANA’s official registry of media types.

Message Content Updates

The Layer XDK is capable of receiving message content updates issued through the SAPI calls where content can be added, updated or removed. All these operations are seen as direct mutations on the Message and Message Part instances, but can also be captured as object changes or through the query controller (where available).


If a query controller setup for Messages utilizes the updatableProperties feature, make sure to add the parts to the set, otherwise the query controller will ignore message part mutations. Read more on Updatable Properties here.

Sending a message

//Sends the specified message
NSError *error = nil;
BOOL success = [conversation sendMessage:message error:&error];
if (success) {
  NSLog(@"Message enqueued for delivery");
} else {
  NSLog(@"Message send failed with error: %@", error);

The sendMessage:error: method returns a boolean value which indicates if the message has passed validation and was enqueued for delivery in the local data store. If LayerKit has a current network connection, the message will immediately be sent off of the device. Otherwise it will remain enqueued locally until the SDK re-establishes a network connection. At that point, the SDK will automatically send the message.

LYRMessage objects declare a boolean property, isSent, which tells your application if the message was successfully sent from your device and synchronized with the Layer service.

Confirming delivery

The simplest way to confirm that a message has been delivered is to visit the Logs page of the Developer Dashboard. If a message was successfully sent, you’ll see a log like this:

May 02 2015 2:34:27pm Sync: User <USER_IDENTIFIER> created a message in conversation <CONVERSATION_IDENTIFIER>.

Additionally, you can use the LYRQueryController object or listen to LYRClientObjectsDidChangeNotification via NSNotificationCenter to be notified of incoming messages.

Receiving messages

The Layer SDK automatically receives incoming messages — you don’t need to force a sync or set up a polling system.

By default, LayerKit automatically downloads content for message parts whose content size is less than 2KB. However, you can change this setting:

// Autodownload all message parts whose content size is less than 100KB
self.layerClient.autodownloadMaximumContentSize = 1024 * 100;

You can also configure the types of content that should be automatically downloaded, regardless of their content size.

// Autodownload all JPEGs (MIME type image/jpeg)
self.layerClient.autodownloadMIMETypes = [NSSet setWithObjects:@"image/jpeg", nil];

Finally, you can manually download message part content — often this is used when a message is scrolled into view, or when the user taps on a preview/placeholder.

LYRMessagePart *messagePart =;

NSError *error;
LYRProgress *progress = [messagePart downloadContent:&error];
if (error) {
    NSLog(@"Content failed download with error %@", error);

Disk space management

You can limit the amount of space Layer will use for saving data. If locally cached content exceeds this limit, then content will be deleted, starting with the least-recently accessed.

// Sets the local disk space Layer is allowed to use (in bytes). Passing in a value of
// 0 will remove the limit (this is the default behavior)
self.layerClient.diskCapacity = 1024 * 1024 * 50; //Sets the limit to 50 MB

// Check Layer's actual usage (in bytes)
long usage = self.layerClient.currentDiskUtilization;

// You can always choose to delete a Message Part (locally only - the server is not affected)
NSError *error = nil;
LYRProgress *progress = [messagePart purgeContent:&error];

Recipient status

Layer keeps track of the recipient status of each message, for each participant in a conversation. Note that messages within channels do not track recipient status; only Conversation rather than Channel messages track this.

There are four possible statuses:

  • LYRRecipientStatusInvalid: The message status cannot be determined
  • LYRRecipientStatusSent: The message has successfully reached Layer servers and is waiting to be synchronized with recipient devices
  • LYRRecipientStatusDelivered: The message has arrived on the recipient’s devices
  • LYRRecipientStatusRead: The recipient’s device has marked the message as read

Your app can check recipient statuses by accessing the recipientStatusByUserID property on LYRMessage objects. The property is a dictionary where the keys are user IDs and the values are the current recipient status for that message. The following shows how to check the recipient status of a message for the currently authenticated user:

NSDictionary *statuses = message.recipientStatusByUserID;
NSString *userID = layerClient.authenticatedUser.userID;
LYRRecipientStatus = [recipientStatus[userID] integerValue];
NSLog(@"Recipient status is %ld", status);

Layer automatically updates the recipient status to sent, delivered, or invalid. The only update your app can perform is to mark a message as read:

NSError *error = nil;
BOOL success = [message markAsRead:&error];

Your app can also mark all the messages in a conversation as read:

NSError *error = nil;
BOOL success = [conversation markAllMessagesAsRead:&error];

Note that Messages within Channels do not yet support marking messages as read.

Conversations Announcements