Writings

What the X algorithm actually rewards

Every number in this article comes from X's published ranking code, not from watching the feed and guessing. The weights are constants in one file. Where the code and the received wisdom disagree, and they disagree often, the code is what ships, and every one of those differences is marked as it comes up.

Almost everything you have read about the X algorithm is from 2023.

That was the first time X open-sourced it. Scala, hundreds of hand-tuned signals, a reputation score called TweepCred. Post at 9am. Never put a link in a post. Threads beat single posts. Every tip still circulating traces back to that release, and that release has since been thrown away and rewritten.

X has since published the code that actually runs. Not a description of it, not a blog post about it: the ranking itself, weights and all, in a public repository. The surprise is not how complicated it is. It is how little there is to it. You can hold the whole thing in your head at once.

All of it:

  1. X guesses what you will doFor every post it might show you, it predicts how likely you are to do each of about two dozen things. Reply. Like. Copy the link. Mute the author.
  2. Each guess gets a priceEvery prediction is multiplied by a number saying what that action is worth. The numbers are in one file, and you can read them in a minute.
  3. The prices are added upThat total is the post's score.
  4. Two discounts land on the totalOne for posting repeatedly. One for being a stranger to the reader.
  5. Everything is sorted by scoreThe top of the list is your feed.

That is it. No reputation score, no time-of-day rule, no penalty for links. Five steps and a list of prices.

The prices are where it gets interesting, because they are not what people assume. A reply is worth ten likes. Someone copying your link is worth forty. A report costs you 468.

Every number below is read off xai-org/x-algorithm on 12 September 2026. I have marked the places where the repository and the popular summaries of it disagree, because they disagree more than you would expect.

What happens when you open the app

Eight stages, in order, every time the feed loads. Figure A is the whole of it.

Three thousand posts are consideredAlmost none of them reach you. Run the cursor across them.

3000candidates, every time you open it
3,000 candidatesyour feed

Every strand is a post that could have been shown to you.

Up to 3,000 candidates gathered, 2,800 scored, and the variety pass only touches the top 150. What this means for you: your post is never judged against a shortlist. It is one of thousands being priced at once, and the only thing that separates it from the rest is the number it ends up with.

Three of the eight are plumbing. Query hydration loads who you are: your follows, your blocks, your mutes, what you have already been shown. Candidate hydration attaches the actual text and media to the posts. Blending is where ads and Who to Follow get interleaved at the end.

The two that decide what you see are sourcing and scoring. Sourcing gathers up to three thousand posts you could be shown. Scoring puts them in an order. Everything people call “the algorithm” is the second one.

Worth noticing how brutal the narrowing is. Three thousand candidates go in. The variety reorder only bothers with the top 150. Whatever your post is competing against, it is competing on one number against a few thousand others, and almost none of them survive.

Where the posts come from

Two pipes feed that funnel. Thunder holds recent posts in memory and returns the ones from accounts you follow. Phoenix and SimClusters go and find posts from accounts you don’t.

OonWeightFactor 0.75 and TopicOonWeightFactor 0.5. Nothing about the post earns the markdown, it is applied for how the post was found. What this means for you: reaching people who do not follow you is not a fair fight. Your post has to predict about a third more engagement than a followed account's to land in the same slot.

The part that surprised me: a post from someone you don’t follow is multiplied by 0.75 before anything about it is scored. If it was reached by topic rather than by similarity, it is multiplied by 0.5. The discount is not earned by the post being worse. It is applied for being out of network, in advance, to all of them.

So reaching strangers is not a fair fight, and it was never meant to be. An out-of-network post has to predict roughly a third more engagement than an in-network one to land in the same position.

The model reads you, not your post

Phoenix embeds you and each candidate post as vectors and predicts how likely you are to do each of about two dozen things: like, reply, quote, share, click, dwell, follow the author, mute them, report them.

Two details matter more than they sound like they do.

The first is that it reads your action history, up to 1,024 positions of it. Not the post’s history. Yours. When people say “the algorithm decided my post was bad”, the model did not evaluate the post in isolation at all. It predicted what one specific viewer tends to do with things like it.

The second is that candidates cannot attend to each other during ranking. Each post is scored against your context alone, never against the other posts in the batch. Your score does not depend on who else posted that minute. There is no queue you are at the back of.

