Skip to content

fix(feed): keep For You feed populated (no empty-state flash + live recommended endpoint)#14446

Closed
dylanjeffers wants to merge 2 commits into
mainfrom
fix/for-you-feed-empty-overwrite
Closed

fix(feed): keep For You feed populated (no empty-state flash + live recommended endpoint)#14446
dylanjeffers wants to merge 2 commits into
mainfrom
fix/for-you-feed-empty-overwrite

Conversation

@dylanjeffers
Copy link
Copy Markdown
Contributor

@dylanjeffers dylanjeffers commented Jun 4, 2026

This PR has two commits, both keeping the For You feed populated:

  1. Stop the feed from blanking to the follow-artists empty state (timing/race fix)
  2. Back the feed with the live /tracks/recommended endpoint (the new for-you endpoint 404s in prod)

Commit 1 — stop the empty-state flash

Summary

The For You feed renders real tracks for a split second and then swaps in the "follow artists" empty state — even for users who follow plenty of people. The data lands and renders correctly, then something overwrites it with empty.

Root cause

The empty state is purely lineup-driven (entries.length === 0 on mobile, tiles.length === 0 on web) — there is no follow-count check, so a momentarily-empty response is indistinguishable from "follows nobody." useForYouFeed returns data = query.data ?? [], so anything that makes query.data empty surfaces the follow prompt.

useForYouFeed set no staleTime. With the react-query default of 0, the personalized query refetches on the next mount/focus right after the first paint. When that refetch settles empty — a transient backend result, or a different validator node in the fleet returning no items for this user — react-query replaces the just-rendered pages with []. The feed appears, then blanks. (The chronological Latest feed shares the same render path but its backend is deterministic, so its refetch returns the same data and it never visibly blanks — which is why only For You is affected.)

A secondary trap: enabled was gated on currentUserId !== null, which is true while the account is still loading (currentUserId is undefined). The query then runs its !currentUserId guard and caches [] under the [forYouFeed, undefined] key — a stale empty entry a later render could briefly surface.

Fix

packages/common/src/api/tan-query/lineups/useForYouFeed.ts:

  • staleTime: Infinity (overridable via options) — the loaded feed stays stable for the session instead of being re-fetched-and-clobbered. Pagination is unaffected (fetchNextPage ignores staleTime). This matches the existing pattern in useLibraryTracks.
  • enabled: ... && currentUserId != null (excludes undefined) — the query no longer runs / seeds an empty cache entry while the account is resolving. isDisabled still keys off === null, so during account load the consumer shows skeletons (not the empty state).

Commit 2 — back the feed with the live /tracks/recommended endpoint

Problem

The For You tab is empty in production because it calls the new GET /v1/users/{id}/feed/for-you endpoint (sdk.users.getUserForYouFeed()), which 404s on the current validator-node deployment and won't be fixed for ~a week.

Fix

Point useForYouFeed at GET /v1/tracks/recommended (sdk.tracks.getRecommendedTracks) — the long-standing, personalized recommendation source the Explore page used before the For You feed existed. It reliably returns 200 from api.audius.co today (verified: for-you → 404 on the old fleet, /tracks/recommended → 200).

Pagination: /tracks/recommended has no offset parameter, but it accepts an exclusionList. Pagination now passes the accumulated already-seen track ids as the exclusion list, so each page returns fresh recommendations without repeats. The pageParam carries that list.

Compatibility: the hook keeps its existing return shape (a tracks-only LineupData[] plus derived trackIds), so the feed-page consumers (FeedPageContent web desktop/mobile, mobile FeedScreen) are unchanged.

This is a temporary fallback — revert to getUserForYouFeed() once the dedicated endpoint is deployed (a NOTE comment in the hook calls this out).


Verification status

  • tsc --noEmit passes for @audius/common
  • Verified https://api.audius.co/v1/tracks/recommended?limit=3 returns 200
  • ⚠️ On-device verification still pending. The empty-state flash is a sub-second race that isn't reliably reproducible through the browser preview. Recommend confirming on a mobile build signed in as a user with a real following graph: feed populates with recommended tracks, "load more" pages without duplicates, no empty-state flash.

🤖 Generated with Claude Code

…y state

The For You feed would render real tracks for a split second and then swap in
the "follow artists" empty state, even for users who follow plenty of people.

`useForYouFeed` set no `staleTime`, so with the react-query default of 0 the
personalized query refetched on the next mount/focus immediately after the
first paint. When that refetch settled empty — a transient backend result, or
a different validator node in the fleet returning no items — react-query
replaced the just-rendered feed with `[]`. The lineup reads an empty list as
"no content" and renders the SuggestedFollows / FollowArtists prompt, so the
feed appears then blanks. The empty-state has no follow-count check, so a
momentary empty response is indistinguishable from "follows nobody."

- Set `staleTime: Infinity` (overridable via options) so the loaded feed is
  stable for the session and isn't re-fetched-and-clobbered. Pagination is
  unaffected (fetchNextPage ignores staleTime).
- Gate `enabled` on `currentUserId != null` (excluding `undefined`) so the
  query doesn't run while the account is still resolving and cache `[]` under
  the `[forYouFeed, undefined]` key — a stale empty entry a later render could
  briefly surface as the empty state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 4, 2026

🦋 Changeset detected

Latest commit: bacadd1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@audius/common Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🌐 Web preview ready

Preview URL: https://audius-web-preview-pr-14446.audius.workers.dev

Unique preview for this PR (deployed from this branch).
Workflow run

The dedicated GET /v1/users/{id}/feed/for-you endpoint is not yet rolled
out across the validator-node fleet and 404s in production, so the For
You tab renders empty. Fall back to GET /v1/tracks/recommended
(sdk.tracks.getRecommendedTracks) — the same personalized recommendation
source the Explore page used before the For You feed existed, which
reliably returns 200 from api.audius.co today.

/tracks/recommended has no offset param, so pagination passes the
already-seen track ids as exclusionList; each page returns fresh
recommendations that don't repeat earlier ones. The pageParam carries
the accumulated exclusion list. The hook keeps its existing return shape
(tracks-only lineup) plus the prior staleTime/enabled hardening, so
feed-page consumers are unchanged.

Swap back to getUserForYouFeed() once the new endpoint is deployed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/L and removed size/S labels Jun 4, 2026
@dylanjeffers dylanjeffers changed the title fix(feed): stop For You feed from blanking to the follow-artists empty state fix(feed): keep For You feed populated (no empty-state flash + live recommended endpoint) Jun 4, 2026
@dylanjeffers dylanjeffers deleted the fix/for-you-feed-empty-overwrite branch June 4, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant