Message Types

In many use cases it makes sense to have descriptive, predefined categories of messages to ensure that as your app grows and expands its functionality, you aren't limited by basic messaging structures. Moreover, you might want to apply conditional processing to messages of the same type, for example:

  • Text messaging.
  • Text messaging with language translations embedded in the message.
  • Hosted image/file messages, where the file is static and the URL is referenced.
  • Video files that contain thumbnails and loading icons.
  • Polling and questionnaire messages where you also supply predefined answers.
  • Invitations to new channels for private or group chat.
  • Action messages for the app to do something for this user.
  • Session data linked to a third-party such as video service or streaming event.

Custom vs. internal message type

There are two distinct message type fields a message may have.

  • Integer messageType refers to the internal PubNub type of the message.
  • String custom_message_type refers to a business-specific label or category to messages, signals, and files.

Server response

Every message sent through PubNub has its internal integer message type returned as type in the subscribe payload. On the contrary, a custom message type string (returned as cmt) is only returned when it has been explicitly set beforehand. The cmt value in the returned server response is the same as the value of custom_message_type (name may vary across SDKs) used during a publish.

Internal message typeDescription
0Regular message
2App Context event
3Message Reactions event
4File message

When working with historical messages, you can choose to return the type and the custom message type in the response by enabling the include_custom_message_type flag (name varies across SDKs). For more information on fetching historical messages and how those parameters are returned, refer to Retrieve messages.

Custom message type not present in payload

If you don't set the custom_message_type parameter during a publish, it is not present in the subscribe or history payloads.

Descriptive message types

Consider these three messages:

  • {payload: “Hello I am a Message"}
  • {payload: "https://cdn.app/your/image/here.png"}
  • {payload: "https://cdn.app/your/video/here.mp4"}

Because of the way these messages are constructed, you may run into a number of problems while trying to interpret their payloads in your app. Should you just scan for text? Should you check if every message starts with https? Should you look for .fileType at the end of each message?

You can make your app easier to expand upon by including message types in the publish call. Making types more descriptive also makes it easier to interpret these messages later on.

Generic payloadDescriptive payload
{payload: “Hello, I am a message"}{message:"Hello, I am a Message"} with custom_message_type set to text
{payload: "https://cdn.app/your/image/here.png"}{full:"https://cdn.app/your/image/here.png", thumbnail:" https://cdn.app/your/image/here_thumbnail.png"} with custom_message_type set to image
{payload: "https://cdn.app/your/video/here.mp4"}{url:"https://cdn.app/your/video/here.mp4", thumbnail:"https://cdn.app/your/video/here_thumbnail.png"} with custom_message_type set to video

When your app receives these kinds of messages, it can process them differently displaying text, images and videos according to their respective types.

Future-proof message types

You can add fail-safe measures into your app. If you introduce new message types, older versions of your app can prompt users to upgrade to unlock the features the new message types provide.

Check out these examples of publishing a Hello World! message with the custom_message_type parameter set to text-message:

pubnub.publish()
.message("Hello World!")
.channel("my_channel")
.customMessageType("text-message")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
}
System.out.println("pub status code: " + status.getStatusCode());
}
});

Custom message type

Like we showed before, the optional string parameter custom_message_type (name may vary across SDKs) in the Publish and Files APIs allows you to add business-specific label or category to messages, signals, and files.

You can use this parameter to easily filter, group or apply conditional logic based on the value of the custom_message_type parameter. Refer to Sending Messages, Sending Signals, and Sending Files for more information.

The value or the custom_message_type parameter must be a case-sensitive, alphanumeric string from 3 to 50 characters (dashes and underscores are allowed). The value can't start with special characters or the pn_ or pn- string.

SDKs supporting custom_message_type

For more info on custom_message_type, go to the following SDKs that already support this parameter: Objective-C, Swift, Java, JavaScript, Python, PHP, and Kotlin.

