AlgoMaster Logo

Design a Personalized News Feed

26 min readUpdated May 29, 2026
Listen to this chapter
Unlock Audio

A personalized news feed is the ranked list of posts, photos, videos, and links a user sees when they open a social app like Facebook, LinkedIn, or Twitter/X. The ranking problem looks similar to video or product recommendations on the surface, but three things make it harder: the inventory is heterogeneous, the objective is multi-dimensional, and the shelf life of most posts is measured in hours. Getting one of those three wrong breaks the feed in a different way, which is why this is one of the most instructive ML system design interview problems.

1. Problem Formulation

Clarifying Questions

The feed at Meta looks different from the home timeline at Twitter/X or the feed on LinkedIn. Before drawing any architecture, a candidate should lock down scope, inventory, and what counts as success.

Candidate: "When you say news feed, do you mean the home feed, stories, reels, or all three surfaces?"

Interviewer: "Home feed only. Stories and short-form video have their own rankers. Assume our home feed includes text posts, photos, videos, link shares, and a small amount of sponsored content interleaved."

Candidate: "Is the feed purely algorithmic, or do users see a chronological option as well?"

Interviewer: "Both exist, but we're designing the default algorithmic feed. Chronological is a user setting that bypasses ranking."

Candidate: "How big is the platform? DAU, posts created per day, and average feed loads per user?"

Interviewer: "Around 2 billion registered users, 500 million DAU. About 20 billion new pieces of content per day across all types. An active user opens the feed roughly 10 times a day and scrolls through 50 to 100 items per session."

Candidate: "What's the candidate pool per user? Am I ranking posts only from accounts they follow, or a broader set?"

Interviewer: "Broader. Followed accounts are the seed, but we also mix in posts from second-degree connections, groups the user joined, and a small exploration slice of topical content from strangers. Expect a few thousand eligible posts per user per request."

Candidate: "What's the target latency and size of a single feed response?"

Interviewer: "Return 50 ranked items per request. P99 for the ranking service is 200ms end to end."

Candidate: "How do we handle ads? Are they ranked in the same model or blended in later?"

Interviewer: "Ads come from a separate auction pipeline. The organic ranker returns a sorted list, and an ads-blending service inserts sponsored items at configured slots. You don't need to model the ad auction itself."

Candidate: "What's the north-star metric? Clicks, likes, session time, or something longer-horizon?"

Interviewer: "We've been burned by raw engagement before. Optimizing for clicks pulls the feed toward clickbait and outrage. The north star is a weekly active retention metric combined with self-reported survey scores on how valuable users found their feed. We call that bundle 'meaningful interactions' internally."

Candidate: "What's hard-filtered before ranking? Blocked accounts, integrity-flagged content, anything else?"

Interviewer: "Hard filters: blocks, mutes, reported accounts, posts flagged by integrity classifiers above a safety threshold, content the user has already seen in the last 24 hours, and content outside the user's locale when required by regional policy. Everything else is eligible for ranking."

Requirements

Functional Requirements:

  • Return 50 ranked posts per feed request for a given user, drawing from a candidate pool of a few thousand eligible items.
  • Support heterogeneous inventory: text posts, photos, videos, link shares, and third-party embeds.
  • Enforce hard filters (blocks, mutes, integrity flags, seen-in-24h, locale) before any scoring.
  • Handle cold-start users with no follow graph using topical affinity and global trending fallbacks.
  • Handle cold-start posts by giving newly created content a bounded impression floor so the ranker has signal to learn from.
  • Allow the ads-blending service to inject sponsored content into configured slots without reshaping the organic ranking.
  • Record every impression, engagement event, and negative signal (hide, report, not interested) for retraining and monitoring.

Non-Functional Requirements:

  • P99 ranking latency under 200ms.
  • Post-create to ranker-eligible under 30 seconds so new content can compete for early impressions.
  • Serve 500M DAU with a steady peak of roughly 60K ranking QPS.
  • Fairness across creator tail: a user with 100 followers should get a reasonable share of impressions when their content is relevant, not be crowded out entirely by the top 1% of creators.
  • Integrity: posts flagged above the safety threshold must never reach ranking, and the integrity filter must run before any model sees the candidate.
  • Privacy: no feature exposing the identity of another user through ranking signals (for example, a recommendation reason that would leak who reported a post).

ML Problem Framing

