---
title: "Feed SDK"
description: "Activity feeds with posts, likes, comments, and fan-out delivery."
---

# @nolag/feed

Activity feeds with posts, likes, comments, and fan-out delivery.

## Overview

`@nolag/feed` powers real-time activity feeds for social apps, community platforms, and content aggregators. Posts, likes, and comments are delivered live to all subscribers of a channel and replayed for up to 30 days so users joining late always see a full timeline. Fan-out happens server-side: publish once to a channel and every subscriber receives the update instantly.

### Key Features

- Real-time post, like, and comment delivery to all channel subscribers
- 30-day replay across all three topics: posts, reactions, and comments
- Unread post tracking with per-channel badge counts
- Unlike support with live tally updates
- Nested comment threads per post
- Automatic reconnection with channel and state restoration

## How It Works

`NoLagFeed` wraps the `@nolag/js-sdk` client. Calling `joinChannel()` creates a `FeedChannel` that subscribes to three topics: `posts` for post creation events, `reactions` for like and unlike events, and `comments` for comment creation events. A `PostStore` accumulates posts and their reaction counts, while a `CommentStore` groups comments by post ID. An unread counter tracks posts that arrived while the user was away.

| Topic | Purpose | Replay |
| --- | --- | --- |
| `posts` | Post creation events: text, media, author, timestamp | 30 days |
| `reactions` | Like and unlike events with running tally | 30 days |
| `comments` | Comment creation events keyed by post ID | 30 days |

## Installation

```bash [Terminal]
npm install @nolag/feed @nolag/js-sdk
```

## Quick Start

```typescript [TypeScript]
import { NoLagFeed } from '@nolag/feed'

// Create and connect the client
const feed = new NoLagFeed('your-access-token', {
  user: { id: 'user-123', name: 'Alice', avatar: '/img/alice.png' },
})

await feed.connect()

// Join a feed channel (e.g. a user timeline or community feed)
const channel = await feed.joinChannel('user-123-timeline')

// Listen for new posts in real time
channel.on('postCreated', (post) => {
  console.log(`${post.author.name}: ${post.text}`)
  console.log('Likes:', post.likeCount)
})

// Create a post
await channel.createPost({
  text: 'Just shipped a new feature!',
  media: [{ type: 'image', url: '/uploads/screenshot.png' }],
})

// Like a post
await channel.likePost('post-abc')

channel.on('postLiked', ({ postId, likeCount }) => {
  console.log(`Post ${postId} now has ${likeCount} likes`)
})

// Comment on a post
await channel.addComment('post-abc', 'Congrats!')

channel.on('commentAdded', ({ postId, comment }) => {
  console.log(`New comment on ${postId}: ${comment.text}`)
})

// Get unread count and mark as read
console.log('Unread:', channel.unreadCount)
await channel.markRead()

await feed.leaveChannel('user-123-timeline')
feed.disconnect()
```

## API Reference

### NoLagFeed

The main class. Manages the WebSocket connection, global user presence, and feed channel lifecycle.

| Method | Description |
| --- | --- |
| `connect()` | Establish WebSocket connection and announce presence |
| `disconnect()` | Gracefully close the connection and leave all channels |
| `joinChannel(name)` | Join a feed channel; returns a `FeedChannel` instance |
| `leaveChannel(name)` | Leave a channel and unsubscribe from its topics |
| `getOnlineUsers()` | Return all users currently online across all joined channels |

### Events: NoLagFeed

| Event | Payload | Description |
| --- | --- | --- |
| `connected` | none | WebSocket connection established |
| `disconnected` | `reason: string` | Connection closed |
| `reconnected` | none | Reconnection successful; channels are restored automatically |
| `error` | `error: Error` | Unrecoverable error occurred |
| `userOnline` | `user: FeedUser` | A user has come online |
| `userOffline` | `user: FeedUser` | A user has gone offline |

### FeedChannel

Returned by `joinChannel()`. Handles posts, reactions, comments, and unread tracking for a single channel.

| Method / Property | Description |
| --- | --- |
| `createPost(opts)` | Publish a new post with text, optional media array, and custom metadata |
| `likePost(postId)` | Like a post; increments the like count for all subscribers |
| `unlikePost(postId)` | Remove your like from a post |
| `addComment(postId, text)` | Add a comment to the specified post |
| `getPosts()` | Return all posts in the local store, newest first |
| `getComments(postId)` | Return all comments for the specified post |
| `unreadCount` | Number of posts that arrived since `markRead()` was last called |
| `markRead()` | Reset the unread count to zero |

### Events: FeedChannel

| Event | Payload | Description |
| --- | --- | --- |
| `postCreated` | `FeedPost` | A new post arrived from another user |
| `postSent` | `FeedPost` | Confirmation that your own post was delivered |
| `postLiked` | `{ postId: string, likeCount: number, likedBy: string }` | A post received a new like |
| `postUnliked` | `{ postId: string, likeCount: number, unlikedBy: string }` | A like was removed from a post |
| `commentAdded` | `{ postId: string, comment: FeedComment }` | A comment was added to a post |
| `commentSent` | `{ postId: string, comment: FeedComment }` | Confirmation that your own comment was delivered |
| `subscriberJoined` | `user: FeedUser` | A user joined this channel |
| `subscriberLeft` | `user: FeedUser` | A user left this channel |
| `replayStart` | `{ count: number }` | Historical feed replay is beginning |
| `replayEnd` | `{ replayed: number }` | Historical feed replay is complete |
| `unreadChanged` | `{ count: number }` | The unread post count for this channel changed |