Recommendations

Message payloads and their types should be easy to read and extendable. As your app grows, you want to ensure that future releases don't break old versions.

Below is a list of payload structures and message types that might be helpful to you:

Text

pubnub.publish()
.message(new JSONObject()
.put("content", new JSONObject()
.put("message", "This is a message"))
.put("sender", "Mathew.Jenkinson"))
.channel("my_channel")
.customMessageType("text-message")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
}
System.out.println("pub status code: " + status.getStatusCode());
}
show all 16 lines

Multi-language Text

JSONObject data = new JSONObject()
.put("content", new JSONObject()
.put("message", new JSONObject()
.put("en", "This is a message")
.put("es", "Este es un mensaje")
.put("de", "Dies ist eine Nachricht")
.put("nl", "Dit is een bericht")))
.put("sender", "Mathew.Jenkinson");

pubnub.publish()
.message(data)
.channel("my_channel")
.customMessageType("multi-language-text")
.async(new PNCallback<PNPublishResult>() {
@Override
show all 22 lines

Text with image

pubnub.publish()
.message(new JSONObject()
.put("content", new JSONObject()
.put("text", "The weather is gorgeous today. Who's available to meet up for lunch at Bob’s Diner? 🌞")
.put("attachments", new JSONArray()
.put(new JSONObject()
.put("image", new JSONObject()
.put("source", "https://www.pubnub.com/pubnub_logo.svg")
)
)
)
.put("sender", "Mathew.Jenkinson"))
.channel("my_channel")
.customMessageType("text-with-image")
.async(new PNCallback<PNPublishResult>() {
show all 23 lines

Document

pubnub.publish()
.message(new JSONObject()
.put("content", new JSONObject()
.put("link", "https://my/full/document.pdf")
.put("thumbnail", "https://my/thumbnail/image.png"))
.put("sender", "Mathew.Jenkinson"))
.channel("my_channel")
.customMessageType("document")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
}
System.out.println("pub status code: " + status.getStatusCode());
show all 17 lines

Video

pubnub.publish()
.message(new JSONObject()
.put("content", new JSONObject()
.put("url", "https://my/video/file.png")
.put("thumbnail", "https://my/video/image.png"))
.put("sender", "Mathew.Jenkinson"))
.channel("my_channel")
.customMessageType("video")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
}
System.out.println("pub status code: " + status.getStatusCode());
show all 17 lines

Typing indicator

pubnub.signal()
.message(new JSONObject()
.put("content", new JSONObject()
.put("event", "typing"))
.put("sender", "Mathew.Jenkinson"))
.channel("my_channel")
.customMessageType("typing-indicator")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
}
System.out.println("pub status code: " + status.getStatusCode());
}
show all 16 lines

Chat invitation

JSONObject message = new JSONObject()
.put("content", new JSONObject()
.put("channel", "this is the channel you are being invited to")
.put("message", "Hi Craig, welcome to the team!"))
.put("sender", "Mathew.Jenkinson");

pubnub.publish()
.message(message)
.channel("my_channel")
.customMessageType("chat-invitation")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
show all 19 lines

Video invitation

JSONObject data = new JSONObject()
.put("content", new JSONObject()
.put("session", "your-token-here"))
.put("sender", "Mathew.Jenkinson");

pubnub.publish()
.message(data)
.channel("my_channel")
.customMessageType("video-invitation")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
System.out.println("pub timetoken: " + result.getTimetoken());
}
show all 18 lines

Poll

pubnub.publish()
.message(new JSONObject()
.put("content", new JSONObject()
.put("question", "What do people want for lunch?")
.put("answers", new JSONObject()
.put("pizza", 0)
.put("pierogi", 6)
.put("sushi", 0)))
.put("sender", "Mathew.Jenkinson"))
.channel("my_channel")
.customMessageType("poll")
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if(!status.isError()) {
show all 20 lines
Last updated on