Real-Time

Methods for Reliable Message Delivery for Real-time Apps

0 MIN READ • Oliver Carson on Jun 5, 2026

Ensuring messages are delivered promptly and accurately in real-time applications is crucial in enhancing user experience and building trust with your users. However, achieving this reliability can be challenging, as many of the issues that come with guaranteeing message delivery are typically beyond the control of real-time messaging systems.

Two properties are worth separating before going further. Ordering is guaranteed by the platform: PubNub assigns every published message a monotonically increasing 17-digit timetoken, so messages on a channel form a single ordered sequence and subscribers receive them in that order. Live delivery is at-most-once: a subscriber on a clean connection never receives a duplicate of a message it already got, but it can miss messages if its buffer overflows or if it was disconnected when the message was published. Everything below is about closing that second gap.

Challenges in Guaranteeing Message Delivery

Reliably delivering messages in real-time applications can be impeded by several challenges, regardless of the platform’s infrastructure and functionality:

  • Network instability and latency: Fluctuations in network quality can cause significant delays or even complete loss of messages as they are delivered. Network congestion and packet loss can leave a subscriber behind the publish rate, and once its receive buffer overflows the oldest messages are discarded - so messages go missing rather than arriving out of order.
  • Device connectivity issues: Devices connected to the internet via Wi-Fi or especially through mobile networks can be prone to connectivity issues. Mobile users might have poor signal strength as they move, and devices can be unexpectedly shut down due to battery life or sudden application closure.
  • Server-side limitations and inefficient architecture: Servers might experience overloads during peak usage times, leading to performance degradation, especially if the server is not properly architected to handle the real-time data. If there are no mechanisms in place to retry and retrieve these failed messages, messages can be lost and not delivered in real time.
  • External factors: A range of external factors can affect message delivery, often beyond the control of both the real-time platform and its users. Power outages can knock out data centers, and issues with internet service providers (ISPs) can significantly disrupt message delivery.

Methods to Improve Message Delivery Reliability

Although some of these challenges are completely out of the control of the real-time provider and its users, application design can help reduce message loss and recover missed messages.

Let Timetokens Order Your Messages

You do not need a client-side sequence field to reproduce the platform’s per-channel timetoken order. PubNub assigns each published message a monotonically increasing timetoken server-side - a 17-digit value - so messages on a channel form a single ordered sequence and subscribers receive them in that order without any client-side coordination. The ordering is per channel, and it holds for messages replayed later from Message Persistence, because every stored message carries the timetoken it was assigned at publish time.

This platform ordering does not establish your application’s intended business order for concurrent publish requests. If one event must follow another, coordinate that dependency in your application. You must also handle gaps in delivery. If a subscriber falls behind, the default subscriber message buffer holds 100 messages for up to 16 minutes and drops the oldest first (FIFO). Keep the timetoken of the last message your app actually handled, and replay from it after any gap - see Message ordering and Connection Management.

Bundling Messages

Bundling is an application-side pattern rather than a platform feature: you combine several small updates into one publish, which cuts the number of API calls and the number of chances for a call to fail. Three limits shape how far it pays off:

  • A single message can be up to 32 KiB, counting the escaped character count and the channel name.
  • Under transaction-based pricing, one transaction covers up to a 2048-byte payload, and anything larger is counted as multiple transactions split into 2 KiB parts. Bundling can reduce billed publish transaction units even above 2048 bytes: compare the units required by the combined payload with the sum for separate publishes. For example, ten separate 300-byte payloads use ten publish transaction units, while a combined payload that stays within 4096 bytes after serialization uses two. This comparison covers publish transaction units; other usage charges still apply.
  • For high-frequency, disposable updates such as typing indicators or GPS ticks, signals cost less than messages - but they are limited to 64 bytes, cannot be persisted or trigger push notifications, and should be sent on their own channels.

The trade-off is real: a bundle adds the latency you spend waiting to fill it, and coarsens recovery, since one lost bundle is n lost updates.

Architectural Choices

Message aggregation and sharding can significantly reduce the risk of message loss due to server overloads. Rather than subscribing a server to every channel - a channel list that grows indefinitely and loads unevenly - clients dual-publish to their normal channel and to one server-inbound shard, and your back end subscribes only to the shards. Use a consistent hash such as CRC32 or FNV-1a modulo the shard count so publishes spread evenly, since a single hot shard is what tips a distributed consumer over its capacity limits.

