Back to blog
Social Media Marketing

We Read X’s Algorithm Source Code — 17 Filters Matter More Than the Weights

X's algorithm repository is open, and this time it is not the 2023 snapshot that was published once and abandoned. It is the code running the For You feed right now. Commits land through August 25, and two update notes — August 13 and August 14 — sit at the top of the README.

We covered the secondhand reporting in X's Algorithm Weights Are Public. This time we opened the repository and read it. Two things came out of that. The weight-ratio reading that spread everywhere is wrong — wrong enough that X added code comments to stop it. And the levers a marketer can actually pull are not in the weights at all. They sit on either side of them.

What Is Actually in the Repository

xai-org/x-algorithm ships under Apache 2.0. It splits into two paths: the request path that assembles a feed the moment someone pulls to refresh, and the labeling path that continuously attaches labels to posts and accounts.

home-mixer is the center of the request path. It is written in Rust, and the full pipeline — gather candidates, filter, score, cut — lives there. Phoenix, the ranking model, arrived with both its JAX training code and its Rust serving engine. X states plainly that this release is the production implementation, not a demonstration model. Synthetic data generators are included, so a shrunk version can be trained end to end on a single GPU.

The labeling path landed whole in the August 13 update: visibility-filtering, which decides whether a post can be shown at all, plus the systems that manufacture the labels it reads (grox, agatha, bdsm, user-cred-v2, scarecrow, botmaker, abuse-enforcement-service) and the image and video classifiers.

The August 14 note is a different kind of entry. It is not a feature. It is a correction.

One Feed Request, Step by Step

Candidate Retrieval

Three sources are queried in parallel.

  • Thunder — recent posts from accounts the viewer follows, held in memory. Default cap 1,200.
  • Phoenix retrieval — embedding search across accounts the viewer does not follow. Default cap 1,000.
  • SimClusters — clusters accounts and posts by who engages with what, then pulls candidates from the clusters.

Another source contributes up to 800 more. Roughly 3,000 candidates enter the pipeline.

Seventeen Pre-Scoring Filters

Seventeen filters run in order before anything is scored. A post caught here never gets a score at all.

FilterWhat it removes
DropDuplicatesFilterThe same post returned by more than one source
CoreDataHydrationFilterPosts whose text and metadata failed to load
AgeFilterPosts older than 48 hours
SelfTweetFilterThe viewer's own posts
OONRetweetReplyFilterReposts and replies from accounts the viewer does not follow
OONNsfwSimclustersFilterSimClusters posts from adult-flagged authors
RetweetDeduplicationFilterRepeated reposts of the same post
IneligibleSubscriptionFilterSubscriber-only posts the viewer cannot access
PreviouslySeenPostsFilterPosts already shown
PreviouslySeenPostsBackupFilterThe same, from a second impression record
PreviouslyServedPostsFilterPosts already served this session
MutedKeywordFilterPosts matching muted keywords
AuthorSocialgraphFilterPosts from blocked or muted accounts
VideoFilterVideo posts when the request excludes video
TopicIdsFilterPosts outside requested topics, posts in excluded topics
NewUserMinEngagementFilterLow-engagement out-of-network posts, for new accounts
InventoryHoldoutFilterA configured share of posts, chosen deterministically

The third row is the one to internalize. Forty-eight hours. After that, no score matters.

Scoring

Phoenix assigns a probability to each action a viewer might take: favorite, reply, repost, quote, share, share via DM, share via copy link, a range of clicks, dwell, video views, following the author — and the negative actions, not interested, mute, block, report.

RankingScorer collapses them into one number.

Final Score = Σ (weight × P(action))

Selection and Visibility

Sort, keep the top 50. Then ask visibility-filtering about each post and viewer. Whatever it says to drop comes out. The response size is 35. Three thousand candidates in, thirty-five posts out.

Blending

Items the model does not rank get interleaved: ads, Who to Follow, prompts. Who to Follow sits at a fixed slot — position 6 — and the default ads blender reorders posts once more for ad adjacency.

The Weights, as Written in the Code

Straight from home-mixer/params/param.rs.

ActionWeight
Share via copy link20.0
Reply5.0
Quote5.0
Share via DM5.0
Follow author4.0
Share2.0
Repost1.0
Post click0.4
Open link0.2
Favorite0.5
Video open0.07
Photo expand0.05
Dwell0.05
Dwell time (continuous)0.004
Profile click0.0
Not interested−43.2
Block author−31.2
Mute author−58.8
Report−234.0
Not dwelled−0.02

