Updated August 13, 2026

For You Algorithm
Deep Dive

A comprehensive, interactive guide to how X decides what appears in your For You feed — from raw candidates to ranked results.

7 stages
Post pipeline
20 filters
Pre + post selection
24 signals
Predicted actions
3 sources
Thunder + Phoenix + SimClusters
Explore the algorithm ↓

How Your Feed Gets Built

The For You feed blends posts from accounts you follow (in-network) with posts found by Phoenix retrieval and SimClusters (out-of-network). Phoenix predicts what you may do next, Home Mixer turns those probabilities into a score, and a separate visibility system decides whether a post can be shown at all.

Thunder — In-Network

An in-memory post store that tracks recent posts from all users in real time. It serves posts from accounts you follow in sub-millisecond lookups via Kafka-ingested events.

Rust · In-Memory
🔭

Phoenix Retrieval — Out-of-Network

A two-tower ML model that encodes you and all posts into embedding vectors, then retrieves the most relevant out-of-network posts via approximate nearest-neighbour search.

JAX · Two-Tower
🧩

SimClusters — Community Discovery

A second out-of-network source. It groups accounts and posts by shared engagement patterns, then finds candidates from communities that match the viewer.

Graph · Clusters
🧠

Phoenix Ranking — The Brain

A transformer trained and served from the released Phoenix code. It reads your engagement history and predicts 24 actions for every candidate post.

Transformer · Multi-action
🧹

Home Mixer — Orchestration

The glue layer written in Rust that wires together all pipeline stages: query hydration, candidate sourcing, enrichment, filtering, scoring, and final selection.

Rust · gRPC
🔍

Grox — Content Understanding

An AI pipeline that classifies every new post for spam, safety violations, and topic category using Grok-powered vision-language models before posts enter the ranking pool.

Python · Grok VLM
📐

Candidate Pipeline — Framework

A reusable Rust framework defining composable traits (Source, Filter, Scorer, Hydrator…) that run in parallel where possible with built-in observability and error handling.

Rust · Async

The 7-Stage Journey

Every feed request runs through these stages in sequence. Click any stage to expand details.

1
Query Hydration Parallel async
Load the user's full context before touching any candidates

All query hydrators run in parallel. Their results are merged back into the query object before the next stage begins.

UserActionSequence FollowedUserIds MutedUserIds BlockedUserIds UserDemographics ImpressionBloomFilter FollowedGrokTopics StarterPacks MutualFollowGraph ServedHistory
2
Candidate Sourcing Parallel
Pull posts from multiple sources simultaneously

Sources run in parallel and their results are pooled together into a single candidate list for the next stage.

IN-NETWORK
Thunder — sub-ms lookups from an in-memory store of every followed account's recent posts
OUT-OF-NETWORK
Phoenix Retrieval finds nearby posts in embedding space; SimClusters finds posts through engagement communities.
3
Candidate Hydration Parallel async
Enrich candidates with the metadata needed for filtering and scoring

Hydrators fetch additional data and write it back to each candidate. They run in parallel since they don't depend on each other.

CoreData (text, media) AuthorInfo EngagementCounts VideoDuration SubscriptionStatus BrandSafety LanguageCode MutualFollowScore QuotePostExpansion AuthorBlocksViewer
4
Pre-Scoring Filters Sequential
Eliminate candidates that should never reach the scorer

Filters run one after another. Each partitions candidates into "kept" and "removed." Removed candidates are discarded (or tracked for logging) and never scored.

Removes: duplicates, posts older than the age threshold, your own posts, posts from blocked/muted accounts, previously seen posts, paywalled content you can't access, and muted keywords.

5
Scoring Sequential scorers
Predict engagement probabilities and compute the final rank score

Scorers run in order, each updating candidates with new fields. The full scoring chain is:

🧠
Phoenix Scorer
Predicts 24 probabilities per post: engagement, clicks, attention, author follow, and negative feedback.
⚖️
Ranking Scorer
Combines the predictions using the now-published production-default weights: Σ(weight × P(action)).
🎭
Author Diversity Scorer
Applies an exponential decay multiplier to repeated authors. 2nd post from same author × decay, 3rd × decay², etc.
🌐
OON Scorer
Out-of-network posts get score × OON_WEIGHT_FACTOR. New users and topic-filtered feeds use different factors.
🌱
New-Author Boost
Authors below an impression threshold can be lifted toward a configured target position.
🎛️
VMRanker
Reorders the list with a determinantal point process, trading a little score for less repetition between neighbouring posts.
6
Selection
Sort by final score, pick the top K