The feed is a pointwise multi-task ranking problem. For a given user u and candidate post p, the model predicts the probability of several engagement events, and a value model blends those predictions into a single score used for sorting.

The naive framing is a single-head CTR model: P(click | u, p). It's easy to train because every impression is labeled, but it fails in two ways. Clicks are biased toward sensational content, and a single objective cannot trade off fast engagement against longer-term signals like whether the user hides the post or marks it as not interested.

A better framing uses a small set of heads, each representing a distinct user action, and a value model that combines them:

  • P(click | u, p, shown)
  • P(like | u, p, shown)
  • P(comment | u, p, shown)
  • P(share | u, p, shown)
  • P(long_dwell | u, p, shown), defined as at least 3 seconds visible with active scroll
  • P(hide_or_report | u, p, shown), the explicit negative signal

The blended score is a weighted sum, with the negative head subtracted. Weights are learned or hand-tuned from A/B tests that optimize the retention north star rather than raw engagement. Candidate generation is a separate stage with its own architecture; the ranker assumes it receives a few hundred to a few thousand candidates that have already cleared integrity filters.

Metrics

TypeMetricWhy It Matters
OfflinePer-head AUC (click, like, comment, share, long_dwell, hide)Calibration of each head on held-out next-day impressions
OfflineNDCG@10 on blended value scoreHow well the blend ranks real engagement events
OfflineCalibration plots per headPredicted vs observed probability per decile; drift shows up here first
OnlineSessions per DAUDo users come back more often during the experiment?
OnlineMeaningful interactions per user-dayComposite of long_dwell, likes, comments, shares minus hides
Online7-day and 28-day retentionWhether the ranker is optimizing for habit, not just today's clicks
GuardrailIntegrity false-positive rateDon't fix ranking by over-filtering borderline content
GuardrailCreator-tail impression shareFraction of impressions going to creators outside the top 1%
GuardrailSource diversity (Gini on topic/creator mix)Detect echo chambers collapsing the feed onto a narrow set
GuardrailNegative-feedback rate (hide + report + not interested)A slow rise here always precedes a retention drop

2. System Architecture

At the top level, a feed request flows through four stages: candidate generation fans out across heterogeneous sources, a lightweight pre-ranker trims the pool, a heavy multi-task model scores the survivors, and a re-ranker enforces diversity, dedupe, and ads-blending rules before returning a ranked list.

Each stage trims the candidate set by an order of magnitude while using progressively more expensive features. This chapter focuses on what's specific to feed ranking: the heterogeneity of the candidates, the blend of retrieval sources, and the re-ranking stage.

Data Flow

Three loops keep the system healthy, and they run on very different cadences.

The offline loop retrains the ranker on the previous day's impressions joined with labels that landed within the attribution window. The streaming loop keeps time-sensitive features fresh: a newly created post has its early-velocity features updated every few seconds as likes and comments arrive, and a user's recent-engagement vector refreshes within seconds of each action. The online loop is a straight feature-fetch-score-rank pipeline, and its budget is set by the 200ms p99 target.

Back-of-Envelope Scale

Before touching architecture details, it's worth grounding the scale with a few estimates. These numbers drive almost every design decision downstream.

QuantityEstimateCalculation
DAU500MGiven
Feed loads per DAU per day10Given
Ranking requests per day5B500M x 10
Peak ranking QPS~60K5B / 86,400 x 3 (peak factor)
Candidates scored per request (ranker)200Pre-ranker output
Ranker scoring ops per second at peak12M60K x 200
Eligible candidates per user per request3,000-5,000From candidate gen
Posts created per day20BGiven
Post features retained for 30 days600B rows20B x 30
Impression log volume per day~300B events5B requests x 50 items shown, deduped

The 12M-per-second ranker scoring number is what drives the push toward model distillation, batched GPU inference, and aggressive caching of user-side features. The 600B post-feature rows push toward tiered storage with hot posts in Redis and long-tail posts in a columnar store.

3. Data

Data Sources