How the score is made

Steps two and three, with real numbers in them. One post, five of its predicted actions, and the arithmetic that turns them into the single number everything is sorted by.

Five of about twenty-six actions, with one worked post. The model predicts the rates, param.rs sets the prices, and the two multipliers land afterwards. What this means for you: you influence the rates and nothing else. The prices are fixed and the multipliers depend on who you are and when you posted.

There is nothing hidden behind that. The rest of this piece is just the prices, where they came from, and what they mean for what you post.

Twenty-one numbers

This is the file. home-mixer/params/param.rs, the weights that multiply each predicted action into one score. All twenty-one of them, priced in likes, because a like is the only unit anyone has an instinct for. The top block is what X pays you for. The bottom block is what it charges you, on a scale of its own, because it does not fit on the same one.

Read it as a statement of values, because that is what it is. Somebody sat down and decided what a person doing each of these things is worth to X.

What it pays for× a like
Share via copy link2040×
Reply510×
Quote510×
Share via DM510×
Follow author4
Share2
Repost1
Like0.5
Click0.40.8×
Open link0.20.4×
Video open0.070.14×
Photo expand0.050.1×
Dwell0.050.1×
Post unexplored0.020.04×
Profile click0off
Video quality view0off
What it charges you× a like, own scale
Not dwelled-0.020.04×
Block author-31.262×
Not interested-43.286×
Mute author-58.8118×
Report-234468×

Copying your link to send it somewhere else is the single most valuable thing a reader can do, at forty times a like. Replying, quoting and sending by DM are ten times a like. Following you off the back of a post is eight. A like is 0.5, which puts it near the bottom of everything that counts as engagement at all.

Two actions are predicted and then multiplied by zero. Profile clicks and video quality views are both switched off. The model still works out how likely you are to do them, and the ranking ignores the answer.

Then the negatives, which are on a different scale entirely. Block is −31.2. Not interested is −43.2. Mute is −58.8. Report is −234, which is 468 times a like in the other direction.

One caveat, and most versions of this going around get it wrong. These weights multiply predicted probabilities, not counts. A report weight of −234 does not mean one report cancels 468 likes. It means the model’s belief that you might report a post costs 468 times more per unit of belief than its belief that you might like it. Nobody has to actually report anything. The prediction alone does the damage.

It is a hard sentence to feel, so the arithmetic has handles on it below. Put in the numbers you actually see on a post. Views turn the counts back into rates, and the rate is what gets multiplied.

Score a post yourselfCounts go in. Rates are what get scored.

7.9/10
0.020weighted scoreVery good

900 likes on 100k views is a 0.90% like rate, and the rate is what the weight multiplies.

Nine reports cancel nine hundred likes on this post, because a report is weighted 468 times a like. Bookmarks do nothing: there is no bookmark weight in the file and none for views either. What this means for you: two of the numbers X prints on the front of every post are not in the ranking at all.

Start with the post as it loads: nine hundred likes, a hundred and sixty replies, thirty people who copied the link. A good week. Now drag reports up.

At nine reports the whole thing goes negative. Nine. Against nine hundred likes, because a report is weighted 468 times what a like is, and four hundred and sixty-eight times a small number is still a much bigger number. You cannot win that back on the likes slider even at its maximum.

Drag bookmarks and watch nothing happen. There is no bookmark weight in the file. There is no weight for views either. Two of the numbers X puts on the front of every post are not in the ranking at all.

If you write for one thing, write for the reply. If you avoid one thing, avoid being the post someone mutes.

The one weight with a reason attached

Most of those weights are simply there, with no explanation attached. One of them has a note in the repository explaining how it got to be what it is, and it is the most human thing in the whole codebase.

A reply from a mutual counts tripleSomeone who follows you back, replying to your original post. Move across the field.

3×what a mutual's reply is worth
Every dot is one replyfrom anyone5from a mutual150 of 133 worth 15
10 JulyTested at five values at once: 0, 5, 10, 15 and 20.
13 JulyShipped to everyone at 20, the top of the range.
24 JulyCut to 15. The World Cup was on and people were missing it, because too much of the discussion came from accounts they did not follow.
BidirectionalFollowReplyWeightBoost 15, the only weight in the repository with a written reason attached. What this means for you: following back the people who reply to you is worth more than almost anything else you can do, because it triples the weight of every reply between you in both directions.