The TopKScoreSelector sorts all surviving candidates by their final score (descending) and takes the top K. Non-selected candidates are passed to side effects for logging and caching.

7
Post-Selection Filters + Side Effects
Final safety pass, then log and cache for next request

VFFilter asks the separate visibility-filtering service whether to allow, drop, or interstitial a post. AncillaryVFFilter also checks parents, quoted posts, and reposted posts. DedupConversation removes extra branches of the same thread.

Side effects run async in the background: caching scored posts in Redis, publishing served candidate IDs to Kafka, updating impression history, logging for A/B experiments.

System Architecture

The August release exposes both the request path that builds the feed and the labeling path that determines what is eligible to appear.

Home Mixer

Orchestration Layer

Written in Rust. Exposes a gRPC ScoredPostsService endpoint. Wires together all pipeline stages and owns the final response format.

  • Rust
  • gRPC / Tonic
  • Tokio async
Thunder

In-Network Post Store

Consumes post create/delete Kafka events in real time. Maintains per-user stores for original posts, replies/reposts, and video posts. Auto-trims old posts.

  • Rust
  • Kafka
  • In-Memory
Phoenix

ML Retrieval + Ranking

Two JAX models: a two-tower retrieval model (user + candidate towers) and a Grok-based transformer ranker. Ported from Grok-1, adapted for RecSys.

  • JAX / Haiku
  • Grok transformer
  • ANN search
SimClusters

Community Retrieval

Clusters accounts and posts from engagement patterns, then retrieves out-of-network candidates from communities relevant to the viewer.

  • Graph signals
  • Clusters
  • OON source
VMRanker

Diversity Reranking

Uses a determinantal point process over post embeddings to reduce near-duplicate neighbours without discarding relevance.

  • DPP
  • Embeddings
  • Reranking
Grox

Content Understanding

Python pipeline that classifies new posts for spam, safety violations, and topics using Grok's VLM. Powers embeddings and policy enforcement at ingest time.

  • Python
  • Grok VLM
  • Kafka
Visibility Filtering

Eligibility + Safety Rules

Evaluates viewer relationships and labels from Grox, media models, account models, rule engines, and enforcement systems. Returns allow, drop, or interstitial.

  • Ordered rules
  • Labels
  • Viewer context
Candidate Pipeline

Reusable Framework

A Rust crate defining trait-based abstractions for building recommendation pipelines. Sources, Hydrators, Filters, Scorers, Selectors, and SideEffects.

  • Rust traits
  • Parallel exec
  • Stats / tracing
Ads Blending

Ad Injection

New in 2026. Blends ads into the organic feed at appropriate positions. Tracks brand-safety signals so ads don't appear adjacent to sensitive content.

  • Rust
  • Brand safety
  • Partition blend

How Posts Get Their Score

Phoenix predicts 24 actions across engagement, clicks, attention, author follow, and negative feedback. RankingScorer combines them using published default weights, then applies additional adjustments and diversity reranking.

Score Simulator

Explore a nine-signal subset using the August 2026 published defaults

✦ Positive Signals
FavoriteP(like) × weight
0.12
ReplyP(reply) × weight
0.04
RepostP(repost) × weight
0.05
ShareP(share) × weight
0.03
Post ClickP(click) × weight
0.08
Follow AuthorP(follow) × weight
0.01
✗ Negative Signals
Not InterestedNegative weight
0.02
Block AuthorStrong negative
0.00
ReportStrongest negative
0.00
Partial Weighted Sum
0.33
Decent engagement predicted. This post would likely be included in the feed but won't rank in the top tier.
LowAverageTop

Educational approximation only. The real scorer uses 24 predictions, conditional weights, score offsets, experiment configuration, author/network adjustments, and VMRanker. A post can also be removed by visibility filtering regardless of score.