The feed draws from several independent data streams, each owned by a different team in most large organizations. Getting the join keys right across these sources is half the engineering effort.

  • Post creation stream: every new post arrives on a Kafka topic within milliseconds. Downstream consumers include the integrity classifier, the indexing service that writes posts to the retrieval index, and the early-velocity feature job.
  • Engagement log: every impression, click, like, comment, share, long-dwell event, hide, and report. This is the label source for training and the input to recent-user-state features.
  • Social graph: follow edges, group memberships, page subscriptions. Updated in near-real-time but consumed mostly by candidate generation, not ranking features.
  • User profile: slowly changing attributes like locale, declared interests, account age.
  • Content classifiers: topic tags, content-type labels, quality scores, integrity scores. These run asynchronously after post creation; a post is eligible to be shown once the mandatory classifiers complete, which typically takes a few seconds to a few tens of seconds.
  • Surveys: periodic in-product surveys asking users to rate how valuable specific posts were. Low-volume but high-signal, and essential for tuning the value model against something other than click behavior.

Feature Engineering

Feed features fall into four groups: user, post, viewer-creator cross features, and context. The hardest to get right are the cross features, because they describe the relationship between a specific user and a specific post, which cannot be precomputed for all pairs.

User features capture who is asking: their recent engagement behavior, topic-affinity embedding, active hours, device class, and session-so-far signals like how many posts they've already scrolled past without engaging.

Post features describe the item: age in minutes, creator identity and reputation, content-type flags, topic tags, language, embedding of the text and media, quality-classifier score, integrity-classifier score, and early-velocity signals like likes-per-minute and hide-rate-per-impression.

Viewer-creator cross features are where most of the signal lives: whether the viewer follows the creator, how many prior interactions the viewer has had with this creator, time-decayed engagement rate, and whether the viewer and creator share groups or pages.

Context features situate the request in time and place: hour of day, day of week, device, network quality, and whether this is a cold-start session (app just opened) or a deep scroll within an existing session.

Cross-features between user embeddings and post embeddings are learned implicitly by the deep ranker, but a few explicit crosses via DCN-style or DeepFM-style layers tend to help on sparse signals like user-creator affinity.

Feature Table

FeatureTypeSourceFreshnessDescription
user_embeddingVector(128)Batch pipelineDailyLearned from long-term engagement history
user_topic_affinityVector(64)Batch pipelineDailyUser's preference over topic taxonomy
user_recent_actionsSeq(50)Streaming<10sLast 50 engagement events with metadata
user_session_depthIntRequest-timeReal-timePosts scrolled so far in current session
user_active_hoursVector(24)Batch pipelineWeeklyProbability of being active per hour
post_embeddingVector(256)Batch at createAt createMultimodal embedding of text + media
post_age_minutesIntStreamingReal-timeMinutes since post creation
post_creator_idIdPost metadataAt createForeign key to creator features
post_topic_distributionVector(32)ClassifierAt create + 10sSoft distribution over topic taxonomy
post_quality_scoreFloatClassifierAt create + 30sQuality classifier output, 0 to 1
post_integrity_scoreFloatClassifierAt create + 30sSafety classifier, hard filter above threshold
post_likes_per_minuteFloatStreaming<10sEarly velocity, smoothed
post_hide_rateFloatStreaming<60sHides per 1000 impressions, smoothed
viewer_follows_creatorBoolGraph service<60sDirect follow edge
viewer_creator_interactions_30dIntBatch pipelineDailyCount of engagements with this creator
viewer_creator_decayed_rateFloatBatch pipelineDailyTime-decayed engagement rate
context_hour_of_dayIntRequest-timeReal-time0 to 23 in user locale
context_device_classCategoricalRequest-timeReal-timePhone tier, tablet, web

The freshness column matters more than it looks. A post's integrity score must be available before it can enter the ranker, but its velocity features update continuously after that. A viewer-creator interaction feature can lag by a day without hurting quality, because long-term affinity doesn't swing hour to hour. Knowing which features tolerate lag and which cannot is what lets the feature store keep the budget under control.

4. Model

Baseline Approach

The first version of every feed ranker in history has been logistic regression on hand-crafted features with a single click label. It's not glamorous, but it's honest: it sets a floor the next model has to clear, and it exposes what the feature pipeline is actually producing.

A reasonable baseline looks like this:

  • Label: clicked or not clicked, aggregated per impression.
  • Features: a few hundred hand-crafted signals including user activity level, creator popularity, post age, viewer-creator interaction count, and simple cross-features like whether the viewer follows the creator.
  • Model: regularized logistic regression trained daily on the prior 30 days of impressions.
  • Serving: single score per candidate, sort by score.

This caps out quickly for two reasons. A click-only objective pushes the ranker toward clickbait and sensational content, because those items have the highest short-term click probability and the worst long-term effect on retention. And logistic regression cannot learn the dense interaction between a user embedding and a post embedding without extensive manual cross-featuring, so it leaves a lot of signal on the floor.

