---
source_url: https://www.pubnub.com/docs/pub-sub/publish/send-different-message-types
title: Send different message types
updated_at: 2026-09-30T07:20:08.000Z
---

# Send different message types

## Documentation index

To discover more PubNub resources:

1. Fetch [PubNub's llms.txt](https://www.pubnub.com/llms-full.txt) for a list of available pages in Markdown format.
2. Identify relevant URLs from that index.
3. Fetch the target pages.

Do not assume a path exists, always check the index first.

This guide shows you how to send typed data to a PubNub [channel](https://www.pubnub.com/docs/architecture/core-concepts.md#channel).

* Publish a message and label it with a custom message type, so subscribers can route it without parsing the payload.
* Send a signal instead, when the value changes constantly.
* Attach metadata for server-side filtering.

This page covers `customMessageType`: a label you set at publish time. Platform-assigned type integers (file events, [App Context](https://www.pubnub.com/docs/data-storage/metadata/overview.md) events, message action events) are set automatically by their respective APIs.

Every call on this page addresses exactly one channel and needs an SDK instance initialized with your publish key. If you don't have a keyset yet, start with [Set up your account](https://www.pubnub.com/docs/architecture/authentication/set-up-your-account.md). If you already publish untyped messages and only need the type label, skip to [Label the message with a custom message type](#label-the-message-with-a-custom-message-type).

Examples use the JavaScript, Swift, Java, Kotlin, Python, and PHP SDKs, which document every parameter this guide uses. For any other language, refer to [Available SDKs](https://www.pubnub.com/docs/getting-started/available-sdks.md).

## Publish a message

Call `publish()` with a channel and a payload. The payload can be any JSON-serializable value: an object, an array, a string, or a number. Don't serialize it yourself, because the SDK does that for you.

### JavaScript

```javascript
const result = await pubnub.publish({
  channel: "my_channel",
  message: { text: "Hello World!" },
});

console.log("timetoken:", result.timetoken);
```

### Swift

```swift
pubnub.publish(
  channel: "my_channel",
  message: ["text": "Hello World!"]
) { result in
  switch result {
  case let .success(timetoken):
    print("timetoken: \(timetoken)")
  case let .failure(error):
    print("failed: \(error.localizedDescription)")
  }
}
```

### Java

```java
JsonObject data = new JsonObject();
data.addProperty("text", "Hello World!");

Channel channel = pubnub.channel("my_channel");

channel.publish(data)
    .async(result -> result.onSuccess(value ->
        System.out.println("timetoken: " + value.getTimetoken())));
```

### Kotlin

```kotlin
val channel = pubnub.channel("my_channel")

channel.publish(
    message = mapOf("text" to "Hello World!")
).async { result ->
    result.onSuccess { println("timetoken: ${it.timetoken}") }
        .onFailure { println("failed: ${it.message}") }
}
```

### Python

```python
def publish_callback(result, status):
    if status.is_error():
        print(status.error_data.information)
    else:
        print("timetoken: {}".format(result.timetoken))

pubnub.publish() \
    .channel("my_channel") \
    .message({"text": "Hello World!"}) \
    .pn_async(publish_callback)
```

### PHP

```php
$result = $pubnub->publish()
    ->channel("my_channel")
    ->message(["text" => "Hello World!"])
    ->sync();

echo "timetoken: " . $result->getTimetoken();
```

A successful publish returns `[1, "Sent", "<timetoken>"]`, and a failed one returns `0` in the first position. For what the timetoken identifies afterwards, refer to [Publish response and the timetoken](https://www.pubnub.com/docs/pub-sub/publish/overview.md#publish-response-and-the-timetoken).

The standard message payload size limit is 32 KiB. This includes the channel name and any metadata. If your payloads approach that limit, measure one before you ship it.

Channel name
Message body

Payload Size: 0.00 KiB (0 bytes)

:::tip Need larger messages?
PubNub supports payloads larger than the standard limit, but raising it requires verifying compatibility with your use case.
Talk to [our team](https://www.pubnub.com/company/contact-sales/) to discuss increasing the message size limit for your use case.
:::

The sections below build on this call by adding a type label, a signal variant, and metadata.

## Label the message with a custom message type

Set `customMessageType` (`custom_message_type` in the Python SDK) to attach a business-specific label to a message, a signal, or a file. Subscribers then branch on the label instead of inspecting the payload, and a [subscribe filter](https://www.pubnub.com/docs/pub-sub/subscribe/overview.md#filter-on-the-server) can discard traffic of the wrong type server-side before it reaches a client.

The `custom_message_type` value accepted by the PubNub Publish, Signal, and File Sharing APIs must be a case-sensitive alphanumeric string of 3 to 50 characters. Dashes (`-`) and underscores (`_`) are allowed. The value cannot start with a special character or with the reserved prefixes `pn_` or `pn-`.

### JavaScript

```javascript
await pubnub.publish({
  channel: "my_channel",
  message: { text: "Hello World!" },
  customMessageType: "text-message",
});
```

### Swift

```swift
pubnub.publish(
  channel: "my_channel",
  message: ["text": "Hello World!"],
  customMessageType: "text-message"
) { result in
  switch result {
  case let .success(timetoken):
    print("timetoken: \(timetoken)")
  case let .failure(error):
    print("failed: \(error.localizedDescription)")
  }
}
```

### Java

```java
JsonObject data = new JsonObject();
data.addProperty("text", "Hello World!");

Channel channel = pubnub.channel("my_channel");

channel.publish(data)
    .customMessageType("text-message")
    .async(result -> { /* check result */ });
```

### Kotlin

```kotlin
val channel = pubnub.channel("my_channel")

channel.publish(
    message = mapOf("text" to "Hello World!"),
    customMessageType = "text-message"
).async { result -> /* check result */ }
```

### Python

```python
pubnub.publish() \
    .channel("my_channel") \
    .message({"text": "Hello World!"}) \
    .custom_message_type("text-message") \
    .pn_async(publish_callback)
```

### PHP

```php
$result = $pubnub->publish()
    ->channel("my_channel")
    ->message(["text" => "Hello World!"])
    ->customMessageType("text-message")
    ->sync();
```

Two consequences are worth designing for.

* The label is absent unless a publish set it, so give subscribers a default path for untyped traffic rather than assuming the field is present.
* Messages retrieved from Message Persistence include the custom message type only when the request enables the `include_custom_message_type` flag, whose name varies across SDKs. Enable that flag in any history call whose results your routing logic depends on.

A message also carries a separate integer `messageType` that PubNub sets, which identifies the kind of event PubNub delivered rather than your business label. For its values and for how both fields appear in subscribe and history payloads, refer to [Message types categorize traffic on a shared channel](https://www.pubnub.com/docs/pub-sub/overview.md#message-types-categorize-traffic-on-a-shared-channel).

## Choose a payload shape per type

PubNub validates a payload only for size and JSON-serializability, so a payload shape is a convention your application owns. Choosing one shape per type up front lets a receiver render an event from its type alone. It also lets an older client build recognize a type it doesn't handle, and prompt for an upgrade instead of failing on a shape it can't parse.

The shapes below are examples: an envelope with a `content` object holding the type-specific fields. Adapt the field names to your application.

| Type | `customMessageType` | `content` fields |
| --- | --- | --- |
| Plain text | `text-message` | `message` |
| Text in several languages | `multi-language-text` | `message`, as an object keyed by language code |
| Text with an image | `text-with-image` | `text`, `attachments` as an array of `{"image": {"source": "…"}}` |
| Document link | `document` | `link`, `thumbnail` |
| Video link | `video` | `url`, `thumbnail` |
| Chat invitation | `chat-invitation` | `channel`, `message` |
| Video call invitation | `video-invitation` | `session` |
| Poll | `poll` | `question`, `answers` as an object of option to count |
| Typing indicator | `typing-indicator` | `event`. Send this one as a signal, not a message |

A fully worked payload for `text-with-image`:

```json
{
  "content": {
    "text": "The weather is gorgeous today. Lunch at Bob's Diner? 🌞",
    "attachments": [
      { "image": { "source": "https://www.pubnub.com/pubnub_logo.svg" } }
    ]
  }
}
```

Every event already carries the publisher's [User ID](https://www.pubnub.com/docs/architecture/core-concepts.md#user-id), so add a `sender` field only when you need a display name or an identity different from the publishing connection's.

## Send a signal instead of a message

Use `signal()` when a value changes constantly and only the latest one matters: a typing indicator, a live GPS position, or a sensor reading. Signal payloads are limited to 64 bytes. Signals are never stored and can't trigger mobile push notifications, so use a message for anything a client must be able to recover later.

Send signals and messages on separate channels. Mixing them on the same channel interferes with how the SDK recovers missed events after a disconnect.

### JavaScript

```javascript
await pubnub.signal({
  channel: "locations.route1",
  message: ["35.9296", "-78.9482"],
  customMessageType: "gps-update",
});
```

### Swift

```swift
pubnub.signal(
  channel: "locations.route1",
  message: ["35.9296", "-78.9482"],
  customMessageType: "gps-update"
) { result in
  switch result {
  case let .success(timetoken):
    print("timetoken: \(timetoken)")
  case let .failure(error):
    print("failed: \(error.localizedDescription)")
  }
}
```

### Java

```java
Channel channel = pubnub.channel("locations.route1");

channel.signal(Arrays.asList("35.9296", "-78.9482"))
    .customMessageType("gps-update")
    .async(result -> { /* check result */ });
```

### Kotlin

```kotlin
val channel = pubnub.channel("locations.route1")

channel.signal(
    message = listOf("35.9296", "-78.9482"),
    customMessageType = "gps-update"
).async { result -> /* check result */ }
```

### Python

```python
pubnub.signal() \
    .channel("locations.route1") \
    .message(["35.9296", "-78.9482"]) \
    .custom_message_type("gps-update") \
    .pn_async(publish_callback)
```

### PHP

```php
// The PHP SDK's signal() takes no customMessageType parameter.
$result = $pubnub->signal()
    ->channel("locations.route1")
    ->message(["35.9296", "-78.9482"])
    ->sync();
```

## Attach metadata to a message

Pass `meta` to carry data alongside a message that stays out of the payload. Set it when you want PubNub to filter on a value server-side, or when the payload is encrypted and a value still has to be readable by PubNub services such as [Functions](https://www.pubnub.com/docs/message-processing/serverless/overview.md) and subscribe filtering. Because `meta` stays unencrypted, never put a secret in it.

### JavaScript

```javascript
await pubnub.publish({
  channel: "notifications",
  message: {
    title: "System maintenance",
    body: "Scheduled maintenance window starting soon",
  },
  customMessageType: "system-notice",
  meta: { priority: "high", region: "us-west" },
});
```

### Swift

```swift
pubnub.publish(
  channel: "notifications",
  message: [
    "title": "System maintenance",
    "body": "Scheduled maintenance window starting soon"
  ],
  customMessageType: "system-notice",
  meta: ["priority": "high", "region": "us-west"]
) { result in
  switch result {
  case let .success(timetoken):
    print("timetoken: \(timetoken)")
  case let .failure(error):
    print("failed: \(error.localizedDescription)")
  }
}
```

### Java

```java
Map<String, Object> message = new HashMap<>();
message.put("title", "System maintenance");
message.put("body", "Scheduled maintenance window starting soon");

Map<String, Object> meta = new HashMap<>();
meta.put("priority", "high");
meta.put("region", "us-west");

Channel channel = pubnub.channel("notifications");

channel.publish(message)
    .customMessageType("system-notice")
    .meta(meta)
    .async(result -> { /* check result */ });
```

### Kotlin

```kotlin
val channel = pubnub.channel("notifications")

channel.publish(
    message = mapOf(
        "title" to "System maintenance",
        "body" to "Scheduled maintenance window starting soon"
    ),
    meta = mapOf("priority" to "high", "region" to "us-west"),
    customMessageType = "system-notice"
).async { result -> /* check result */ }
```

### Python

```python
pubnub.publish() \
    .channel("notifications") \
    .message({
        "title": "System maintenance",
        "body": "Scheduled maintenance window starting soon"
    }) \
    .meta({"priority": "high", "region": "us-west"}) \
    .custom_message_type("system-notice") \
    .pn_async(publish_callback)
```

### PHP

```php
$result = $pubnub->publish()
    ->channel("notifications")
    ->message([
        "title" => "System maintenance",
        "body" => "Scheduled maintenance window starting soon"
    ])
    ->meta(["priority" => "high", "region" => "us-west"])
    ->customMessageType("system-notice")
    ->sync();
```

Metadata values must be JSON-serializable.

`meta` is a message-only parameter. Signals don't accept it, so a value a filter has to see must travel in the signal payload itself.

## Related tasks

* [Filter received messages](https://www.pubnub.com/docs/pub-sub/subscribe/filter-received-messages.md). Write the subscribe filter that reads the type or the metadata you just set.
* [Receive messages](https://www.pubnub.com/docs/pub-sub/subscribe/receive-messages.md). Handle the events these calls produce.
* [Delete messages](https://www.pubnub.com/docs/data-storage/message-history/delete-messages-from-history.md). Remove a published message from a channel's history.
* [Send a file to a channel](https://www.pubnub.com/docs/data-storage/files/send-file-to-channel.md). Publish a file with an optional text message and a custom message type.
* [Encrypt and decrypt all messages and files](https://www.pubnub.com/docs/security/encryption/encrypt-all-messages-and-files.md). Encrypt the payload while leaving `meta` filterable.

Last updated at: 2026-09-30T07:20:08.000Z
