Add Social Feeds

Activity feeds with posts, reactions, threads, and tags

Add activity feeds with posts, reactions, threaded replies, tags, and media to any application using the Recursiv SDK. Works with React, Next.js, React Native, Vue, Svelte, or any TypeScript/JavaScript project.

What You’ll Build

  • Activity feed with paginated posts
  • Post creation with markdown support and media
  • Reactions (like, heart, fire, laugh, sad, angry)
  • Threaded replies
  • Tag-based categorization and search
  • Filtered feeds (by community, author, tag)

Prerequisites

  • Node.js 18+ (22+ recommended)
  • A Recursiv API key with posts:read and posts:write scopes
  • npm install @recursiv/sdk

Step 1: Initialize the SDK

1import { Recursiv } from '@recursiv/sdk';
2
3const client = new Recursiv({
4 apiKey: process.env.RECURSIV_API_KEY!,
5});

Step 2: Create Posts

1// Simple text post
2const { data: post } = await client.posts.create({
3 content: 'Just shipped a new feature!',
4 content_format: 'plain',
5});
6
7// Markdown post with tags
8const { data: richPost } = await client.posts.create({
9 content: '# Release v2.0\n\nWe just shipped **social feeds** with full markdown support.',
10 content_format: 'markdown',
11 tag_ids: ['tag_release', 'tag_product'],
12});
13
14// Post to a specific community
15const { data: communityPost } = await client.posts.create({
16 content: 'Discussion: What features do you want next?',
17 community_id: 'comm_abc',
18});
19
20// Reply to a post (threaded)
21const { data: reply } = await client.posts.create({
22 content: 'Great update! Love the markdown support.',
23 reply_to_id: richPost.id,
24});

Step 3: Fetch and Display Feeds

1// Global feed
2const { data: posts, meta } = await client.posts.list({ limit: 20 });
3
4// Community feed
5const { data: communityPosts } = await client.posts.list({
6 limit: 20,
7 community_id: 'comm_abc',
8});
9
10// User's posts
11const { data: userPosts } = await client.posts.list({
12 limit: 20,
13 author_id: 'user_xyz',
14});
15
16// Search posts
17const { data: results } = await client.posts.search({
18 q: 'typescript tutorial',
19});
20
21// Pagination
22if (meta.has_more) {
23 const page2 = await client.posts.list({ limit: 20, offset: 20 });
24}

Step 4: Reactions

1// React to a post
2await client.posts.react(post.id, 'fire');
3
4// Remove a reaction
5await client.posts.unreact(post.id, 'fire');
6
7// Available reactions: 'like' | 'heart' | 'fire' | 'laugh' | 'sad' | 'angry'

Step 5: Tags for Organization

1// Create tags
2const { data: tag } = await client.tags.create({
3 name: 'announcement',
4 description: 'Official announcements',
5 color: '#3b82f6',
6});
7
8// Search posts by tag
9const { data: tagged } = await client.posts.search({
10 q: 'release',
11 tag_ids: tag.id,
12});

React Feed Component Example

1import { useState, useEffect, useCallback } from 'react';
2import { Recursiv, type Post } from '@recursiv/sdk';
3
4const client = new Recursiv({ apiKey: process.env.NEXT_PUBLIC_RECURSIV_KEY! });
5
6function SocialFeed({ communityId }: { communityId?: string }) {
7 const [posts, setPosts] = useState<Post[]>([]);
8 const [loading, setLoading] = useState(true);
9
10 const loadPosts = useCallback(async () => {
11 setLoading(true);
12 const { data } = await client.posts.list({
13 limit: 20,
14 community_id: communityId,
15 });
16 setPosts(data);
17 setLoading(false);
18 }, [communityId]);
19
20 useEffect(() => { loadPosts(); }, [loadPosts]);
21
22 const handleReact = async (postId: string, type: string) => {
23 await client.posts.react(postId, type as any);
24 loadPosts(); // refresh
25 };
26
27 if (loading) return <div>Loading feed...</div>;
28
29 return (
30 <div className="feed">
31 {posts.map(post => (
32 <article key={post.id} className="post">
33 <header>
34 <img src={post.author.image || '/default-avatar.png'} alt="" />
35 <span>{post.author.name}</span>
36 <time>{new Date(post.created_at).toLocaleDateString()}</time>
37 </header>
38 <div className="content">{post.content}</div>
39 <footer>
40 <button onClick={() => handleReact(post.id, 'like')}>
41 Like ({post.reactions_count})
42 </button>
43 {post.tags.map(tag => (
44 <span key={tag.id} className="tag">{tag.name}</span>
45 ))}
46 </footer>
47 </article>
48 ))}
49 </div>
50 );
51}

What’s Included vs Building from Scratch

FeatureRecursivBuilding from Scratch
Activity feedclient.posts.list()Design schema, build API, handle pagination, caching
Post creationclient.posts.create()Input validation, markdown parsing, media handling
Reactionsclient.posts.react()Reaction aggregation, deduplication, real-time sync
Threaded repliesreply_to_id fieldRecursive thread loading, depth limiting, UI
Tag systemclient.tags.create()Tag CRUD, post-tag relations, search indexing
Full-text searchclient.posts.search()PostgreSQL FTS or Elasticsearch setup, query parsing
Feed algorithmsChronological + filteredRanking algorithms, personalization, A/B testing

Time to ship: Hours with Recursiv vs months from scratch.

Next Steps