Advanced Approach

The production ranker is a multi-task deep model with a shared bottom and several task-specific heads. Variants in the literature include MMoE (Multi-gate Mixture of Experts) and PLE (Progressive Layered Extraction); the high-level architecture is similar across them.

The shared bottom compresses raw features into a dense representation. Experts are small MLPs that specialize in subsets of tasks. Task-specific heads take expert outputs (optionally gated) and predict the per-head probability. The hide head is trained with the same architecture but its prediction gets subtracted from the blended score at serving time, not added.

Why this architecture works well for feeds:

  • The rare heads (share, hide, long-comment) benefit from parameter sharing with common heads (click, like), which have orders of magnitude more labels.
  • Gating lets the model route a video post's features through experts that are good at video-like signals, and a text post's features through different experts, without needing separate models per content type.
  • Adding a new head (for example, "report" or "save for later") is a training-pipeline change, not an architecture change.

For embedding inputs, user and post embeddings come from two-tower retrieval models, or from dedicated content-understanding models for richer text and media representations. The ranker uses these embeddings as features rather than training them from scratch.

Training

Training data comes from joining the impression log with labels that landed within the attribution window.

  • Positives per head are defined by the action: a click-positive is an impression followed by a click, a long-dwell positive is an impression with >=3 seconds active dwell, a hide-positive is an explicit hide or report.
  • Negatives are all impressions without the positive action within the window.
  • Position debiasing is applied by including rank-position as a feature at training time and zeroing it at inference, or by using inverse-propensity weighting. Without this, the ranker learns to predict that the top position always wins, which is circular.
  • Sampling downweights the vast oversupply of negatives and upweights rare positive classes (shares, long dwells) to keep per-head gradients balanced.
  • Loss is the sum of per-head binary cross-entropy losses with head-level weights. Weights are not the same as the serving blend weights; training weights are tuned to balance gradient magnitude, serving weights are tuned to maximize the retention north star.
  • Retraining cadence is daily, with the previous day's logs appended to the training window and the oldest day dropped. Hotfix retrains kick in when a guardrail metric moves beyond its threshold.

The value-model blend at serving time is a weighted sum:

Weights are set by offline grid search on a Pareto frontier of engagement vs negative-feedback, then confirmed by A/B testing against retention. Common practice is to set the comment and share weights noticeably higher than click and like, because those actions correlate more strongly with long-term retention. The hide weight is set aggressively: a single predicted hide probability above 0.05 should usually demote a post below anything without that signal.

5. Serving

Inference Pipeline

A feed request starts when the user opens the app or scrolls deep enough to refresh. Every request goes through the same pipeline, though different surfaces (app launch vs pull-to-refresh vs deep scroll) parameterize it differently.

User state includes the user's embedding, recent-action sequence, and surface-level settings. It's cached at the edge for active users and refreshed every few seconds or on explicit invalidation. Candidate generation fans out in parallel to three sources, described in detail in the deep dives section. The integrity filter sits between candidate generation and the ranker to guarantee that no flagged content reaches a scoring model, regardless of what candidate generation produced.

Batch vs Real-Time

Every component in the pipeline lands somewhere on the spectrum from fully precomputed to computed per request. Getting the split right is how feed systems hit 200ms p99 with billion-user catalogs.

ComponentComputedWhy
User long-term embeddingDaily batchChanges slowly; retraining daily is enough
Post embeddingOnce at post createContent doesn't change after posting
User recent-action sequenceStreaming, <10s lagChanges every scroll; request-time would miss the most recent action
Post early-velocity featuresStreaming, <10s lagChanges as engagement accrues; critical for new posts
Viewer-creator interaction rateDaily batchLong-term affinity is stable; real-time precision not worth the cost
Candidate generationRequest-timeSocial graph and trending both change; cached per-user for seconds at most
Pre-ranker scoresRequest-timeDepends on all three sources and user context
Ranker scoresRequest-timeMust combine freshest user and post state
Diversity re-rankRequest-timeDepends on the specific 200 candidates and their topic mix

The sharpest split is between daily-batch features and streaming features. A batch feature is cheap to compute once and serve many times; a streaming feature requires a continuously running job consuming from Kafka and writing to the online store. Feeds use more streaming features than most recommendation systems because the inventory itself is fresh: a post is created, accrues engagement, and decays in hours, so its features cannot be precomputed once and frozen.