A separate mutual-follow reply boost of +15.0 stacks on top. More on that below.

Why "Forty Times a Like" Is Wrong

Divide 20.0 by 0.5 and you get 40. Divide −234 by 0.5 and you get 468. Hence the claims: one copy-link share equals 40 likes, one report cancels 468 likes.

The comments X added to the code on August 14 reject that arithmetic outright.

Weights multiply predicted probabilities, not raw counts. The formula is Σ(weight × P(action)), not Σ(weight × action count). What gets multiplied is the chance that this viewer reports this post — not how many reports the post has collected.

So why is the report weight −234? Because the baseline probability of a report is more than a thousand times lower than that of a like. When a probability is that small, the weight has to be large for the prediction to move the final score at all. The big number is scale correction, not importance.

A second claim falls with it: that coordinated mass reporting or blocking can crush an account's reach. X gives three reasons in the comments.

Recommendations are personalized. Reports from bad actors mostly affect recommendations shown to users similar to those bad actors, not everyone equally.

The action has to occur on a post served in the Home Timeline to count for ranking. Passing a link around a group chat and reporting from there has no ranking impact.

And users have no reliable way to make a specific post appear in their own timeline in the first place.

Three Adjustments After the Weighted Sum

Author Diversity Decay

When one author has several posts among the candidates, everything after the first is discounted.

multiplier = (1 − floor) × decay^rank + floor
decay = 0.5, floor = 0.25

That gives 1.0, then 0.625, then 0.4375, then 0.34375, bottoming out at 0.25. Push four posts from one account into a single feed assembly and the fourth is valued at roughly a third of the first.

Out-of-Network Discount

Posts from accounts the viewer does not follow are multiplied by 0.75. For topic-based requests it is 0.5. Replies and reposts from followed accounts take the same discount.

One constant is worth staring at. For new users — account younger than a threshold, following at least five accounts — that factor drops to 0.00001. Effectively zero. A brand-new user's feed is followed accounts and almost nothing else.

New-Author Boost

Low-impression authors get lifted. The conditions are in the code: under 1,000 impressions, 1,000 or fewer followers, posted within 24 hours. The target slot is 15 to 16, and boosted placement is capped at 85% of the way down the feed.

VMRanker then calls a separate service that reorders the result with a determinantal point process over post embeddings, trading a little score for less similarity between neighbors.

What Actually Changed in July: the Mutual-Follow Boost

The repository includes a document tracing one algorithm change through its diffs — the bidirectional follow boost that drew attention in July.

On July 10, X started an A/B test assigning boost values of 5, 10, 15 and 20 to a small share of users, with everyone else at 0. On July 13, results were strong enough to roll value 20 out broadly. On July 24, after feedback during the World Cup that people were seeing too little discussion from accounts they did not follow, the value was lowered to 15. That is the default in the code today.

The mechanic is simple: if the author is a mutual follow, add 15 to the reply weight. 5.0 becomes 20.0. Four times.

The eligibility check matters more than the number. bidirectional_boost_eligible requires all three: not a reply, not a repost, and a mutual-follow author. The boost applies only to original posts from mutual follows. The same person's replies and reposts get nothing.

Ranking and Visibility Are Separate Systems

This is stated as a design principle in the repository. Ranking decides order. Visibility filtering decides whether a post can be shown at all. Different services, different inputs, different rules.

visibility-filtering returns one of three answers per post and viewer: allow, interstitial, or drop. Rules evaluate in order, and the first drop ends evaluation.

The Band Where Followers See You and Others Do Not

Here is the part worth understanding. A subset of rules applies only when the post is a recommendation from an account the viewer does not follow, and those rules can only drop. Spam caught at high recall, for instance.

The same post is shown normally to a follower and never recommended to anyone else. This is the closest thing in the code to what people call a shadowban, and the rule names say it out loud: RecommendationsOnlyRule, AbusiveHighRecallRule, DoNotAmplifyNonFollowerRule, MaliciousUrlOonDropRule.

In account analytics it looks strange. Follower response holds steady while impressions collapse. Reach down with engagement rate flat is the signature to look for.

Where the Labels Come From

