X ranking weights: what the code actually says | Gyo
Reading X’s ranking weights
Copy links, negative feedback, same-author discounts and age limits, read from the code with the switches and assumptions left in view.
Gyo
A copied link gets a weight of 20 in X’s published ranking code. A like gets 0.66. Divide one by the other and you get 30.3—the sort of number that makes a good screenshot and a bad rule for posting.
The missing piece is probability. The ranker multiplies each weight by how likely it thinks a particular viewer is to take that action. A 1% chance of copying a link contributes 0.01 × 20 = 0.20. A 30% chance of liking contributes 0.30 × 0.66 = 0.198. In that example, the two terms are almost equal, despite the thirtyfold difference between their weights.
That is how to read the tables below. They describe the arithmetic applied to a model’s predictions. The source is X’s published recommendation code; the exact revisions and verification notes are at the end.
Copy links, likes and the rest
Here are the published action weights. The last column divides each coefficient by 0.66, so everything can be compared on the same scale.
Action
Weight
Like-weight ratio
Copy link
20.0
30.3
Reply prediction, eligible mutual-author original
FAQ
Are the X algorithm weights public?
Yes. X’s repository includes coefficient defaults and scoring code. The links here point to revision 9106e9f, checked against b220448 on November 3, 2026. Live experiments can override those defaults.
What is a like worth in the X algorithm?
The like coefficient is 0.66. A copy link has a coefficient of 20, about 30.3 times larger. Each multiplies a predicted probability: a 1% copy-link prediction contributes about as much as a 30% like prediction.
Why does a post stop getting reach?
The code gives us places to look: eligibility filters, candidate selection and ranking. It cannot tell us where a particular post dropped out. That needs serving records or account analytics.
Does posting more often help?
There is no posting schedule in these coefficients. The enabled same-author diversity formula discounts additional candidates in a ranked set; it does not measure the total reach an author gains or loses by publishing another post.
20.0
30.3
Reply prediction, base coefficient
5.0
7.6
Quote
5.0
7.6
Share by DM
5.0
7.6
Follow the author
4.0
6.1
Share
2.0
3.0
Repost
1.0
1.5
Like
0.66
1.0
Open the post
0.3
0.45
Open an outbound link
0.2
0.30
Expand a photo
0.05
0.08
Open a video
0.02
0.03
Profile click
0.0
0
Video quality view
0.0
0
Copy links have a coefficient of 20. A reply prediction can reach 20 too, but only for an eligible candidate: the viewer and author must follow each other, and the candidate itself must be neither a reply nor a repost. The eligibility predicate supplies those conditions; the weight helper adds the 15-point boost to the base coefficient of 5.
The distinction is easy to lose in a short table. This is the predicted chance that the reader will reply to the candidate. It is not a blanket reward of 20 for publishing a reply to someone who follows you.
Quotes and DM shares come next at 5, followed by following the author at 4. A repost gets 1. That ordering is more useful than the loose advice to “get engagement”: the code assigns quite different values to different predicted actions.
Two zeroes are also worth looking at. Profile clicks and video-quality views contribute nothing through these particular terms. A good profile can still affect whether someone follows; the zero beside profile clicks does not settle that question. It tells us exactly one thing: this coefficient is zero in the published snapshot.
A second inside a post counts differently
Opening a post has its own coefficient, 0.3. Time spent afterwards is accounted for separately. The continuous coefficient for time after opening is 0.4; the coefficient for time in the scrolling feed is 0.006.
The coefficient ratio is about 66.7. These coefficients multiply predicted time outputs, not a stopwatch reading added to a post after someone views it. To show the arithmetic, suppose the returned outputs represent the following durations in seconds; multiply each by its coefficient and divide by 0.66:
Hypothetical predicted duration
Like-weight units/sec
Calculated like-weight units
Dwell after opening, 5s
0.61
3.0
Dwell after opening, 10s
0.61
6.1
Stop while scrolling, 300s
0.009
2.7
A predicted five seconds after opening gives a term of about 3.0 like-weight units. A hypothetical predicted 300 seconds in the feed gives about 2.7. The opening term itself is excluded from both calculations. These examples do not establish the deployed model’s output range, time caps or actual viewing behavior.
There is a temptation to turn that into advice about writing shorter posts, or getting people to click before they read. The calculation does not choose between those strategies. It shows that the two kinds of time are valued differently. Whether a particular piece earns either kind of attention is still a prediction the model has to make.
Negative feedback has much larger coefficients
The negative side of the table is much steeper. Ratios and percentages are rounded; coefficients retain their published values:
Action
Weight
Like-weight ratio
Probability matching one certain like
Report
-234.0
-354
0.28%
Mute author
-58.8
-89
1.12%
Not interested
-52.272
-79
1.26%
Block author
-31.2
-47
2.12%
The report coefficient is -234, about 354 times the magnitude of the like coefficient. The comments beside the scoring code explain part of the reasoning: reports are far rarer than likes, so a small coefficient would give the report prediction little influence. The claim about event frequency comes from those comments; it was not measured independently for this article.
The last column asks a deliberately narrow question: how large would one negative-action probability have to be to offset a like prediction of 100%, with every other term held at zero? For reports, 0.66 / 234 is about 0.28%. For muting, the answer is about 1.12%.
Those examples help explain the scale of the coefficients. They do not turn reports into a currency that can be subtracted from a post’s accumulated likes. The model is producing a prediction for a viewer, then adding up the weighted terms.
Muting has a larger coefficient magnitude than blocking: -58.8 against -31.2. The code treats them as separate outcomes. That is an interesting distinction, though the coefficients alone cannot tell us which one is more likely for a given audience.
What happens to a negative total
After summing the contributions, the code calls offset_score. With the published weights, negative-action predictions bounded between zero and one, and nonnegative contributions from the other terms, negative totals map into a narrow band from 0 to just below about 0.000897. A raw total of zero maps to 0.001; positive totals map above it.
So, at this step, a negative total sits below the positive band. The difference survives the conversion into positive-looking numbers; the offset has not made a bad score good. Later multipliers and selection steps still affect the final ordering.
The band width comes from the weights themselves. The positive coefficients used in that calculation sum to 43.345 and the negative magnitudes to 376.292. The upper edge of the negative band is 376.292 / (43.345 + 376.292) × 0.001, or about 0.000897. The helper does not clamp every input into that band. A raw total below −376.292 can still produce a negative result with these weights, and changing the weights changes the bounds. The stated range depends on those input assumptions; it is not an unconditional guarantee of offset_score.
The multiplier switch matters as much as the number
This was the easiest part of the repository to misread. There are several places where scores are calculated, and they do not all use the same switches.
In Home Mixer’s local coefficient setup, author diversity and in-network reply/repost rescoring are turned off. Read that file on its own and it would be easy to conclude that neither feature matters.
But Home Mixer also sends a request to VM Ranker with compute_value_model set to true. VM Ranker reads its own parameters, where both switches default to true. The local calculation is only part of the path. Request configuration and fallback behavior decide which result is used.
These are the VM Ranker defaults relevant here:
Setting
Published default
Condition or scope
Out-of-network coefficient
0.75
Non-topic scoring context, except an eligible new viewer
Topic out-of-network coefficient
0.5
Topic scoring context
Rescore in-network replies/reposts
Enabled
Applies the effective out-of-network coefficient when this option is used
Author diversity
Enabled
VM Ranker value-model path; local Home Mixer calculation disables it
New-viewer out-of-network coefficient
0.00001
Requires account age below the configured threshold and sufficient following
New-viewer age threshold
0 seconds
With this default, a nonnegative account age does not qualify
The tiny new-viewer multiplier, 0.00001, needs its eligibility check beside it. The code compares the reader’s account age with a threshold and also checks following count. With the published threshold set to zero seconds, a nonnegative account age does not qualify. An experiment could change that threshold; the constant by itself tells us little about how often this branch runs.
It is also the reader’s account being checked. Using this setting to explain why a new author gets little reach would mix up the two people involved.
The same-author discount
When author diversity is enabled, the formula uses decay 0.5 and floor 0.25:
multiplier = 0.75 × 0.5^k + 0.25
Here, k counts higher-ranked candidates from the same author in the ordering used by this step. The first candidate has k = 0; the next has k = 1.
Candidate position for the same author
Calculated multiplier
First candidate
1.0
Second candidate
0.625
Third candidate
0.4375
Fourth candidate
0.3438
Fifth candidate
0.2969
Limiting value as the count grows
0.25
The discount gets strong quite quickly. The second candidate receives 0.625 and the third 0.4375, approaching a floor of 0.25 as the count grows.
That describes competition among candidates in this calculation. It does not tell an author how many times to post per day. Another post might add a useful candidate, reach a different audience or appear in a different request. An optimal posting schedule would need evidence about those outcomes.
There is a real cutoff here, but its scope matters: candidates passing through this pipeline. It is too broad to say that every post disappears from X’s recommendations after two days.
The repository also contains Rankall indexing windows for ordinary videos at 2, 4, 7, 14 and 30 days, along with separate evergreen windows. At first glance, the 30-day window seems to contradict the 48-hour filter. They belong to different stages. Having an older item in an index does not exempt it from a later serving filter.
Stage or component
Published setting
What it establishes
Phoenix candidate pipeline age filter
48 hours
Age eligibility on this pipeline
Rankall main ordinary-video windows
2, 4, 7, 14 and 30 days
Dataset/indexing windows, not final feed eligibility
Popular-pool quality calculation
8-hour half-life parameter
Age-normalized view projection, not an eight-hour score-halving rule
The popular-pool clock needs a closer look. Its quality function and default configuration use an eight-hour half-life parameter to project observed views over a 24-hour window. With λ = ln(2) / 8, the calculation is views × (1 − exp(−λ × 24)) / (1 − exp(−λ × max(age_hours, 0.5))).
For the same observed 100 views, that gives quality values of 175 at age eight hours, about 116.67 at sixteen hours, and 100 at twenty-four hours. The quality does not halve every eight hours. The exponential describes the projection’s saturation curve; the post’s observed views can also change. This popular-pool helper separately excludes ages outside its 24-hour window. Neither clock establishes a platform-wide expiry time for impressions.
Reading all three as “how long a post lives” hides the distinctions that make the numbers useful.
Fifty selected is not fifty retrieved
The configuration has two eye-catching constants: 50 for TOP_K_CANDIDATES_TO_SELECT and 35 for RESULT_SIZE.
The selector explains the first one. It sorts a candidate set that has already been assembled, then keeps up to 50. When the video-carousel feature is enabled, it can append extra candidates as well. Fifty is a cap at this selection step, not the number of posts retrieved at the start of a request.
The Phoenix pipeline’s result-size method returns the 35-item constant. The outer For You feed has additional allowances for module slots and frames, while filtering and post-selection work can change what remains available.
Dividing 35 by 50 would therefore give a tidy percentage with no demonstrated meaning. The constants do not describe a fixed funnel, and they certainly do not give each candidate a 70% chance of appearing.
The useful distinction is earlier in the process: eligibility comes before ranking. A candidate removed by a filter never gets to benefit from a high score. To explain why one particular post stopped reaching people, we would need serving or analytics data showing where it dropped out.
The compared action coefficients, VM Ranker multiplier defaults, Home Mixer age and size constants, and local coefficient wiring were unchanged. The newer version exposes named weighted terms and can report the largest prediction-head contributions. Those additions make the score easier to inspect; they do not change the coefficients in these tables.
For this fact audit, the five arithmetic files—inputs.rs, weights.rs, scoring.rs, phoenix_scores.rs and lib.rs—were copied from each pinned revision into isolated Rust crates. The internal proto module declaration was removed, and rustc-hash and md5 supplied as dependencies. The checks include the upstream unit tests and additional cases for mutual-reply eligibility, offset boundaries, diversity multipliers, popular-pool quality and FairShare allocation.
That checks the extracted arithmetic, not the trained model, redacted thresholds, live experiments or complete serving system. The extraction and its limits matter: this is not a claim that the full X repository was built or its production behavior reproduced.
The weights are useful because they make part of X’s ranking choices visible. They show how differently the system values predicted actions, how heavily it weights negative feedback, and how much depends on the path a candidate takes. Turning those observations into advice about a particular account still requires the missing half of the calculation: what the model predicts for its readers.
The next article follows the candidates that never reach this calculation: Before X scores your post, a closer look at the eligibility checks, history filters and candidate budgets that run before this pipeline’s scorers.
Part three goes further upstream: How X finds posts for your feed follows the retrieval sources that bring candidates into the pool in the first place.