---
source_url: https://www.pubnub.com/docs/general/messages/publish
title: Message Publish
updated_at: 2026-05-25T11:26:19.139Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Message Publish

The foundation of all our PubNub offerings is the ability to send a message that will be delivered anywhere in less than 30 ms. Below, we walk you through different ways to send a message.

##### Need help. Flat tire. Kansas City.

Hi, I’m Sarah, and I work as a Staff Software Engineer for multiple transportation projects. I’m the go-to person for build vs. buy matters. In my recent project, I worked for a transport company that managed a massive fleet of buses and trucks. They had to deal with hundreds of thousands of service issues every day: “I’m near KC, MO and I got a flat tire,” “I’ll fetch the cargo a bit later cause I’m stuck in traffic” or “Have to skip work today, got sick.” The question was how to track and prioritize so many issues reported from various geographical locations and handle them swiftly?

We decided to treat these issues as events of various types and assign them different attributes - stage, service location, estimate value, event status, and priority. We needed a tool to combine the upcoming events in one place, categorize them according to their attributes and display all changes in real-time for everyone to track. However, we didn’t have the know-how required to handle all these events wisely.

We’ve decided to reach out to PubNub. With the company’s huge fleet and the number of daily cases, we reckoned scalability and stability are essential. With PubNub [Pub/Sub Messaging](https://www.pubnub.com/docs/general/basics/send-messages), we built a real-time interactive UI dashboard for event and fleet tracking. We stream data between the company’s backend and the dashboard which is also [subscribed](https://www.pubnub.com/docs/general/basics/receive-messages) to notifications from the server through listeners. Every time the backend is updated, the incoming data is filtered using [Subscribe Filters](https://www.pubnub.com/docs/general/channels/subscribe-filters) to fall into specific categories. Then, the dashboard is notified of changes and displays the data in real time. Thanks to PubNub, the company can monitor & react to issues immediately & get the ball rolling at an impressive speed by fixing flat tires, finding backups or replacements, and simply getting things done.

A [PubNub Message](#) can contain any kind of serializable data, like objects, numbers and UTF-8 encoded strings. Its format may be plain text, a URL-encoded object, or most commonly, JavaScript Object Notation (JSON). The max size of a message is 32 Kibibytes (KiB). You can check the size of your message payload using our [message size calculator.](https://www.pubnub.com/docs/general/messages/publish#message-size-limit)

:::tip Receiving messages
Add a listener to receive and handle incoming messages, signals, and events. If you're new to PubNub, review how to set up [your account](https://www.pubnub.com/docs/general/setup/account-setup).
:::

## Send messages

The primary means for sending messages is using the *Publish* API. You may only send a message to one channel at a time. If you want to publish to multiple channels, you must create a [channel group](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups).

PubNub's network reliably supports unlimited publishes without waiting for response on the same TCP socket connection.

### JavaScript

```javascript
pubnub.publish(
  {
    channel: "my_channel",
    message: {"text": "Hello World!"}
  },
  function(status, response) {
    console.log(status);
    console.log(response);
  }
);
```

### Swift

```swift
pubnub.publish(
  channel: "my_channel",
  message: ["text": "Hello World!"]
){ result in
  switch result {
    case let .success(response):
      print("succeeded: \(response)")

    case let .failure(error):
      print("failed: \(error.localizedDescription)")
  }
}
```

### Objective-C

```objectivec
[self publish: @{@"text" : @"Hello World!"} toChannel:@"my_channel"
    completion:^(PNPublishStatus *status) {
    NSLog(@"%@status '%@'", status);
}];
```

### Java

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

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

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

### C#

```csharp
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("text", "Hello World!");

pubnub.Publish()
  .Channel("my_channel")
  .Message(data)
  .Execute(new PNPublishResultExt(
    (result, status) => {
      if (status.is_error()) {
        Console.WriteLine("status code: " + status.ErrorData.Information);
      }
      else {
        Console.WriteLine("timetoken: " + result.Timetoken.ToString());
      }
    }
  ));
```

### Python

```python
def publish_callback(result, status):
  if status.is_error():
    print status.status_code
  elif
    print result.timetoken

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

When you publish a message to a channel, you're asking PubNub Platform to deliver that message to everyone who is subscribed to that channel.

A PubNub message may be sent as plain text, URL-encoded object, and most commonly, JSON. For more information, refer to [message types](https://www.pubnub.com/docs/general/messages/type).

As you can see, in the above publish method we specify the channel on which to send the message, the message content we want to send and a way to capture the server response, which in most languages is an asynchronous callback. A successful response looks like this:

```json
[1,"Sent","14375189629170609"]
```

The response has three parts:

1. **success flag**: 1 = success, 0 = failed
2. **response message**: *Sent* or *Failed*
3. **publish timetoken**: exact timestamp of the message which is a 17 digit value to the nearest 10th nanosecond (can be converted to UNIX epoch by dividing by 10000).

The publish timetoken can be used later to retrieve (or augment) that message using [Message Persistence](https://www.pubnub.com/docs/general/storage).

###### Use the publish timetoken for retrieval and ordering

The timetoken in the publish response uniquely identifies this message across the PubNub network. PubNub assigns it server-side as a monotonically increasing value, so messages on a channel form a single ordered sequence without client-side coordination. Pass this timetoken to [Message Persistence](https://www.pubnub.com/docs/general/storage#retrieve-messages) to fetch the message later, to [message actions](https://www.pubnub.com/docs/general/messages/actions) to attach reactions or receipts, or store it client-side to resume a subscription from this exact point after a disconnect.

:::note HTTP streaming and pipelining
For details on streaming and pipelining, see this [gist](https://gist.github.com/stephenlb/9496723).
:::

### Send announcements to all users

You can send announcements to all users, or a limited set of users, in your application by using a channel to which the announcer has read/write access, and to which all other users have read-only access.

Once you have the channel set up, you can display any messages sent on the channel as announcements. Users with read access can subscribe to the channel to receive announcements, but can't send messages on the same channel.

###### Enforce announcement channel permissions with Access Manager

Use [Access Manager](https://www.pubnub.com/docs/general/security/access-control) to enforce these permission boundaries with tokens. Grant the announcer `write` access and grant listeners `read`-only access on the announcement channel.

###### JavaScript

```javascript
pubnub.publish({
  message: {
    type: 'announcement',
    text: 'Hello, this is an announcement'
  },
  channel: 'ch-1',
}, (status, response) => {
  // handle status, response
});
```

###### Swift

```swift
pubnub.publish(
  channel: "ch-1",
  message: ["type": "announcement", "text": "Announcement message to all users"]
) { result in
  switch result {
  case let .success(response):
    print("Successful Publish Response: \(response)")
  case let .failure(error):
    print("Failed Publish Response: \(error.localizedDescription)")
  }
}
```

###### Java

```java
// Java SDK uses channel-based publish
JsonObject messagePayload = new JsonObject();
messagePayload.addProperty("type", "announcement");
messagePayload.addProperty("text", "Hello, this is an announcement");

Channel channel = pubnub.channel("ch-1");

channel.publish(messagePayload)
        .async(result -> { /* check result */ });
```

###### Unity

```csharp
Dictionary<string, string> payload = new Dictionary<string, string>();
payload.Add("type", "announcement");
payload.Add("text", "Hello, this is an announcement");

pubnub.Publish()
    .Channel("ch-1")
    .Message(payload)
    .Async((result, status) => {
        if (!status.Error) {
            Debug.Log(result.Timetoken);
        } else {
            Debug.Log(status.Error);
            Debug.Log(status.ErrorData.Info);
        }
    });
```

### Message specifications

The `message` property can contain any JSON serializable data (JSON isn't required, just recommended and is typical in most use cases), including: Objects, Arrays, Integers and Strings. String content can include any single-byte or multi-byte UTF-8 character.

:::note JSON serialization
You don’t need to serialize a JSON object when sending messages. PubNub SDKs handle serialization.
:::

#### Delivery

* PubNub provides status and timing details for each publish.
* The Sent status confirms that the PubNub Network received the message and forwarded it to connected subscribers.
* Network conditions on the last mile can affect delivery outside PubNub’s control.

Subscribers with interrupted or offline connections can still retrieve missed messages. For status codes and retrieving missed and historical messages, see [Connection Management](https://www.pubnub.com/docs/general/setup/connection-management) and [Message Persistence](https://www.pubnub.com/docs/general/storage).

###### Extend delivery with persistence and push

A published message is ephemeral by default. To retain it, enable [Message Persistence](https://www.pubnub.com/docs/general/storage) and use the publish timetoken for later retrieval. To also deliver the message as a native notification, include a push payload to trigger [Mobile Push Notifications](https://www.pubnub.com/docs/general/push/send) for offline devices. Both features compose on top of standard publish without changing the publish call structure.

#### Order

As long as the publisher sends messages slower than the consumer can receive them, messages are typically kept in order.

If your app requires strict ordering, add a sequence field to the message payload and order by it.

#### Message size limit

The maximum number of characters per message is 32 KiB. The maximum message size is based on the final escaped character count, including the channel name.

If the message you publish exceeds the configured size, you'll receive the following message:

```json
["PUBLISHED",[0,"Message Too Large","13524237335750949"]]
```

If you expect your messages will be pushing the size limit, check the size of your message in our payload size calculator.

Channel name
Message body

Payload Size: 0.00 KiB (0 bytes)

For more information on calculating payload size within your application, refer to our [knowledge base](https://support.pubnub.com/hc/en-us/articles/360051495932-Calculating-Message-Payload-Size-Before-Publish).

### Receive messages

To receive a message, your client should [implement a message listener](https://www.pubnub.com/docs/general/messages/receive) and [subscribe](https://www.pubnub.com/docs/general/channels/subscribe) to a channel in which the message is being published.

## Send signals

*Signals* are ideal for high-volume, low-cost use cases. They're intended for sending small bits of data where the last sent data is the only important piece of information. For example, chat typing indicators, live GPS location updates, and sensor updates from IoT devices.

##### Sounds like a solution: How we used PubNub to jazz up in-store audio experiences

Hi there, I'm Edward, and as the tech lead, I and the team were facing a significant challenge. Our company focuses mainly on IoT devices, particularly creating customized audio and advertising for retail spaces, with the goal of improving customer experiences. We had a challenge, and it was no small feat - to analyze various data points, such as store location, time of day, weather, and customer footfall, to influence their buying patterns through music and audio.

Finding a solution to allow us to control smart speakers via an [IoT](https://www.pubnub.com/docs/sdks#iot-device-control-sdks) device proved to be quite a pursuit. We needed help to execute our vision. We spent a lot of time looking for a solution. That's when we came across PubNub while scouring the web. We explored their [signals](https://www.pubnub.com/docs/general/messages/publish#send-signals) and data-streaming feature and saw the potential it had for our front-end platform. Integrating it into our system, we could send signals to IoT devices and pass commands to smart speakers to ensure the right music or audio is played while monitoring customer store activity.

Thanks to PubNub, we were able to create a unique customer experience that has increased the number of clients visiting our store and our sales. We received tons of positive feedback from our clients. One even said: "Our brand stands out thanks to the amazing audio experience that connects with customers on an emotional level, making us different from the competition." With PubNub's help, we were able to deliver the best possible experience to our customers, which was our goal all along.

### Messages vs signals

Signals are similar to regular messages, with the following exceptions:

| **Feature** | **Signals** | **Messages** |
| --- | --- | --- |
| **Payload size** | Limited to 64 bytes (64B) | Up to 32 kilobytes (32KB) |
| **Cost efficiency** | Cost less than standard messages | Generally more expensive than signals |
| **Persistence** | Cannot be saved in [Message Persistence](https://www.pubnub.com/docs/general/storage) (past signals cannot be accessed) | Can be saved and accessed through Message Persistence |
| **Push Notifications** | Cannot trigger [Mobile Push Notifications](https://www.pubnub.com/docs/general/push/send) | Can trigger Mobile Push Notifications |
| **Use case suitability** | Best for non-critical data streams, like geolocation updates | Suitable for critical and non-critical use cases |
| **Metadata support** | Do not support metadata | Support metadata |

:::note Channel separation
Signals and messages should be sent on separate channels to improve connection recovery behaviour.
:::

Sending a signal is similar to publishing a message:

###### JavaScript

```javascript
let gps = ["35.9296","-78.9482"];

pubnub.signal(
  {
    channel: "locations.route1",
    message: gps
  },
  function(status, response) {
    console.log(status, response);
  }
);
```

###### Swift

```swift
let gps = ["35.9296","-78.9482"]

pubnub.signal(
  channel: "locations.route1",
  message: gps
) { result in
  switch result {
  case let .success(response):
    print("succeeded: \(response)")

  case let .failure(error):
    print("failed: \(error.localizedDescription)")
  }
}
```

###### Objective-C

```objectivec
NSArray *gps = [NSArray arrayWithObjects:@"35.9296,@"-78.9482",nil];

[self signal: gps toChannel: @"locations.route1"
    completion:^(PNPublishStatus *status) {

  NSLog(@"%@status '%@'", status);
}];
```

###### Java

```java
// Java SDK uses channel-based publish
String[] gps = new String[]{"35.9296","-78.9482"};

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

channel.signal(gps)
  .async(result -> { /* check result */ });
```

###### C#

```csharp
string[] arrayMessage = new string[] {"35.9296","-78.9482"};

pubnub.Signal()
  .Message(data)
  .Channel("locations.route1")
  .Execute(new PNPublishResultExt(
    (result, status) => {
      if (status.is_error()) {
        Console.WriteLine("status code: " + status.ErrorData.Information);
      }
      else {
        Console.WriteLine("timetoken: " + result.Timetoken);
      }
    }
  ));
```

###### Python

```python
def signal_callback(result, status):
  if status.is_error():
    print status.status_code
  elif
    print result.timetoken

pubnub.signal()\
  .channel("locations.route1") \
  .message({"msg": "Hello, my friend!"})\
  .pn_async(signal_callback)
```

The Signal response may not be as important to your application and could be omitted, but is dependent on your use case.

### Receive signals

To receive a signal, your client should [implement a signal listener](https://www.pubnub.com/docs/general/messages/receive) and [subscribe](https://www.pubnub.com/docs/general/channels/subscribe) to a channel in which the signal is being sent.

## Publish with metadata fields

The `meta` parameter allows you to attach additional data to messages that remains separate from the message payload. Metadata fields serve two important purposes in PubNub applications: enabling subscribe filtering and maintaining data accessibility when using message encryption.

:::tip Subscribe filtering
Metadata fields can be filtered using [subscribe filters](https://www.pubnub.com/docs/general/channels/subscribe-filters), enabling server-side message routing based on user roles, priorities, geographic location, or other criteria.
:::

###### Trigger server-side processing on publish

Each publish event can trigger server-side logic automatically. [Functions](https://www.pubnub.com/docs/serverless/functions/overview) run before or after delivery to transform payloads, add fields, or block messages that fail validation. [Events & Actions](https://www.pubnub.com/docs/serverless/events-and-actions/overview) forward publish events to external services for storage, analytics, or further processing without additional client-side code. See [event types](https://www.pubnub.com/docs/serverless/functions/overview#event-types) for the full list of Function triggers and [E&A event sources](https://www.pubnub.com/docs/serverless/events-and-actions/events#messages) for supported message events.

Key benefits of metadata fields include:

* **Subscribe filtering support** - Metadata fields can be filtered using [subscribe filters](https://www.pubnub.com/docs/general/channels/subscribe-filters), enabling sophisticated message routing based on user roles, priorities, geographic location, or other criteria
* **Encryption compatibility** - When using AES-256 or other message encryption, metadata fields remain unencrypted and accessible to PubNub services like Functions, Illuminate, and Subscribe Filtering, while the message payload stays encrypted

To include metadata with your published messages, prepare the metadata object and pass it via the `meta` parameter.

:::note User ID / UUID
User ID is also referred to as **UUID/uuid** in some APIs and server responses but **holds the value** of the **userId** parameter you [set during initialization](https://www.pubnub.com/docs/general/setup/users-and-devices#set-the-user-id).
:::

###### JavaScript

```javascript
// Publishing with comprehensive metadata
pubnub.publish(
  {
    channel: "notifications",
    message: {
      title: "System Maintenance",
      body: "Scheduled maintenance window starting soon",
      timestamp: new Date().toISOString()
    },
    meta: {
      priority: "high",
      department: "engineering", 
      region: "San Francisco",
      publisher: pubnub.getUserId(),
      requiresAck: true
    }
  },
  function(status, response) {
    console.log(status, response);
  }
);
```

###### Swift

```swift
// Publishing with comprehensive metadata
pubnub.publish(
  channel: "notifications",
  message: [
    "title": "System Maintenance",
    "body": "Scheduled maintenance window starting soon",
    "timestamp": ISO8601DateFormatter().string(from: Date())
  ],
  meta: [
    "priority": "high",
    "department": "engineering",
    "region": "San Francisco",
    "publisher": pubnub.configuration.userId,
    "requiresAck": true
  ]
) { result in
  switch result {
  case let .success(response):
    print("Successful Publish Response: \(response)")

  case let .failure(error):
    print("Failed Publish Response: \(error.localizedDescription)")
  }
}
```

###### Objective-C

```objectivec
// Publishing with comprehensive metadata
NSDictionary *message = @{
  @"title": @"System Maintenance",
  @"body": @"Scheduled maintenance window starting soon",
  @"timestamp": [[NSDateFormatter new] stringFromDate:[NSDate date]]
};

NSDictionary *meta = @{
  @"priority": @"high",
  @"department": @"engineering",
  @"region": @"San Francisco",
  @"publisher": self.pubnub.currentConfiguration.uuid,
  @"requiresAck": @YES
};

[self.pubnub publish:message
      toChannel:@"notifications" withMetadata:meta
      completion:^(PNPublishStatus *status) {
    NSLog(@"Publish status: %@", status);
}];
```

###### Java

```java
// Publishing with comprehensive metadata
Map<String, Object> message = new HashMap<>();
message.put("title", "System Maintenance");
message.put("body", "Scheduled maintenance window starting soon");
message.put("timestamp", Instant.now().toString());

Map<String, Object> meta = new HashMap<>();
meta.put("priority", "high");
meta.put("department", "engineering");
meta.put("region", "San Francisco");
meta.put("publisher", pubnub.getConfiguration().getUserId().getValue());
meta.put("requiresAck", true);

Channel channel = pubnub.channel("notifications");
channel.publish(message)
  .meta(meta)
  .async(result -> { /* check result */ });
```

###### C#

```csharp
// Publishing with comprehensive metadata
var message = new {
  title = "System Maintenance",
  body = "Scheduled maintenance window starting soon",
  timestamp = DateTime.UtcNow.ToString("O")
};

Dictionary<string, object> meta = new Dictionary<string, object>
{
  {"priority", "high"},
  {"department", "engineering"},
  {"region", "San Francisco"},
  {"publisher", pubnub.PNConfig.UserId},
  {"requiresAck", true}
};

pubnub.Publish().Channel("notifications").Meta(meta)
  .Message(message)
  .Execute(new DemoPublishResult());
```

###### Python

```python
# Publishing with comprehensive metadata
from datetime import datetime

message = {
    "title": "System Maintenance",
    "body": "Scheduled maintenance window starting soon", 
    "timestamp": datetime.utcnow().isoformat()
}

meta = {
    "priority": "high",
    "department": "engineering",
    "region": "San Francisco", 
    "publisher": pubnub.config.user_id,
    "requiresAck": True
}

pubnub.publish()\
  .channel("notifications")\
  .meta(meta)\
  .message(message)\
  .sync()
```

In the above examples, the metadata enables powerful filtering capabilities on the subscriber side. For instance, subscribers could filter for:

* High-priority messages: `meta.priority == "high"`
* Department-specific notifications: `meta.department == "engineering"`
* Regional content: `meta.region == "San Francisco"`
* Messages requiring acknowledgment: `meta.requiresAck == "true"`

The metadata fields remain accessible even when message encryption is enabled, making them ideal for routing and filtering while keeping sensitive message content secure.

For complete subscribe filtering documentation and syntax reference, see [Subscribe Filter Details](https://www.pubnub.com/docs/general/channels/subscribe-filters).

## Terms in this document

* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