Latency Budget

The 200ms p99 target has to be allocated across the pipeline, with enough slack to absorb tail latency on any single component.

ComponentBudgetNotes
Network ingress + egress20msApp to edge to ranking service
User state fetch15msEdge cache hit; miss triggers reshape
Candidate generation (parallel)30msMax of graph, trending, and ANN lookups
Integrity + hard filter10msIn-memory bloom filters plus per-candidate check
Feature fetch for pre-ranker15msOnline store reads, batched
Pre-ranker inference15msSmall MLP or GBDT, CPU
Feature fetch for ranker20msHeavier feature set; cached where possible
Ranker inference40msBatched across 200 candidates, GPU
Diversity re-rank10msSingle-threaded, deterministic
Ads blending5msInsert at fixed slots
Buffer20msTail-latency headroom
Total200msP99 target

The ranker inference budget drives the most decisions. Forty milliseconds for 200 candidates on GPU means the model has to be small enough to fit several requests per batch, or it has to be distilled from a larger teacher model. A common pattern is to train a big two-stage teacher and distill into a smaller student that fits the latency budget.

6. Deep Dives

6.1 Multi-Objective Ranking and the Value Model

Every other system in this section has a cleaner objective. Video recommendations optimize watch time. Product recommendations optimize purchases. PYMK optimizes accepted connections. A news feed doesn't get to pick one. If the ranker chases clicks, users end up seeing outrage content and session length crashes a week later. If it chases long dwell, it under-weights quick reactions like likes that are genuine positive signal. If it chases pure "meaningful interactions," it can under-show time-sensitive content like breaking news that a user just wants to scan.

The value model is the hinge. Its job is to combine per-head predictions into a single scalar score where weights encode a business judgment about what the feed should feel like. Setting those weights is more of a policy decision than a modeling decision, and it's tuned against long-horizon A/B results, not same-day clicks.

Three strategies dominate in practice, each with distinct trade-offs.

StrategyHow It WorksProsCons
Hand-tuned weightsWeights chosen by PM and ML leads, validated by A/BTransparent, easy to reason aboutSlow to adapt; prone to drift as inventory changes
Learned weightsWeights optimized to maximize a chosen online metric via offline bandit or contextual RLAdapts to shifting inventory; captures non-linear interactionsHard to debug; can overfit to short-term signals if not regularized
Pareto + A/B confirmOffline grid search generates a Pareto frontier of engagement vs negative feedback; candidates on the frontier go to A/B tests against retentionExplicit trade-off visualization; anchors product decisionsExpensive; needs a lot of A/B bandwidth

Counterfactual reweighting is an important refinement in all three. Users see only the top-ranked items, so the log is biased toward the ranker's past beliefs. Inverse propensity scoring at training time corrects for this, and randomized exploration slots in production generate unbiased data for evaluating new value-model weights offline.

Surveys earn their keep here. Meta has publicly discussed using in-product surveys asking users to rate individual posts as a direct signal for quality. The survey signal is low volume compared to clicks, but it anchors the value model against something closer to genuine user preference than passive engagement metrics. Without a survey signal, any value-model tuning loop slowly overfits to whatever is measurable, and the feed drifts toward whatever form of engagement is easiest to provoke.

6.2 Candidate Generation at Feed Scale

A user's social graph alone isn't enough to populate 50 quality slots. Follow graphs are sparse in the tail and dominated by inactive creators in the head; pure friend-and-follow feeds run dry within seconds of scrolling. Feed candidate generation pulls from three parallel sources, unions the results, and deduplicates before handing the pool to the pre-ranker.

The graph source walks direct follows, groups, and second-degree connections, returning recent posts sorted by a cheap recency-weighted engagement score. The trending source retrieves posts with high velocity restricted to topics or creator clusters the user has engaged with before. The topical ANN source performs an approximate nearest-neighbor lookup against post embeddings using the user's topic-affinity embedding as the query, pulling in content from accounts the user doesn't follow but is likely to engage with.

SourceStrengthWeaknessTypical Quota
Social graphHighest precision for engaged users, natural explanation ("your friend posted")Dries up for low-connection users; biased toward head accounts40-60%
Trending-by-affinityBrings in fresh, viral content within user's interest spaceRisk of same-content-twice if dedupe is loose20-30%
Topical ANNExploration beyond the follow graph; critical for cold-start usersLower precision; can surface low-quality content if not filtered10-30%