The labels those rules read are produced continuously, off the request path.

  • grox — classifiers that run as posts are published: spam, adult content, violent media.
  • media-model-proxy / clip — image and video models, and the embeddings feeding them.
  • agatha — batch jobs that score an account by how others respond to it. The key axis is blocks, reports and spam reports relative to favorites.
  • bdsm — reads an account's action sequence over time to find inauthentic or abusive patterns.
  • user-cred-v2 — PageRank over the follow graph and engagement edges.
  • scarecrow + botmaker — apply label rules to events as they happen.
  • abuse-enforcement-service — acts on model scores: label, challenge, or suspend.

Agatha's axis is instructive. It reads blocks and reports as a ratio to favorites, not in absolute counts. An account that gets a lot of response and a proportional amount of complaint is treated as normal.

What Is Not Published

X named the exclusions: Grox's LLM prompt files, and some botmaker rules. The reason is gaming. Publish the full rule text and circumvention becomes designable.

In place of that, X is piloting Under the Hood, which shows aggregate statistics on the visibility-limiting labels applied to your own account and posts — the tool covered in X Open-Sources Its Reach Code. Read the rules in the code, check your own labels in the tool. That pairing is the transparency model X is proposing.

One more entry deserves attention. The August 14 note added a Brazil 2026 election filter: under Brazilian electoral law, For You now removes posts from accounts reported to Brazil's Electoral Court, unless the viewer explicitly follows the account. The account list was updated on August 25. It is a clean example of how jurisdiction-specific law enters the code.

What a Marketer Can Do With This

Forty-eight hours is the whole window. AgeFilter cuts everything past it. There is no long tail in For You. Publication time and the first few hours are the entire lifespan.

Posting more does not scale linearly. Author diversity decay values the fourth post in a feed assembly at 34% of the first. Two or three posts spread across the day beats five stacked together.

Mutual follows are the single largest lever. Original posts from mutual-follow authors carry a 4× reply weight. Growing follower count and building mutual follows are different operations in algorithmic terms. Mutual follows with industry accounts, partners and client-side contacts have measurable value.

Reposts and replies cannot earn the boost. Eligibility is limited to original posts, and replies and reposts from non-followed accounts are cut at the pre-scoring stage anyway. A repost-heavy channel strategy is structurally disadvantaged.

Demote likes as a KPI, but skip the multiplication. A 0.5 weight is genuinely low. Still, "40 copy-link shares equals 1,600 likes" does not hold. Read the direction only: content people want to carry elsewhere, and content that draws replies, is valued higher.

Campaigns targeting new users need the follow first. The out-of-network factor for a new account is 0.00001. Reaching that feed requires a follow, not a recommendation.

Reach down with engagement rate flat means check labels, not content. That pattern points at visibility filtering rather than ranking. Checking Under the Hood is faster than rebuilding a content strategy.

Finally, X says experiments running at 10% of traffic or more should be visible in the repository, and cron scripts push production defaults back into the published code. Parameter changes leave diffs — which is how the July boost dropping from 20 to 15 is verifiable at all. For a different angle on X's tooling, see X Launches Its Ads MCP Server. Watch the repository instead of waiting for announcements, and the next change arrives before the coverage does.

Frequently Asked Questions

Is a report weight of −234 really 468 times a like?

No. Weights multiply predicted probabilities, not action counts. The baseline probability of a report is more than a thousand times lower than a like, so the weight must be large for the prediction to move the score at all. X added code comments on August 14, 2026 specifically rejecting this ratio reading.

Are posts older than 48 hours excluded from For You entirely?

Yes. AgeFilter removes them before any scoring happens, so the score is never computed. This applies to the For You feed only — search and profile visits are unaffected.

Which posts qualify for the mutual-follow boost?

Only original posts from mutual-follow authors. The code requires all three conditions: not a reply, not a repost, and a mutual-follow author. When they hold, the reply weight of 5.0 gains 15.0 for a total of 20.0.

What does falling reach with a flat engagement rate indicate?

It points at visibility filtering rather than ranking. Some rules apply only when a post is a recommendation from an account the viewer does not follow, and they can only drop — so the same post stays visible to followers while disappearing from recommendations. Checking your account labels in Under the Hood is the faster first step.

Where does your own site stand?

To apply what you just read to your own site, start with a free audit of where things are now.

A strategist replies within 24 hours on business days.

Read next

We Read X’s Algorithm Source Code — 17 Filters Matter More Than the Weights | BestPartner