The subscribe model in PubNub

Subscribing is how a PubNub client receives what other clients publish. A subscription names one or more channels, and the PubNub network then pushes every event that arrives on them to that client without the client polling for it. This page explains:

  • what a subscription addresses, and what scopes the handlers attached to it
  • how one connection carries many subscriptions
  • when a client is eligible to receive, and what happens to what it misses
  • how a server-side subscribe filter narrows the stream before it reaches the client
  • how filtering differs for messages you retrieve from history

One rule holds throughout. A client receives only what arrives on the channels it is subscribed to, and only while that subscription is active. Both the set of channels and the window of time decide what a client sees. Subscribing uses the subscribe key from your keyset, and to create one, refer to Set up your account.

What a subscription addresses​

A subscription identifies the channels, channel groups, or other resources from which a client receives events. Entity-capable SDKs represent that scope with local Subscription and SubscriptionSet objects. SDKs without entities subscribe and register handlers on the PubNub client instead. For the object types, entity scopes, and handler boundaries, refer to Subscriptions and subscription sets. For the handler model and the code that sets it up, refer to Event listeners and Receive messages.

Subscribing is also the delivery path for more than messages. Signals, file events from File Sharing, App Context metadata changes, message action events, and presence events all arrive on the same subscription, each through its own handler. Each one also depends on its feature being enabled on the keyset. For the full event list and the fields each one carries, refer to Events.

One connection carries every subscription​

Subscriptions do not each get a socket. The SDK runs a single subscribe loop that names every currently subscribed channel and channel group in one request. The PubNub network holds that request open instead of answering immediately. An event arrives as the response, and the SDK immediately issues the next request from the timetoken it just received. A subscribe request is held open for up to 310 seconds before the client reissues it with an updated timetoken cursor. Each PubNub client instance uses two TCP sockets: one for subscribe requests and one for all non-subscribe operations.

Subscribing to several channels this way is called multiplexing, and it has two consequences worth designing around:

  • Subscribing again adds rather than replaces. A client that subscribes to chats.room1 now and chats.room2 later ends up receiving both, exactly as if it had named them together. Unsubscribing removes a channel from the same list.
  • The channel list travels in the request. Because every subscribed channel name is part of the subscribe request, long channel names and large channel counts both grow it, and the request has a size ceiling. For the recommended channel count per client and the URI length limit, refer to API limits.

The subscribe loop is the SDK's responsibility, so your code never opens the socket, schedules the next request, or decides when to retry. For the transport, the retry policies, and the status events that report both, refer to Connection management.

Three ways to name what you receive​

A client can reach a set of channels three ways, and they differ in who owns the list of channel names.

MechanismWho controls the listWhat it costs to change the list
Explicit channel namesThe clientThe client subscribes or unsubscribes
Channel groupYour serverNothing on the client, which keeps receiving whatever the group now holds
Wildcard pattern such as alerts.*Your naming schemeNothing, because a matching channel is covered the moment it is used

A channel group is a server-managed, named list of channels that a client subscribes to with a single call. Adding or removing channels in a channel group server-side changes what every subscribed client receives without any client resubscribing. That makes groups the right tool when your backend decides membership, and it lets your server take a channel away from a client. Channel groups support subscribe operations only, so you can't publish to a group. Channel groups require the Stream Controller add-on enabled on the keyset.

Each PubNub keyset supports up to 10 channel groups. Each group holds up to 1,000 channels by default. Paid plans can raise the cap to 2,000 channels per group.

A wildcard subscription matches by name instead of by list. Subscribing to alerts.* receives alerts.fire, alerts.flood, and every other channel matching the pattern, including channels that first carry traffic after the subscription started. A pattern must end with .*, you cannot publish to a pattern, and wildcard depth is bounded, so refer to API limits before designing a deep hierarchy. Channel group names cannot contain a period, so wildcards do not apply to groups. Wildcard subscribe requires the Stream Controller add-on with the Wildcard Subscribe option enabled on the keyset.

When Presence is enabled, each channel has a -pnpres companion channel carrying join, leave, and timeout events for it. Receiving those events requires the presence option set when the subscription is created, and it is a separate decision from subscribing to the channel itself. Refer to Receive presence events.

When a client is eligible to receive​

