Skip to content

Follow

A follow edge points from one feed to another, e.g. timeline:maya follows user:diego. There is no backfill: a follow only affects activities posted after the edge exists (copy_limit=0, spec §1) — following someone doesn’t retroactively pull their history into your timeline. Follower/following counts are denormalized (spec §4) and read without a COUNT(*).

// client.feed(sourceGroup, sourceId).follow(targetGroup, targetId)
await client.feed('timeline', 'maya').follow('user', 'diego')
await client.feed('timeline', 'maya').unfollow('user', 'diego')

Unfollowing hard-deletes the edge and enqueues a scrub of the follower’s copies of that feed’s activities, so their timeline loses the history shortly after — the delete is immediate, the scrub is a background job. Re-following is a genuine new edge — new created_at, a fresh follow.added webhook — but it does not produce a second notification: those are unique per (owner, verb, actor, object) for the life of the account, so unfollow/re-follow cannot be used to ping someone repeatedly. See what will never create a second notification.

And re-following does not backfill: like any follow, the timeline picks up the target’s activities from the next post onward, not the ones posted while unfollowed.

Import the existing graph before you mirror it

Section titled “Import the existing graph before you mirror it”

Mirroring live follows only covers edges created from now on. If your product already has a follow graph, every existing user’s timeline is empty on day one — they follow people, and nothing arrives, because dropin has never heard of those edges.

So the order is: import first, then start mirroring.

// One-off, before (or alongside) the trigger that mirrors live follows.
await server.batch.userFollows(
edges.map(({ follower, following }) => ({ follower, following })),
)

100 edges per call, quiet — nobody is notified that they were “followed” by someone who followed them two years ago. Full recipe, including how to page a large graph: Migrating existing data.

Self-follow is accepted: maya may follow maya, and it increments her public follower_count like any other edge. Nothing rejects it, so do not use it as a trick to get someone’s own posts into their timeline — the inflated counter is visible to every reader.

A timeline contains exactly what its follow edges bring in, and nothing else — a user’s own posts land in user:maya, not timeline:maya. To render “my feed including my own posts”, read both and merge client-side:

const [mine, timeline] = await Promise.all([
client.feed('user', 'maya').get(),
client.feed('timeline', 'maya').get(),
])

Merge on time descending, and de-duplicate on id — an activity can legitimately appear in both if someone you follow reposted it into a feed you also read.

const stats = await client.feed('user', 'diego').followStats()
stats.follower_count
stats.following_count

For the lists themselves rather than the counts. Both return a Page<Follow>, newest edge first, keyset-paginated.

const followers = await client.feed('user', 'diego').followers({ limit: 20 })
const following = await client.feed('timeline', 'maya').following({ limit: 20 })

Suggestions are user: feeds a feed doesn’t already follow, ranked by mutual overlap (feeds followed by feeds it follows — friends-of-friends), then topped up by global popularity for a cold-start feed with a thin graph. Call it on the timeline:<id> feed — following happens from the timeline side (spec §5), so that’s the graph walked.

const { results } = await client.feed('timeline', 'diego').suggestions({ limit: 25 })
results // [{ group: 'user', id: 'anna', mutuals: 3 }, …] — best first

mutuals is how many of the caller’s follows also follow that suggestion; a popularity-fill suggestion has mutuals: 0. This is a capped top-N, not a page — limit defaults to 25 (max 50), and there’s no cursor or next. Reads are open within a tenant, so any valid token — including a server-minted one — can fetch suggestions for any feed.

  • Feeds — the timeline these edges feed, and why a new follow shows no history.
  • Notifications — what the followed user receives.
  • Migrating existing data — importing an existing follow graph, quietly, versus mirroring live follows.
  • Webhooks — follow.added / follow.removed.
  • Promoted activities — targeting an audience by following users into a feed such as city:belgrade.