// The actual scoring formula from ranking_scorer.rs
let score = apply(p_fav, w_fav)
    + apply(p_reply, w_reply)
    + apply(p_repost, w_repost)
    + apply(p_share, w_share) // + 20 more predictions...
    + apply(p_not_interested, -w_ni) // negative
    + apply(p_block_author, -w_block) // negative
    + apply(p_report, -w_report);// negative

// Author diversity: exponential decay for repeated authors
let multiplier = (1.0 - floor) * decay.powf(position) + floor;
let diversity_score = score * multiplier;

// OON penalty: out-of-network posts score × oon_weight_factor
let final_score = if !in_network { diversity_score * oon_factor } else { diversity_score };

What Gets Removed & Why

Filters run at two points: before scoring (to avoid wasting ML compute on ineligible posts) and after selection (for final safety checks).

Filter Stage What it removes
DropDuplicatesFilter Pre Candidate posts with duplicate IDs in the same request
CoreDataHydrationFilter Pre Posts that failed to hydrate core metadata (e.g., deleted before hydration)
AgeFilter Pre Posts older than the configured max age threshold
SelfTweetFilter Pre Posts authored by the viewing user (your own posts)
OONRetweetReplyFilter Pre Out-of-network reposts and replies, plus replies whose parent post is missing
OONNsfwSimclustersFilter Pre SimClusters recommendations from adult-content authors the viewer does not follow
RetweetDeduplicationFilter Pre Multiple reposts pointing to the same original post
IneligibleSubscriptionFilter Pre Paywalled / subscription-only content the viewer hasn't subscribed to
PreviouslySeenPostsFilter Pre Posts the user has already seen, tracked via impression bloom filter
PreviouslySeenPostsBackupFilter Pre Already-seen posts found in a second impression record
PreviouslyServedPostsFilter Pre Posts already served to the user in a recent prior request
MutedKeywordFilter Pre Posts containing any keyword or phrase the user has muted
AuthorSocialgraphFilter Pre Posts from blocked or muted accounts, or accounts that block the viewer; also covers quoted/retweeted authors
TopicIdsFilter Pre Posts that don't match the viewer's active topic filters
VideoFilter Pre Video posts when the current request excludes video
NewUserMinEngagementFilter Pre Low-engagement out-of-network posts for new accounts
InventoryHoldoutFilter Pre A configured experimental holdout, selected deterministically per viewer and post
VFFilter Post Posts the visibility service decides must be dropped; interstitial is a separate possible response
DedupConversationFilter Post Duplicate branches of the same conversation thread to avoid showing the same thread multiple times
AncillaryVFFilter Post Visibility-filtered ancillary posts (quoted tweets, parent replies) attached to otherwise-visible candidates

The Grok-Powered Brain

Phoenix is a two-stage ML system: a two-tower retrieval model to narrow millions of posts to thousands, and a Grok-based transformer ranker to score each one with full context.

Stage 1 — Retrieval

Two-Tower Model

Encodes you and every post into a shared embedding space. Finds the top-K posts most similar to you via dot-product ANN search.

User Tower
Engagement history → user embedding
·
Item Tower
Post content → post embedding
Stage 2 — Ranking

Transformer with Candidate Isolation

Input: [user token] + [engagement history sequence] + [candidate posts]. Candidates attend to user + history but not to each other.

Input: [User] [H₁ H₂ … Hₛ] [C₁ C₂ … Cₙ]
Output: logits[B, n_candidates, 19 actions]

Candidate Isolation — The Attention Mask

Candidates can only attend to the user token and engagement history — never to each other. This means each post's score is independent of what else is in the batch, making scores cacheable and consistent across requests.

Can attend   Blocked   Self only

Hash-Based Embeddings

Neither the ranking nor retrieval model uses hand-crafted feature IDs. Instead, both users and posts are embedded via multiple independent hash functions:

User hashes — 2 independent hashes per user ID
Item hashes — 2 independent hashes per post ID
Author hashes — 2 independent hashes per author ID

Multiple hash embeddings are summed (reduced) before entering the transformer, providing collision resistance and graceful handling of unseen IDs.

AI-Powered Post Classification

