---
source_url: https://www.pubnub.com/docs/design-patterns/friend-list-and-status-feed
title: Friend List and Status Feed
updated_at: 2026-09-30T07:20:08.000Z
---

# Friend List and Status Feed

## 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.

A friend list shows which of a user's contacts are currently online. A status feed shows updates those contacts post. Both are views onto the same underlying shape: a follow/follower graph where each person's activity needs to reach everyone following them. Neither view works if every follower has to subscribe to every person they follow, one channel at a time. This page covers a pattern built from two fixed channels per user and the [channel groups](https://www.pubnub.com/docs/architecture/core-concepts.md#channel) that [Architectural choices](https://www.pubnub.com/docs/design-patterns/architectural-choices.md#shape-channels-around-traffic-not-the-other-way-around) introduces as a fan-out mechanism for social features like this one.

This is a follow/follower model, not a general graph. It answers "which of my friends are online" and "what did my friends post," not multi-degree questions like mutual friends or shortest path between two users.

## Give every user two fixed channels

Each user gets two channels that never change once created:

* A **status channel**, such as `user-a.status`, that the user publishes updates to.
* An **online channel**, such as `user-a.online`, that the user subscribes to for no reason other than to be present on it. Nothing is ever published there. Its only job is to give other users something to track presence on.

Keeping these fixed and per-user is what makes the rest of the pattern work. Your server can reference "user A's status channel" forever, without knowing in advance who will end up following user A.

## Fan many friends into one subscription with channel groups

A [channel group](https://www.pubnub.com/docs/architecture/core-concepts.md#channel) is a server-managed, named list of channels that a client subscribes to as one unit. Adding or removing a channel from the group changes what every subscribed client receives, with no client resubscribing. That property is what lets a friend list grow or shrink without the viewing client ever touching its own subscription.

Give each user two channel groups, built from the fixed channels of everyone they follow:

* `cg-user-a-online`, holding the **online channel** of every person user A follows.
* `cg-user-a-feed`, holding the **status channel** of every person user A follows.

User A subscribes to both groups exactly once. From then on, following or unfollowing someone is a change your server makes to group membership, not a change user A's client makes to its own subscription list.

Your server adds each followed person's online channel to `cg-user-a-online` and their status channel to `cg-user-a-feed`. User A's client subscribes to `cg-user-a-online` with `receivePresenceEvents` to receive presence events, and to `cg-user-a-feed` to receive status messages. Both subscriptions also cover every friend added to the groups later.

```mermaid
flowchart LR
    USER_A["<b>User A's client</b>"]

    subgraph FRIENDS[" "]
        direction TB
        B_PRESENT["user-b.online"]
        B_STATUS["user-b.status"]
        C_PRESENT["user-c.online"]
        C_STATUS["user-c.status"]
    end

    subgraph GROUPS[" "]
        CG_FRIENDS["<b>cg-user-a-online</b><br/>(subscribed with<br/>receivePresenceEvents)"]
        CG_FEED["<b>cg-user-a-feed</b><br/>(subscribed directly<br/>for messages)"]
    end

    USER_A -->|"subscribes once, receives<br/>from every friend added later"| CG_FRIENDS
    USER_A -->|"subscribes once, receives<br/>from every friend added later"| CG_FEED

    B_PRESENT --> CG_FRIENDS
    C_PRESENT --> CG_FRIENDS
    B_STATUS --> CG_FEED
    C_STATUS --> CG_FEED

    class CG_FRIENDS,CG_FEED emphasis
    class B_PRESENT,B_STATUS,C_PRESENT,C_STATUS muted
```

Channel groups require the Stream Controller add-on enabled on the keyset, and both the number of groups and the channels per group carry limits that scale with your plan. Refer to [Core concepts](https://www.pubnub.com/docs/architecture/core-concepts.md#channel) and [Plan comparison](https://www.pubnub.com/docs/pricing/quotas.md#channel-groups) before committing to two groups per user at a scale where that matters, and contact PubNub Support if your design needs a higher ceiling.

## See who's online without subscribing to their messages

Subscribing to `cg-user-a-online` for ordinary messages would be pointless, since nothing is ever published on an online channel. What you actually want is [Presence](https://www.pubnub.com/docs/presence/overview.md) join, leave, and timeout events for every channel currently in that group. Current SDKs give you that through the `receivePresenceEvents` option on the group's subscription, the same option a single channel's subscription uses:

```javascript
const onlineGroup = pubnub.channelGroup('cg-user-a-online');
const onlineSubscription = onlineGroup.subscription({ receivePresenceEvents: true });

onlineSubscription.onPresence = (event) => {
  console.log(`${event.uuid} is now ${event.action}`); // join, leave, or timeout
};

onlineSubscription.subscribe();

const feedGroup = pubnub.channelGroup('cg-user-a-feed');
const feedSubscription = feedGroup.subscription();

feedSubscription.onMessage = (event) => {
  console.log('Status update:', event.message);
};

feedSubscription.subscribe();
```

The snippet above is illustrative rather than a complete program. Call [Here Now](https://www.pubnub.com/docs/presence/get-online-users-in-channel.md) once against the same group to seed the initial online list, then rely on presence events to keep it current. For the full presence event model, including the `-pnpres` mechanism this option builds on, refer to [Presence](https://www.pubnub.com/docs/presence/overview.md#how-presence-delivers-its-data).

## Expand the graph from your server, not the client

Following someone means your server adds their online and status channels to the follower's two groups; unfollowing removes them. Do this from your server, never from the client. A channel group's `manage` permission lets whoever holds it add or remove any channel in that group. A client that could manage its own groups could just as easily add itself to someone else's feed.

Grant `manage` only to server-side tokens, and grant clients `read` on their own groups so they can subscribe. Refer to [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md#resources) for the permission model, and to [Security best practices](https://www.pubnub.com/docs/design-patterns/security.md) for why token issuance belongs on your server in general.

To show a name or avatar next to each entry in the online list, store that profile data in [App Context](https://www.pubnub.com/docs/data-storage/metadata/overview.md) user metadata and look it up by User ID. App Context is a durable profile store, not the graph itself. The follow relationship still lives in channel group membership, exactly as this page has described it.

## Read the feed's history across many channels

The live feed delivers a status update the moment it's published. Retrieving history is less direct than for a single channel, because [Message Persistence](https://www.pubnub.com/docs/data-storage/message-history/overview.md) fetches history per channel, not per channel group. Reconstructing a merged, chronological feed for user A means fetching each followed person's status channel and merging the results yourself, client-side or server-side. There's no single call that returns a channel group's combined history pre-merged.

## Next steps

* [Presence](https://www.pubnub.com/docs/presence/overview.md). Join, leave, timeout, and how presence differs from a stored membership.
* [Core concepts](https://www.pubnub.com/docs/architecture/core-concepts.md#channel). The channel group model this pattern depends on, and its current limits.
* [App Context](https://www.pubnub.com/docs/data-storage/metadata/overview.md). Store profile data to decorate the roster with names and avatars.
* [Access Manager](https://www.pubnub.com/docs/security/access-control/overview.md). Grant `manage` on channel groups to your server only, and `read` to clients.
* [Message Actions](https://www.pubnub.com/docs/pub-sub/message-actions/overview.md). Attach reactions or comments to a status update without a separate channel.
* [Architectural choices](https://www.pubnub.com/docs/design-patterns/architectural-choices.md). Why channel groups replace one subscription per followed user.

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