I spent a weekend digging through the open-sourced X (formerly Twitter) algorithm. What I found was both fascinating and practical: a Grok-based transformer model that predicts your behavior with surprising sophistication.
This isn’t speculation. This is what the code actually does.
The Architecture: Phoenix, Thunder, and Home Mixer
The “For You” feed is powered by three main systems:
1. Phoenix: The Brain
Phoenix is a Grok-based transformer model (yes, the same transformer architecture family as xAI’s Grok). It handles two critical functions:
- Retrieval: Finding relevant posts from millions of candidates using a two-tower model
- Ranking: Scoring posts by predicting engagement probabilities
The ranking model uses a clever technique called candidate isolation: posts can’t “see” each other during scoring, only the user’s context. This ensures consistent, cacheable scores.
| |
2. Thunder: The In-Network Source
Thunder is an in-memory post store that tracks recent posts from accounts you follow. It’s optimized for sub-millisecond lookups.
Key insight: In-network posts get preference. When you follow someone, their posts are more likely to appear in your feed than posts from strangers with similar engagement predictions.
3. Home Mixer: The Orchestrator
This is the glue. It:
- Fetches your engagement history
- Retrieves candidates from both Thunder (in-network) and Phoenix (out-of-network)
- Hydrates posts with metadata
- Filters ineligible content
- Runs the scoring pipeline
- Selects top candidates
- Returns your ranked feed
The Scoring Formula
Here’s the actual scoring logic from the codebase:
| |
The model predicts the probability of each action, then multiplies by a weight. Positive actions add to your score. Negative actions subtract.
This is crucial: one block can hurt more than ten likes help.
The 19 Signals That Determine Your Reach
The Phoenix model predicts probabilities for 19 distinct user actions:
Positive Signals
| Signal | What It Means | Code Reference |
|---|---|---|
favorite_score | P(user will like) | ServerTweetFav |
reply_score | P(user will reply) | ServerTweetReply |
retweet_score | P(user will repost) | ServerTweetRetweet |
quote_score | P(user will quote tweet) | ServerTweetQuote |
click_score | P(user will click post) | ClientTweetClick |
profile_click_score | P(user will click author profile) | ClientTweetClickProfile |
photo_expand_score | P(user will expand image) | ClientTweetPhotoExpand |
vqv_score | P(user will watch video quality view) | ClientTweetVideoQualityView |
share_score | P(user will share) | ClientTweetShare |
share_via_dm_score | P(user will DM post) | ClientTweetClickSendViaDirectMessage |
share_via_copy_link_score | P(user will copy link) | ClientTweetShareViaCopyLink |
dwell_score | P(user will dwell on post) | ClientTweetRecapDwelled |
quoted_click_score | P(user will click quoted tweet) | ClientQuotedTweetClick |
follow_author_score | P(user will follow author) | ClientTweetFollowAuthor |
dwell_time | Expected dwell duration (continuous) | ContinuousActionName::DwellTime |
Negative Signals
| Signal | What It Means | Code Reference |
|---|---|---|
not_interested_score | P(user clicks “not interested”) | ClientTweetNotInterestedIn |
block_author_score | P(user will block author) | ClientTweetBlockAuthor |
mute_author_score | P(user will mute author) | ClientTweetMuteAuthor |
report_score | P(user will report post) | ClientTweetReport |
The Author Diversity Penalty
Here’s something most people don’t know: if you post multiple times, your posts compete against each other.
From the code:
| |
The algorithm sorts your posts by score. The first gets full weight. Each subsequent post gets penalized:
| |
The exact decay factor and floor are excluded from the open source release, but the exponential decay pattern is clear.
Implication: Quality beats quantity. One excellent post outperforms five mediocre ones.
The Filtering Pipeline
Before scoring, posts go through a gauntlet of filters:
| Filter | What It Does |
|---|---|
DropDuplicatesFilter | Removes duplicate post IDs |
AgeFilter | Removes posts older than threshold (~48h) |
SelfTweetFilter | Removes your own posts from your feed |
RetweetDeduplicationFilter | Dedupes reposts of same content |
PreviouslySeenPostsFilter | Removes posts you’ve already seen |
PreviouslyServedPostsFilter | Removes posts served in current session |
MutedKeywordFilter | Removes posts with your muted keywords |
AuthorSocialgraphFilter | Removes posts from blocked/muted accounts |
IneligibleSubscriptionFilter | Removes paywalled content you can’t access |
VFFilter | Post-selection visibility filter (spam, violence, etc.) |
The MutedKeywordFilter is worth noting. If your post contains keywords that many users have muted, it’ll be filtered out for those users regardless of its score.
Video Quality Views: The Duration Threshold
Videos only contribute to VQV (Video Quality View) scoring if they meet a minimum duration:
| |
The exact MIN_VIDEO_DURATION_MS is excluded, but industry standards suggest 2-3 seconds minimum. Videos shorter than this get zero weight for the video view signal.
Optimal Video Lengths
| Duration | Best For | Notes |
|---|---|---|
| 2-15 seconds | Loops, memes, quick hits | Fast engagement, easy shares |
| 30-60 seconds | Tips, insights, reactions | Sweet spot for dwell time |
| 1-2 minutes | Tutorials, stories, threads | Maximum dwell if engaging |
| 2+ minutes | Educational deep dives | Only if content is compelling |
Video Best Practices
| โ Do | โ Don’t |
|---|---|
| Hook in first 1-2 seconds | Slow intros |
| Add captions | Sound-only content |
| Native upload | YouTube/TikTok links |
| Strong thumbnail | Boring first frame |
Dwell Time: The Underrated Signal
The algorithm tracks two distinct dwell signals:
dwell_score: Binary: Did they stop scrolling?dwell_time: Continuous: How long did they spend?
The dwell time is treated as a continuous value, not a probability:
| |
This means longer content that holds attention is genuinely rewarded, not just content that stops the scroll.
Dwell Time by Duration
| Duration | Signal Strength | What It Means |
|---|---|---|
| < 500ms | None | Scrolled past |
| 500ms - 2s | Weak | Brief pause |
| 2-5 seconds | Good | Genuine interest |
| 5+ seconds | Great | Strong engagement |
| 10+ seconds | Best | Deep engagement |
How to Maximize Dwell Time
- Write longer, multi-paragraph posts that take time to read
- Use storytelling that keeps people engaged
- Create threads with valuable content across multiple posts
- Add multiple images to swipe through
- Include detailed visuals people will examine
The Out-of-Network Penalty
In-network posts (from accounts you follow) get preference over out-of-network posts:
| |
Out-of-network content is multiplied by OON_WEIGHT_FACTOR (a value less than 1). This means even a viral post from a stranger has to overcome a built-in handicap compared to a post from someone you follow.
Implication: Growing your follower count has compounding benefits beyond vanity. Your posts get an algorithmic boost with your followers.
The ML Model: Grok-Based Transformer
The ranking model is a transformer architecture ported from xAI’s Grok-1 release. Here’s what makes it interesting:
Hash-Based Embeddings
Instead of looking up users and posts in giant embedding tables, the model uses multiple hash functions:
| |
This allows the model to handle any user or post ID without maintaining massive lookup tables.
The Input Structure
The model takes three components:
- User embedding: Who is viewing
- History embeddings: What they’ve engaged with recently
- Candidate embeddings: Posts to be scored
| |
Candidate Isolation Attention Mask
Here’s the clever part. During attention, candidates can see the user and history, but cannot see each other:
| |
This ensures that a post’s score doesn’t depend on which other posts happen to be in the same batch. Scores are consistent and can be cached.
Practical Takeaways
Based on the code, here’s what actually moves the needle:
What to Optimize For
Replies: High-weight positive signal. Ask questions. Invite discussion.
Shares via DM: Surprisingly high weight. Create “send this to someone” content.
Profile clicks โ Follows: The
follow_author_scoredirectly contributes to ranking.Dwell time: Write substantive content that takes time to read.
Video quality views: Make videos 2+ seconds minimum, hook immediately.
What to Avoid
Blocks: Severe negative weight. Don’t be hostile.
Reports: Severe negative weight. Stay within guidelines.
Mutes: High negative weight. Don’t be spammy.
Excessive posting: The author diversity scorer will penalize your 3rd, 4th, 5th posts.
Content That Triggers Negative Signals
| โ Avoid This | Why It Hurts |
|---|---|
| Engagement bait (“Like if you agree!”) | Triggers “not interested” |
| Rage bait (intentionally provocative) | Triggers blocks and mutes |
| Spam patterns (same content repeatedly) | Triggers mutes |
| Excessive self-promotion | Triggers mutes and unfollows |
| Misleading headlines (clickbait) | Triggers “not interested” |
| Hostile replies (aggressive arguing) | Triggers blocks |
| Posting 5+ times per day | Diversity penalty + mutes |
These behaviors lead to mutes and blocks which severely damage your reach: often more than the positive engagement you might get.
Optimal Posting Cadence
Given the ~48-hour post retention window and the author diversity penalty:
| Posts/Day | Recommendation |
|---|---|
| 1 | Best reach per post |
| 2 | Good; space 12+ hours apart |
| 3 | Acceptable; space 8+ hours |
| 4+ | Diminishing returns |
The Algorithm’s Core Question
All of this complexity reduces to one question the model is trying to answer:
“Will this specific user engage positively with this content?”
It’s not asking what’s objectively “good.” It’s predicting your personal behavior based on your history.
This is why generic growth hacks have diminishing returns. The algorithm is personalized. What works for one audience may not work for another.
The sustainable strategy is straightforward: create content that genuinely resonates with your specific audience, and avoid behaviors that trigger negative signals.
TL;DR Cheat Sheet
โ Do This
| Action | Impact |
|---|---|
| Ask questions (triggers replies) | ๐ฅ๐ฅ๐ฅ |
| Create shareable content | ๐ฅ๐ฅ๐ฅ |
| Write longer posts (dwell time) | ๐ฅ๐ฅ |
| 1-2 quality posts per day | ๐ฅ๐ฅ |
| Space posts 10-12 hours apart | ๐ฅ๐ฅ |
| Respond to replies quickly | ๐ฅ๐ฅ |
| Use multiple images | ๐ฅ |
| Videos 30s-2min with strong hooks | ๐ฅ |
โ Avoid This
| Action | Impact |
|---|---|
| Getting blocked | ๐๐๐ |
| Getting reported | ๐๐๐ |
| Posting 5+ times in 24 hours | ๐๐ |
| Spammy/repetitive content | ๐๐ |
| Engagement bait phrases | ๐ |
| Hostile replies | ๐ |
Technical Notes
For those who want to dig deeper:
- Model architecture: Transformer with special attention masking for candidate isolation
- Inference: Predictions made per-user, not globally
- Serving stack: Rust-based candidate pipeline (
home-mixer/) calling Python ML models (phoenix/) - In-network source:
thunder/; Redis-like in-memory post store with Kafka ingestion - Framework: JAX + Haiku for the ML components
The exact weight values for each signal are excluded from the open source release (noted as “Excluded from open source release for security reasons” in the code), but the relative importance is clear from the architecture.
Related
- What Transformers Taught Me About Attention: Understanding the attention mechanism that powers this algorithm
Further Reading
- X Algorithm Repository: The source code
- Attention Is All You Need: The transformer paper
- Grok-1 Open Source: The base transformer architecture
The irony isn’t lost on me: I’m using insights about the algorithm to write content optimized for the algorithm. But at least now you know how the game works.
Changelog
- 2026-01-20: Initial comprehensive analysis of open-sourced X algorithm
- 2026-01-29: Added frontmatter metadata, minor formatting improvements