Every post goes through Grox before it can be ranked. Grox uses Grok's vision-language model to understand text and images together — enabling nuanced classification that pure text models miss.

🚫

Spam Detection

Uses Grok VLM to classify posts as spam. Has a dedicated path for low-follower accounts (SpamEapiLowFollowerClassifier) that applies stricter standards to new or small accounts.

Safety
🛡️

Safety Screening

Two-pass safety system: a fast initial screen (BangerInitialScreen) followed by the full PostSafetyScreenDeluxe that evaluates PTOS (Policy, Terms of Service) categories.

Safety
📂

Content Classification

Classifies posts into categories to power topic-based feeds and filtering experiments. Supports post-based filtering at 90%, 75%, and 50% confidence thresholds.

Topics
🔢

Multimodal Embeddings

Generates dense embedding vectors for posts using both text and image content (v2 and v5 embedders). Used as features for the Phoenix retrieval model's candidate tower.

ML
📝

Post Summarization

Generates natural-language summaries of posts, used as additional input features to the Phoenix embedding pipeline for richer content understanding.

NLP
⚙️

Task Engine

A DAG-based task scheduler (grox/engine.py) that orchestrates classifiers, embedders, and publishers. Tasks declare dependencies and the engine resolves execution order.

Infrastructure

What This Means for You

Five things worth knowing about how the algorithm actually works — and what they imply for users and creators.

1

Ranking and visibility are separate

A high model score does not guarantee that a post appears. Phoenix and RankingScorer decide order; visibility filtering separately evaluates viewer relationships and safety labels, and can drop a post after ranking.

2

Your negative actions matter a lot

Block, mute, "not interested," and report all carry negative weights in the scoring formula. Using them actively trains the algorithm away from similar content. The scoring formula explicitly penalises posts you're predicted to dislike.

3

Author diversity is enforced algorithmically

The author diversity scorer applies an exponential decay to repeated authors sorted by score. Even if one account dominates your highest scores, later posts from that account get progressively smaller multipliers — ensuring your feed isn't flooded by a single creator.

4

Out-of-network posts are at a disadvantage

After the diversity step, out-of-network posts get score × OON_WEIGHT_FACTOR (less than 1). However, new users get a higher OON factor to help them discover content before building a follow graph, and topic feeds get their own OON factor.

5

Scores are consistent and cacheable

Candidate isolation in the transformer means a post's score doesn't change based on what else is in the request. This makes scored posts cacheable in Redis — so if you've already paid the ML cost for a post, its score can be reused in future requests.

6

Ads respect safety boundaries

The new ads blending system includes brand safety hydrators that track safety labels on organic content. Ads are not injected adjacent to content that violates brand safety thresholds, and the injection positions are validated against the organic post layout.

What Changed on August 13

This release replaces the demonstration-level picture with substantially more of the production system: real defaults, full model training code, visibility decisions, and the systems that create safety labels.

Scoring defaults

The weights are now inspectable

Key Home Mixer parameters now expose the production-default values used to blend Phoenix predictions, including strong negative weights for not interested, mute, block, and report.

Phoenix model

Training and serving code replaces the demo

The repository now includes the code used to train the feed models, a Rust serving layer, synthetic data generation, and a quickstart for a proof-of-concept training run.

Visibility filtering

Ranking and eligibility are visibly separate

The released visibility-filtering/ code shows ordered rules that can allow, drop, or return an interstitial response. Additional recommendation-only rules apply to out-of-network posts.

Labeling stack

The inputs to visibility decisions are included

Botmaker, Scarecrow, Agatha, BDSM, user credibility, media models, adult-content classifiers, and abuse enforcement reveal how posts and accounts receive labels used by filtering.

SimClusters

A third candidate source

Out-of-network retrieval is no longer explained as Phoenix alone. SimClusters finds posts through communities formed by shared engagement patterns and runs alongside Thunder and Phoenix retrieval.

Diversity reranking

VMRanker is now part of the visible path

After scoring adjustments, VMRanker uses a determinantal point process over embeddings to reduce similarity between neighbouring posts while preserving relevance.

Under the Hood

People can inspect their visibility labels

X is piloting an account-level transparency report at x.com/i/under_the_hood, backed by code in the released under-the-hood/ directory.