Be sure to take a look at our message aggregation and sharding documentation for more information, as well as our architecture recommendations to help improve message delivery.

Auto-Reconnect and Replay

Automatic retry behavior depends on the SDK, its version, and its configuration. The general connection-management documentation describes a default exponential policy for subscribe operations with up to 6 attempts and delays ranging from 2 to 150 seconds, but some SDKs do not retry subscribe operations by default. It also describes a linear policy with 10 attempts and a 2-second minimum interval plus jitter. Check your SDK’s configuration reference for the applicable defaults and whether publish or signal operations are retried; do not assume identical behavior across SDKs. If you add your own retry around a publish, treat each attempt as a new message with its own timetoken and design consumers to tolerate the occasional duplicate; PubNub does not deduplicate publishes server-side. See reconnection policy for the configurable parameters.

Recovery of the messages published while a client was away happens through two independent mechanisms - one does not fall back to the other:

  • Automatic buffer replay, for short gaps. When the SDK preserves the subscription cursor across reconnects, the client resumes from that cursor and receives what is still buffered: 100 messages for up to 16 minutes by default, oldest discarded first. If your subscribers routinely fall behind, PubNub support can provision a larger buffer, for example 300 or 500 messages, for your keyset.
  • Manual replay from Message Persistence, for anything longer. Save the timetoken of the last message received before the gap - not the one your listener reports after automatic catch-up has already advanced the cursor - increment it by 1, and pass it as the inclusive end parameter. Timetokens exceed Number.MAX_SAFE_INTEGER, so increment with an arbitrary-precision type such as BigInt. A standard fetch request returns up to 100 messages for one channel, or 25 messages per channel for up to 500 channels. Fetching with message actions has additional limits; see your SDK’s API documentation, for example: JavaScript.

History retrieval searches from newest to oldest, although each page is returned in oldest-first order. Keep the pre-gap end boundary fixed. For each subsequent page, set the exclusive start boundary to the oldest timetoken returned on the previous page, and continue until the recovery interval is exhausted. For multiple channels, maintain pagination progress per channel; fetching each channel separately is one way to do this. Assemble the recovered pages in chronological order before processing them, and coordinate replay with live delivery to avoid processing overlapping messages twice. See how messages are fetched.

Persistence only recovers what was actually stored: signals never are, and neither is a message published with storeInHistory/shouldStore set to false or whose per-message ttl has expired. With Unlimited retention, per-message TTL is ignored. Retention runs from 1 day up to Unlimited depending on your keyset - Message Persistence is enabled by default on new keysets, with 7-day retention on testing keysets.

Delivery Confirmation and Publishing Cadence

PubNub orders messages on a channel using server-assigned timetokens. This does not mean concurrent publish requests preserve the business order you intended at the sender. If event B depends on event A, coordinate their publication, for example by waiting for A to succeed before sending B and handling failures before proceeding. Waiting for publish responses also provides backpressure and an opportunity to handle errors, at a cost in throughput.

When you do need delivery confirmation, the REST publish API accepts a qos parameter: setting it to 1 makes the call wait until the message has been placed into each connected subscriber’s receive buffer, giving at-least-once semantics for currently-connected subscribers. This confirms placement in subscriber buffers, not receipt or successful processing by the subscriber application. A failed publish returns an error; retrying can create an additional distinct message, so consumers must tolerate duplicates. qos is REST-only and is not exposed through the SDKs.

Exactly-once processing is something you build on top: attach your own idempotency key to the payload and deduplicate on the receiving side. Some SDKs additionally deduplicate messages that share the same timetoken, publisher, and payload on subscribe - automatic in the Swift SDK, and configurable via dedupOnSubscribe in the C#, Java, Kotlin, and Unity SDKs.

What’s Next

While ensuring reliable message delivery in real-time applications is challenging, you can implement methods in the design of your app to help improve message delivery reliability. PubNub provides per-channel ordering, buffering, SDK reconnection mechanisms, and Message Persistence. Your application must configure these for its needs, track the last successfully processed timetoken, recover gaps, coordinate business ordering, and handle duplicates when retries or replay overlap.

If you would like to learn more about PubNub, be sure to check out PubNub’s features.

Have any questions or feedback? Feel free to reach out to devrel@pubnub.com at any time.

Alternatives like RabbitMQ and Apache Kafka also offer strong delivery guarantees, but they are brokers built for back-end streaming rather than for the last mile out to unreliable mobile and browser clients.