The quotas are per-request targets and shift based on user state. A user with 5 follows gets almost all candidates from topical ANN. A user with 500 follows gets most from the graph. Cold-start post handling lives mainly in the trending source: a new post from a creator the user follows enters the graph source immediately, but posts from creators the user doesn't follow need to accumulate enough early velocity in the trending-by-affinity job before they become eligible for that user's feed. Giving new posts a small impression floor, even without signal, is how the system avoids an absorbing-state problem where new content can never accumulate enough data to compete.

Deduplication operates on two levels: the same post ID cannot appear twice, and near-duplicate content from different IDs (same link share, same reposted video) is collapsed to a single candidate based on content fingerprinting. The dedupe step sits before the pre-ranker so the expensive stages don't waste cycles on redundant items.

6.3 Diversity, Filter Bubbles, and Fairness

If a ranker optimizes pure predicted engagement, every user's feed collapses onto a narrow set of creators and topics. The top 200 candidates after ranking might all be from the same five creators, all on the same topic, because those are the highest-scoring items this user will see today. That's bad for users (monotony), bad for creators (winner-take-all), and bad for the platform (retention drops when the feed feels repetitive).

Re-ranking applies diversity, fairness, and dedupe constraints after the ranker has scored the candidate set. Several layers run in sequence, each enforcing a different kind of constraint.

The order matters. Near-duplicate collapse runs first so the greedy picker never compares two almost-identical items. Source and topic caps filter out candidates that would violate constraints before the picker sees them. The MMR layer does the actual diversity-aware selection. Creator-tail boost and exploration injection apply late, after the bulk ranking is done, so they don't distort the relative ordering of the main selections.

A common algorithm for the MMR layer is a greedy selection that balances relevance against redundancy.

The lambda controls how much diversity is worth in units of value-score. Setting lambda too high pushes out high-quality content in favor of variety; too low and the feed collapses. The right setting is typically small, around 0.1 to 0.3, and itself a hyperparameter subject to A/B testing.

Beyond MMR, several practical constraints layer on top.

TechniqueWhat It DoesWhen It Kicks In
Source capsLimit N posts from any single creator per feed windowAlways; typical cap is 2 or 3 per session
Topic capsLimit the fraction of slots dedicated to any single topicWhen topic mix across top 50 exceeds a threshold
Creator-tail boostSmall additive bonus to candidates from creators outside the top 1% by impressionsAlways; magnitude tuned against fairness metrics
Exploration injectionRandom slot insertion of candidates from under-explored topicsAt configured frequency, typically 1 in 20 slots
Echo-chamber auditOffline scan for users whose feed exposure has collapsed below a diversity thresholdBatch, daily; triggers reset of exploration injection rate

The creator-tail boost deserves special attention. Without it, the top 0.1% of creators by follower count win almost every scoring comparison because they have more engagement data, better velocity features, and higher-quality content on average. Giving tail creators a small score bonus keeps the feed's creator distribution from collapsing onto the head, which matters for the platform's long-term content supply, not just fairness.

6.4 Freshness and Real-Time Signals

The median post has a useful life of a few hours. Some posts, like breaking news, have a useful life of minutes. Unlike video recommendations or product recommendations, where the catalog turns over slowly and content stays relevant for weeks, feed ranking is constantly racing against the clock.

Three design decisions follow from this.

First, post-create to ranker-eligible must be fast. The pipeline from post creation through integrity classification, indexing, and feature population runs on a streaming backbone with a 30-second budget. Anything slower and trending content misses its window. This is why quality and integrity classifiers have to be fast; they cannot afford minute-scale batch cadences.

Second, early-velocity features dominate early-life ranking. A post that's two minutes old has no viewer-creator interaction history to pull from, no long-term velocity, and no established engagement rate. What it has is likes-per-minute and hide-rate-per-impression over its first few hundred impressions, and those are the features that tell the ranker whether this specific post is resonating. Early-velocity features update every few seconds on a streaming job keyed by post ID.

Third, the scoring function applies an explicit recency decay. The ranker learns to predict the engagement probability from features, but those features include post age. In practice, a small multiplicative decay on the final score based on post age is still applied to ensure that two posts with similar predicted engagement don't crowd out freshness. A typical decay halves a post's effective score every 6 to 12 hours.