A reply to an original post from someone you follow who follows you back is weighted 15 instead of 5. Mutual follows, triple weight.

It was A/B tested on 10 July 2026 at five values including zero. Twenty won, and shipped to everyone on the 13th. Eleven days later it was cut to fifteen, because the World Cup was on and, in the repository’s own words, “some people weren’t seeing as much discussion of it as they wanted, given many of the posts were from accounts they didn’t follow.”

They turned the dial up on your friends, discovered it had quietly walled people off from a thing the whole world was talking about, and turned it back down. That is a product decision, made in public, with the reasoning attached. I wish more of the file looked like this.

The practical read is unglamorous. Follow back the people who reply to you. Their replies are worth triple, and yours on their posts are too.

The multiplier nobody mentions

After the weighted sum there are adjustments, and they do more to your reach than any posting tip. The first one is below. Press post again a few times and watch your own circles shrink.

Post again and you compete with yourselfEvery extra post of yours in the same feed is worth less than the one before

100%what post 1 is worth
100%post 1post 2post 3post 4post 5post 6

Your first post of the day counts for everything it earned.

AuthorDiversityDecay 0.5, AuthorDiversityFloor 0.25. Not a penalty for spamming but a rule protecting the reader from a feed that is all you. What this means for you: your second post of the session competes against your first, and it loses. Waiting is free and costs the earlier post nothing.

Each further post from the same author in one feed load gets multiplied down. The second is 0.63 of the first. The third is 0.44. By the fifth you are at 0.30, and it never falls past a quarter, because there is a floor.

So posting five times in an hour hands your fifth post a seventy percent cut before it competes with anyone. Not a penalty for spamming, and nothing to do with quality. It is a diversity rule protecting the reader from a feed that is all you.

Space your posts out. When you want to say another thing right now, reply to someone instead. Replies are worth ten times a like and they do not compete with your own last post.

That is the only pattern in the code that cares how you schedule. Not the hour, not the day. Just how many of yours arrive together.

Spacing, not timingSpread out, every post is worth full weight. Stacked, the column goes dark.

0%of your week, given away
Mon
Tue
Wed
Thu
Fri
Sat
Sun

Nothing posted yet.

There is no time-of-day rule in the ranking code, so this is not a best-time-to-post chart. The only scheduling pattern the code has an opinion about is how many of yours land together. What this means for you: the hour does not matter and the gap does.

Both multipliers land after the model has already decided what you would enjoy, which is the part I found hardest to picture. So here are six posts going through it one rule at a time.

The same six posts, ranked three timesThe model picks an order. Then two rules that know nothing about the posts rearrange it.

2Your launch thread0.480
3Your demo clip, ten minutes later0.440
4Your third post, still going0.410
5A founder you follow, asking something0.395
1A stranger's pricing-page teardown · stranger0.520
6A stranger's portfolio reel · stranger0.300

All six scored on how likely you are to act on them, based on what you have done before. On merit the stranger's teardown is the best post here and your launch thread is second.

Step through it and watch the order change without a single score being re-predicted. What this means for you: the feed you see is not the ranking the model produced. It is that ranking with two corrections applied on top, one for how often you post and one for who you are to the reader. Neither is something you can write your way out of. A worked example, not production numbers: no trained model is published, so nobody outside X can compute a real score.

Step through it. On predicted engagement the stranger’s thread wins and your three posts hold second, third and fourth. Apply diversity and your own posts fall away from each other. Apply the out-of-network discount and the thread that was winning drops behind a question from a mutual it had comfortably beaten.

Nothing about those posts changed. The model’s opinion of them did not change. Two multipliers rearranged the feed after the fact, and neither of them is something you can write your way out of.

What is not in there

The absence of things is the finding. I went looking for the rules everyone repeats and could not find them.