The live path delivers to the clients subscribed at the moment an event is published, and to nobody else. A client that was disconnected, or that had not yet subscribed, does not get that event on the live path.

Live delivery to subscribers is at-most-once by default. On a stable connection, a subscriber receives each message at most once. After a reconnect, a replayed message can arrive again with the same timetoken. A subscriber can also miss messages if its buffer overflows or if it's disconnected when someone publishes a message.

Two mechanisms cover the gap, and they differ in how far back they reach.

The subscriber message buffer queues messages for a reconnecting client. It holds 100 messages for up to 16 minutes by default, and discards the oldest first (FIFO) when a burst exceeds that size. Larger buffers, for example 300 or 500 messages, can be provisioned per keyset by PubNub Support.

For anything longer than the buffer holds, replay comes from Message Persistence. It stores messages so a client can fetch what it missed by timetoken, once the feature is enabled on the keyset. Signals are never stored, so a signal a client was not present for is gone.

Both mechanisms depend on the timetoken cursor the SDK carries, which is what a reconnecting client resumes from. Recovery is also why the status listener matters on the subscriber side. A held-open request that returns nothing looks exactly like a quiet channel, so a client that ignores status events cannot tell an idle channel from a stream it stopped receiving. Refer to The timetoken cursor and The status listener.

Filtering what a client receives​

A subscriber rarely wants everything on the channels it names. There are three places to narrow the stream, and the earlier you do it, the less the client pays.

Where filtering happensMechanismWhat it saves
At publish timeChannel design, so unwanted traffic never shares a channelEverything, because the client never names the channel
On the PubNub networkA subscribe filter expression evaluated server-sideBandwidth and battery, because non-matching messages are never sent
In the clientA per-subscription predicate in SDKs that offer one, or a branch in the handlerOnly application work, because the message already arrived

Channel design is the blunt instrument and usually the right first move, because a channel a client does not subscribe to costs it nothing. Filtering handles the case a channel split cannot, when one channel is shared by many subscribers who each want a different slice of it.

Filter on the server​

A subscribe filter is an expression PubNub evaluates on the server against each message before deciding whether to deliver it to a given client. Only matching messages reach that client, so a filtered-out message consumes no bandwidth, no battery, and no client-side parsing.

A subscribe filter is a property of the client, not of one subscription or channel, so it applies to every channel and channel group that client subscribes to. Some SDKs accept it only when the client is initialized rather than allowing later changes. A client that needs different rules for different channels therefore needs either separate client instances or a second filtering step in its handlers.

A filter can evaluate only values the publisher puts in the message payload or meta. It cannot evaluate envelope values such as the publisher's User ID, channel name, timetoken, or internal message type. Decide at publish time which values subscribers may need to filter on, and put them in meta. Metadata values must be JSON-serializable.

When message encryption is enabled, a subscribe filter cannot read data.*. meta.* remains unencrypted and filterable, so never put a secret in meta.

For the expression syntax, data types, invalid expressions, and efficiency guidance, refer to Subscribe filter expressions. For the calls that set an expression on a client, refer to Filter received messages.

Filtering messages you retrieve from history​

Retrieval is a different mechanism from live delivery, and a subscribe filter has no counterpart on it. Message Persistence prioritizes low-latency retrieval and offers no server-side content filtering, so a history call returns what the channel stored in the timetoken range you asked for.

That leaves two approaches:

  • Filter on the client after retrieving. Fetch the range you need and discard what you do not want. Filter by the internal message type, or by the custom message type you set at publish time, such as vip-chat or intruder-alert. 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. Timetoken boundaries are the one selective control the retrieval call itself gives you, so narrow the range before you widen the filter. Refer to Retrieve message history.
  • Index the messages somewhere that can search. An After Publish Function can write each message to your own database as it passes through the network, which gives you server-side search with whatever query language that database offers. Event forwarding does the same routing without code.

What subscribing does not give you​

  • No list of who else is subscribed. A subscription tells a client what arrives, not who is listening. Occupancy and join, leave, and timeout events come from Presence.
  • No receipt back to the publisher. Receiving a message reports nothing to its sender. Applications that need delivery or read receipts attach message actions to the original message.
  • No access by default when Access Manager is on. Subscribing to a channel or channel group requires the read permission in the client's token. Refer to Operations to permissions mapping.

Next steps​

Was this page useful?

Last updated on