Spiky posts create a specific headache. A post that goes viral in its first hour accumulates velocity features so strong that the ranker predicts very high engagement for every viewer, which is mostly correct but has two failure modes. One, the post dominates the feed for hours until the velocity signal decays, pushing out everything else. Two, the velocity feature is easy to manipulate by coordinated early engagement, so a small cluster of accounts can inflate a post's early-life score. The mitigations are source caps in re-ranking (a single post can only appear once per user per day) and trust-weighted velocity (engagements from historically reliable accounts count more than engagements from brand-new accounts).

Model artifacts themselves have a freshness question. The ranker is retrained daily, but the world can shift faster than that during events like elections or natural disasters. Some platforms keep a small set of fast-retraining shadow models that can be swapped in if the live model's calibration degrades beyond a threshold. This is the difference between a ranker that's fresh and a ranker that's robust: the features can be seconds old, but if the model's weights are stale against a new distribution, the feature freshness doesn't help.

7. Evaluation and Iteration

Offline Evaluation

Before any new model or value-model weight touches production, it gets scored on held-out impressions from the previous day. Per-head AUC measures whether each head is well-calibrated; NDCG@10 on the blended score measures whether the new configuration would rank real engagement events higher than the live model would.

Two specific offline checks catch the most common failure modes. Calibration plots per head reveal when a head is systematically over- or under-predicting at certain deciles, which is usually the first sign of a feature-pipeline bug or distribution shift. And replay scoring, where the new ranker scores the same candidate pools the live ranker saw, computes the correlation between the two rankings. A correlation below 0.7 against the live model usually signals something more surgical than an experiment should change.

Online Evaluation

Every candidate model goes through a staged rollout: shadow mode where it scores but doesn't serve, a 1% A/B where it serves a small slice, then progressively larger slices if metrics hold.

The interesting thing about feed A/B tests is that short-horizon metrics can lie. A new ranker that cranks up the click weight will show better clicks in a one-week A/B and worse retention in a four-week holdout. The standard response is to maintain long holdouts: a 1% slice of users kept on the previous model for a quarter, with retention and survey scores measured against the treatment group. Compounding retention effects only show up in weeks, not days, so long holdouts are not optional.

Guardrail metrics run alongside the primary metrics on every test. The integrity false-positive rate cannot rise. Creator-tail impression share cannot collapse. Negative-feedback rate (hides, reports, not-interested clicks) cannot increase. If any guardrail moves beyond its threshold, the test is paused regardless of what the primary metric says.

Monitoring

Once a model is live, monitoring falls into four categories: feature drift, model calibration drift, guardrail metrics, and segment-level health.

Serving logs feed every monitor in parallel. Each monitor has its own threshold and its own response: a feature PSI spike pages the data team, a per-head calibration drift pages the ML team, a guardrail breach auto-pauses any active experiments on the affected surface.

MonitorWhat It CatchesAlert Threshold
Feature distribution (per feature)Upstream pipeline failures, shifts during news events5% PSI change day-over-day
Head calibration (predicted vs observed)Model degradation under distribution shiftMiscalibration >10% in any decile
Creator-tail impression shareRe-ranking weight drift>5 percentage point drop week-over-week
Integrity false-positive rateOver-filtering breaking feed quality>0.5% FP on sampled audits
Per-segment NDCG (new users, low-activity users, power users)Ranker regressions that hide in the average>3% drop for any segment week-over-week
Negative-feedback rateSlow creep toward outrage content>10% week-over-week rise

The trickiest monitor is per-segment health. An overall engagement metric can look flat while new users are getting a progressively worse experience, because power users generate most of the engagement volume and drown out new-user signal. Splitting by segment and alerting on segment-level regressions is how long-term retention gets protected against average-case drift.

Feature drift alerts are the most common false positive. Topic distributions shift during real-world events (elections, sports seasons, natural disasters), and the ranker has to absorb that shift without triggering a rollback. The standard pattern is to alert on drift but gate rollback on calibration or guardrail metrics, so a natural distribution shift doesn't unnecessarily revert a healthy model.

Interview Questions

Q1: Why is a multi-task ranker the right choice for a feed, and what would go wrong with a single-head CTR model?