Links are penalisedNot in the code
There is no link rule. Opening a link is a positive action at 0.2. If link posts do worse, it is because the model predicts fewer of the actions X pays for.
One report cancels 468 likesWrong
The weights scale predicted probabilities, not counts, which makes this specific sentence wrong.
TweepCred decides your reachNot in the code
Not in home-mixer. A user-cred-v2 module exists in the repository, the ranking scorer does not call it, and it has no README.
Post at the right timeNot in the code
No time-of-day rule anywhere. Local hour is an input the model can learn from, which is not the same as a rule you can beat.
Hashtags trigger the spam filterCannot be checked
No hashtag rule in ranking. Spam classification lives in Grox, whose prompts are withheld, so this can be neither confirmed nor denied.
Video beats textWrong
Video open is 0.07 and video quality view is 0. A text post that earns replies scores far higher than a video that is merely watched.
Bookmarks are a strong signalNot in the code
There is no bookmark weight in the file, and none for views either. Two of the numbers X prints on every post are not in the ranking at all.
Threads get 40 to 60% more reachCannot be checked
That number is from analytics vendors, not from this code. Each post in a thread is scored on its own.

Also missing: any production model weights. What is published is the architecture, the trainer and the ranking parameters. The trained model is not in there, so nobody outside X can compute a real score for a real post. Anyone selling you a tool that does is selling you a guess.

What I would actually change

Four things follow from the file, and only three of them are things I had believed.

Write for the reply, not the like. This is the biggest gap between what people optimise for and what the code pays for. Twenty to one.

Write things worth sending to one person. The copy-link share is the highest weight in the file by a factor of four over the next one. A post someone DMs to a co-founder is the best outcome available to you.

Space your posts out and reply in between. The decay curve is real and it is steep, and replies sidestep it entirely.

Stop avoiding links. I had this one wrong for years. There is no link penalty in the ranking code. There is a media-card trade-off in how a link renders, and there is the plain fact that a post sending people away earns fewer of the actions that score. Those are different problems from the one everybody warns you about, and only one of them is yours to fix.

The thing I keep coming back to is that the weights are legible in a way the old advice never was. You do not have to guess what the platform wants. It is twenty-one numbers in a file, and it wants replies and it wants your post sent to someone privately, and it really does not care very much whether anyone liked it.


The game plan

Everything above, turned into what to actually do. Ordered by how much the file says it is worth, not by how often you hear it.

  1. Write for the reply. A reply is ten likes, a quote is ten, a DM share is ten. This is the biggest gap between what people optimise for and what the ranking pays for. End on something a person can answer. A question they have an opinion about beats a question they have to look something up for.
  2. Write things worth sending to one person. A copied link is forty likes, four times the next best thing in the file and the highest number there is. The test is whether a reader would paste it into a DM with “this is us”. That is usually a specific number, a named mistake, or a screenshot.
  3. Follow back everyone who replies to you. A reply between two accounts that follow each other is weighted 15 instead of 5. It costs nothing, it triples every future reply in both directions, and it is the only weight X has explained in writing.
  4. Leave hours between your own posts. Your second post in the same feed load is worth 63% of your first, the third 44%, and it floors at 25%. Waiting is free. The earlier post loses nothing by it.
  5. Reply to other people in the gaps. Replies carry the second-highest weight in the file and they do not compete with your own last post the way another post does. This is the one thing that gets better the more you do it.
  6. Stop avoiding links. There is no link rule in the ranking code. If your link posts underperform it is because they earn fewer replies and shares, not because of a penalty. Fix the post, not the URL.
  7. Do not chase bookmarks or views. Neither has a weight in the file. They are the two numbers X prints largest on every post and the ranking ignores both.
  8. Protect the downside first. Nine reports cancel nine hundred likes. Mute is 118 likes and not-interested is 86, both in the wrong direction. The ceiling on a great post is far lower than the floor under a post that annoys people, so the cheapest win available is not writing the second kind.

What none of this can tell you is what to say. The weights price actions, not ideas, and the model predicts from what each reader has done before. Someone who has never replied to anything will not start with your post because you ended on a question.

Every weight and multiplier above is read off 1 the candidate caps come from the same file, the order the multipliers are applied in is in the scorer 2 the July dates and the World Cup rationale are quoted from the change note 3 and the pipeline stages and the sentence about predicted probabilities are from the README 4 Snapshot taken 12 September 2026. If a weight has moved since, the repository is right and I am stale. Corrections welcome.