A single-head CTR model optimizes for one signal that correlates with short-term clicks but not long-term value. Clickbait has high CTR, so the feed drifts toward outrage and sensational content within weeks. Users who find their feed progressively worse churn quietly, which shows up as a retention decline months later, long after the ranker change that caused it. A multi-task model predicts click, like, comment, share, long-dwell, and hide probabilities jointly, and a value model blends them with weights tuned against retention. This lets the system make explicit trade-offs like "a predicted hide outweighs a predicted click" rather than pretending a single number captures everything.

Q2: How would you decide the weights in the value model that blends per-head predictions?

Three approaches work in practice and each has trade-offs. Hand-tuned weights are transparent and stable but slow to adapt as the content mix shifts. Learned weights, optimized via contextual bandits or RL, adapt faster but are hard to debug and can overfit to easy-to-measure signals. The most common approach in large teams is to generate a Pareto frontier offline over engagement vs negative-feedback, pick a few promising points on the frontier, and A/B test them against retention and survey-based quality metrics. Whichever approach you pick, counterfactual reweighting on the training logs and a small randomized exploration slot in production are essential, because the ranker's own past behavior biases every metric the new weights are scored on.

Q3: Why does feed ranking need streaming features more than most recommendation systems?

The useful life of a feed post is measured in hours. A post created five minutes ago has no viewer-creator interaction history, no established engagement rate, and no long-term velocity signal. What it has is a few minutes of early engagement data, and the ranker's ability to score it well depends on having that data available in under 10 seconds. In contrast, a video or product in a catalog has a shelf life of weeks or months, so daily-batch features capture most of the signal. Feeds can't afford that cadence because the window between a post being created and the ranker deciding whether to show it is often shorter than a batch job's schedule.

Q4: How do you prevent a feed ranker from collapsing onto a small set of creators, and what are the trade-offs of your approach?

The core issue is that pure engagement optimization is a winner-take-all process. Top creators have more data, better velocity signals, and higher average engagement, so they win almost every scoring comparison. Diversity re-ranking with a greedy MMR-style algorithm penalizes candidates too similar to what's already selected in the feed, and source caps limit how many posts any single creator can appear in per session. A creator-tail boost adds a small score bonus to candidates from creators outside the top 1% by impressions. The trade-off is that diversity costs short-term engagement: an MMR lambda of 0.3 might drop same-day engagement by 1-2% while increasing retention measurably over weeks. The balance is set by A/B tests on long-horizon metrics, not same-day clicks.

Q5: A new post goes viral in its first hour. Its velocity features predict extremely high engagement for every viewer. What can go wrong, and how do you mitigate it?

Two failure modes show up. The post dominates feeds for hours because its predicted score beats almost everything else, pushing out content variety and creating a monotonous experience. And the velocity features are easy to manipulate: a small cluster of accounts engaging immediately after post creation can inflate the early-life score, which is the basis of many coordinated-inauthentic-behavior campaigns. Mitigations include per-user-per-day source caps so a single post cannot appear more than once in a user's feed per session, trust-weighted velocity where engagements from accounts with a long history count more than engagements from brand-new accounts, and recency decay that halves effective score every 6-12 hours regardless of predicted engagement. These don't eliminate virality, they bound its reach.

Summary

  • A personalized news feed is a pointwise multi-task ranking problem over heterogeneous, short-lived inventory, and multi-objective optimization is what makes it distinct from video or product recommendations.
  • The ranker predicts several engagement probabilities (click, like, comment, share, long-dwell, hide) and a value model blends them with weights tuned against retention, not same-day clicks.
  • Candidate generation runs in parallel across three sources (social graph, trending-by-affinity, topical ANN) because no single source covers both warm and cold-start users well.
  • Integrity and hard filters run before the ranker touches any candidate, not after, because letting flagged content enter the scoring stage is a safety hazard regardless of final ranking.
  • Streaming features matter more for feeds than for most recommendation systems because post shelf life is hours; post-create to ranker-eligible under 30 seconds is a hard requirement.
  • Diversity and fairness are enforced at re-rank time via MMR, source caps, creator-tail boosts, and exploration injection; without these, the feed collapses onto the top 0.1% of creators.
  • Offline AUC and NDCG evaluate the ranker; long online holdouts of a quarter or more catch the retention effects of a ranker change that a short A/B cannot see.
  • Monitoring splits by user segment because average metrics hide per-segment regressions, especially for new and low-activity users.

The next chapter tackles ad click prediction, which shares many patterns with feed ranking but has its own specifics: extreme sparsity, tight calibration requirements, and an auction on the other side that turns predicted CTR into a bid.