A client wants its launch posts on X to send readers to a new landing page. The freelancer running the account has heard two confident claims about this: that X buries posts with links, and that X does not care about links at all. The scenario is hypothetical.
Does X penalise links? In the For You code X publishes, no scoring or filtering step lowers a post’s score because it carries a link. The code scores each viewer’s predicted chance of opening the link, checks every URL in the link’s redirect chain against a reputation verdict, and records how long the visit to the outside page lasts. X’s head of product and its owner both said in 2026 that links are not penalised. What the trained model learned about link posts is not published.
This article is a reading of X’s 2026 open-source For You repository, xai-org/x-algorithm, at commit b220448 (3 November 2026), read on 2026-11-04. No posts were published to test anything.
The published code lists a viewer opening a post’s link among the actions its model predicts, and the default weight on that prediction is positive. The code also sends the post’s has_url flag to the VMRanker service by default. However, the published VMRanker code does not use that flag. The scoring code read has no step that lowers a post’s score because it carries a link. The link’s destination does matter: published labelling rules check each URL a link passes through against a reputation verdict, and a low-quality verdict can keep the post out of recommendations to people who do not follow the account.
Which X code this reads
X publishes a second open-source repository, xai-org/x-algorithm, whose README says it “contains the core code that determines which posts a viewer sees in the For You feed on X”.
GitHub’s metadata records the repository as created on 19 January 2026 and last pushed on 3 November 2026, under the Apache 2.0 licence, with 62 commits on the main branch. The README lists dated “Notable Updates” on 13 August, 14 August, 18 September, 8 October, 13 October and 26 October 2026. The 13 August release “Adds key configuration parameters (including weights used to blend predicted action values into a score for a post)”. The 8 October update says “Ranking predicts time spent much better”. This update is relevant to the click-dwell term discussed below. The 26 October update records the removal of the Brazil election filter. None of these October updates mentions link posts, link clicks or external URLs. On the published values, the README says X runs “cron scripts that set the defaults in this repository’s code to be the primary production values”, and that the aim is for experiments running at “10% or more” of traffic “to be visible in this repository”.
The README also says “a limited set of files” is withheld “to reduce the risk” of gaming, naming “Grox prompts” and “Some botmaker rules”. Every commit on the main branch carries the same message, “Open-source X Recommendation Algorithm”, so the history does not say what changed in each one. The 2023 repository, github.com/twitter/the-algorithm, is a different codebase, read separately in what X’s 2023 recommendation code still says.
What the code scores when a viewer opens a link
The README lists “link” among the click actions that the Phoenix model predicts for each post, alongside post, profile, photo expand, video open and quoted post.
The README says Phoenix “predicts, for each post, how likely the viewer is to take each action on it”, and that the predictions are combined as “Final Score = Σ (weight_i × P(action_i))”. In xai-value-model/scoring.rs, that sum includes the term apply(scores.open_link_score, weights.open_link). The weight is set in home-mixer/params/param.rs as OpenLinkWeight, with a default of 0.2.
The README warns how not to read these numbers. The weights “scale the predicted probabilities of such actions” and “do not scale the raw engagement counts”, and “The weights are a multiple on your own predicted probability of Liking, Reporting, etc, which is substantially driven by your own behavior.” With that warning in mind, the following six defaults from param.rs show where the link term sits:
| Predicted action | Parameter in home-mixer/params/param.rs | Default at the commit read |
|---|---|---|
| Like | FavoriteWeight | 0.66 |
| Click (the README lists “post” among clicks) | ClickWeight | 0.3 |
| Open the link | OpenLinkWeight | 0.2 |
| Profile click | ProfileClickWeight | 0.0 |
| Reply | ReplyWeight | 5.0 |
| Share via copy link | ShareViaCopyLinkWeight | 20.0 |
Source: xai-org/x-algorithm, home-mixer/params/param.rs, commit b220448, read 2026-11-04. Each value multiplies a predicted probability for one viewer. The values are not comparable as counts.
“Share via copy link” copies the X post’s own address. It therefore sends people to X rather than to the client’s site, and the README lists this action under engagement, not clicks. The link term is one of 29 terms in the weighted sum in scoring.rs. A post’s score therefore increases with the model’s predicted chance that a particular viewer will open its link, alongside every other predicted action, and that prediction comes from the viewer’s own history (reasoning from the code).
The repository’s own example diff, docs/BIDIRECTIONAL_BOOST_CHANGE.md, shows that in July 2026 the scorer also carried two switches named OpenLinkWeightInNetworkOnly and OpenLinkWeightLiveBroadcastOnly. Neither name appears in the code at the commit read. The repository does not say when or why they were removed.
Whether a link in the post changes the score
The code calculates a has_url feature for each post in home-mixer/models/content_features.rs. The feature is true when the post’s text carries at least one URL other than attached media.
The feature is included in a debias payload sent to the reranking service. At commit b220448, the default for VMRankerSendDebiasInputs in home-mixer/params/param.rs is true, and home-mixer/scorers/vm_ranker_request.rs sends the payload when that parameter is on and the request is not being served from cached posts. The candidate payload includes has_url among its content features. However, the published vm-ranker/ code does not use has_url. Its user-debias step is disabled by default: in vm-ranker/params.rs, UserDebiasEnabled is false and UserDebiasAlpha is 0.0. Therefore, although the link flag reaches the reranking service by default, the published code does not show it being used to change a post’s score.
In the code read at commit b220448, no scoring or filtering step lowers a post’s score because it carries a link. None of the 35 pre-scoring filters in home-mixer/filters/ reads a URL. That is a reading of the code, and a narrower statement than “X does not penalise links”. Phoenix is trained on viewers’ past behaviour, and what it learned about posts with links lives in trained weights that are not in the repository. If viewers rarely open or engage with a kind of link post, the predictions can reflect that without any rule saying so (reasoning from the README’s description of the model). The withheld labelling rules are a second unknown.
What X has said about a link penalty, next to what the code says
X’s own people have addressed the question twice in 2026, and the code has changed once in a way that matters for reading their answers.
On 20 April 2026, after Techmeme cited a Nieman Lab study that found links reduced engagement, X’s head of product Nikita Bier replied that “there is no code that is deboosting links” and that “To succeed with links, the linked content must bleed into the post” (as reported by TechCrunch, 22 April 2026). On 28 July 2026, replying to a post by Mark Zuckerberg, Bier wrote “Hello Mark, you do not need to put the links in replies anymore.” The next day Paul Graham asked Elon Musk, “You no longer penalize tweets with links in them?”, and Musk answered, “We haven’t for over a year.” (As reported by PPC Land, 30 July 2026, and the Free Press Journal, 29 July 2026.) None of the three posts named a file or a date for the change.
The code’s own record moved between those statements. At the repository’s first commit, aaa167b of 20 January 2026, the action list in phoenix/runners.py named nineteen predicted actions, including click_score, profile_click_score and quoted_click_score, and no action for opening a link. A reading published by PPC Land on 21 January 2026 pointed at that absence and argued that the model would learn to rank link posts lower because link clicks were not among the predicted signals. At commit b220448, the scorer carries open_link_score with its own positive weight, and the README’s 13 August 2026 release note is the entry that added the weights. Whether the production model predicted link opens before August is not something the repository states.
So the two confident claims the freelancer heard both miss the record. “X buries links” is not supported by any published rule, and X’s staff deny it. “X does not care about links” is contradicted by a scorer that predicts link opens and by rules that read where the link goes. What no one outside X can show from the repository is what the trained model does with a given link post for a given viewer, so third-party percentages for a “link penalty” cannot be derived from this code.
Where the link’s destination matters
Three published labelling rules in botmaker-rules/scarecrow/bot/ check the URLs in a post, including each step of its redirection chain, against a reputation verdict.
| Rule (file) | Trigger in the code | Label applied |
|---|---|---|
| 3226, Tweet_Spam_High_Recall_RTF_All_Bad_URL_Sources | On a URL event, the verdict for the post’s redirection chain matches “.*BAD” | SPAM on the post if the verdict is exactly BAD; SPAM_HIGH_RECALL for other matching verdicts |
| 6754, LQ_Tweets_With_LQ_URL_Verdict_At_Mention_To_NonFollower_v2 | Any URL in the chain has the verdict LOW_QUALITY, and the final URL is not GOOD or WHITELIST | SPAM_HIGH_RECALL on the post |
| 20719, PinnedLowQualityOrBadUrl | An account pins a post whose URLs resolve to a BAD or LOW_QUALITY verdict | SPAM_HIGH_RECALL on the account, expiring after one week |
Source: xai-org/x-algorithm, botmaker-rules/scarecrow/bot/, commit b220448, read 2026-11-04.
All three rules exclude test users, a skip list and accounts for which the functions IsHighPageRankUser or IsUserGrayVerified return true. The code does not define either function in the files read.
The labels decide where the post can appear. In visibility-filtering/rules/levels.rs, the rule set for the Home timeline drops posts labelled SPAM. The separate rule set for recommendations also drops posts labelled SPAM_HIGH_RECALL or MALICIOUS_URL, and posts from accounts labelled SPAM_HIGH_RECALL. The README describes the split: some rules drop a post “only when the post is a recommendation from an account the viewer does not follow”, and “The same post is allowed to a follower.”
Take a hypothetical case where the client’s launch link passes through two shorteners before reaching the landing page. The rules check each URL in that chain. Rule 6754 applies if any step carries a LOW_QUALITY verdict, so a low-quality shortener can cause the post to be labelled when the landing page itself has no GOOD or WHITELIST verdict (reasoning from the rule’s condition). The post would still reach the client’s followers and drop out of recommendations to everyone else. The verdict lists themselves, which domains count as BAD, LOW_QUALITY, GOOD or WHITELIST, are not in the repository, so no reader can check a domain against them.
What the code records after the click
The repository’s action list in phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto includes actions related to the time a viewer spends on an external page after opening a link.
Alongside CLIENT_TWEET_OPEN_LINK, the list includes CLIENT_TWEET_EXTERNAL_LINK_LONG_DWELLED, CLIENT_EXTERNAL_LINK_SESSION and duration buckets running from CLIENT_EXTERNAL_LINK_SESSION_LESS_THAN_3_SEC to CLIENT_EXTERNAL_LINK_SESSION_MORE_THAN_60_SEC. The same file defines a field named externalLinkSessionDurationMs. The value model in scoring.rs has no term named for external-link session time. Its link term is open_link_score, and it also weights a click_dwell_time term, whose parameter ContClickDwellTimeWeight defaults to 0.4 in param.rs and which the files read do not define further.
The action list indicates that X’s app records how long a visitor stays on an external page. This gives X a measure of the visit that is separate from the client’s site analytics (reasoning from the action list). Whether the trained model uses those durations is not visible in the repository. Why X’s count of link opens and a site’s count of sessions rarely match is covered in link clicks, landing page views and sessions, and why some of those visits arrive unlabelled is covered in why social traffic shows up as direct.
Driving traffic from X: six checks before a client’s link post goes out
These six questions sort a client’s link post against what the code read implies:
| Question | What the code read implies |
|---|---|
| 1. Would a reader of this post want to open the link? | The scored term is each viewer’s predicted chance of opening the link. |
| 2. How many redirects does the link pass through? | The labelling rules read every URL in the redirection chain. |
| 3. Could any domain in the chain carry a low-quality verdict? | The verdict lists are not published. Fewer hops means fewer URLs for the rules to read. |
| 4. Who is the post meant to reach? | The SPAM_HIGH_RECALL drop applies to recommendations. Followers are still shown the post. |
| 5. Is the post published through X’s API? | The code read says nothing about this. X charges separately for link posts published through its API. |
| 6. How will the visit be counted? | X’s app records its own visit duration. The client’s site analytics count the visit separately. |
The For You code X published in 2026 does not contain a rule that lowers a post’s score simply because it carries a link. Although the link flag is sent to the VMRanker service by default, the published code does not show the service using it. The ranking model scores the chance that a viewer opens the link, while published rules check where the link goes and the app records how long the visit lasts. Whether a client posts links at all is the client’s decision. How the link’s card looks before posting is a separate check, covered in the article on how X documents card previews and the Card Validator.
What could not be confirmed
This reading cannot settle eight points:
- What the trained Phoenix model learned about posts with links. The trained weights are not in the repository.
- Which domains carry each URL verdict. The lists are not published.
- What the withheld botmaker rules do.
- Whether the defaults in param.rs apply to every account. The README says they are “primary production values” and that experiments run on part of the traffic.
- When the two open-link switches left the scorer, and when open_link_score entered it. Every commit carries the same message.
- Whether the external-link session actions are used in training.
- How X defines a link click in its analytics. On 26 October 2026, X’s Help page for the post activity dashboard redirected to an in-app analytics page that prompted the reader to upgrade.
- Whether any of this changes reach for a real post. No posts were published to test it.
FAQ
Does X penalise posts with links?
The For You code X published in 2026 has no scoring or filtering step that lowers a post’s score because it carries a link. Although the code sends the post’s has_url flag to the VMRanker service by default, the published vm-ranker code does not use that flag. X’s head of product said in April 2026 that “there is no code that is deboosting links”, and Elon Musk said in July 2026 that X had not penalised link posts “for over a year”. What the trained model learned about link posts is not visible, and published rules can keep a post out of recommendations if its link’s destination has a low-quality verdict.
Can you post links on X (Twitter)?
Yes. Nothing in the code read removes a post for carrying a link, and X’s staff have said links no longer need to go in a reply. Two separate things do apply to a link post. If the post is published through X’s API, X charges a higher per-post price for a post containing a URL, which is covered in the article linked in the checklist above. And if any URL in the link’s redirect chain carries a BAD or LOW_QUALITY verdict, published rules can label the post and keep it out of recommendations to non-followers.
Does X count link clicks when ranking posts?
Yes, as a predicted action. The code scores each viewer’s predicted chance of opening the link, with a default weight of 0.2 in the commit reviewed. The README warns that weights multiply predicted probabilities, not counts. At the repository’s first commit in January 2026, no link-open action was in the published prediction list; at the commit read, it is.
Do link shorteners affect reach on X?
The published rules check every URL in a link’s redirect chain against a reputation verdict. One step with a low-quality verdict can label the post and keep it out of recommendations to non-followers, while followers can still see it.
Does putting the link in a reply get around this?
No, and X’s head of product said in July 2026 that it is no longer needed. The README lists OONRetweetReplyFilter among the pre-scoring filters and says it removes replies and reposts from accounts the viewer does not follow. The filter code at commit b220448 includes an exception for certain replies retrieved through Phoenix, controlled by EnablePhoenixOonReplies, whose default is false. Therefore, a reply containing a link is not guaranteed to appear in For You recommendations to non-followers (reasoning from the README and filter code). The filter does not check whether a reply contains a link; it checks whether the reply is from an account the viewer does not follow.
Is this the same code X open-sourced in 2023?
No. The 2023 code is github.com/twitter/the-algorithm. This article examines xai-org/x-algorithm, created in January 2026 and described in its README as the core code for X’s For You feed.
Sources
Repository files at commit b220448766ab4ee4c83d58a67d51f0cb5bda86c2 unless stated, read on 2026-11-04.
- GitHub API, xai-org/x-algorithm repository metadata and commits, api.github.com, read 2026-11-04.
- xai-org/x-algorithm, README.md, github.com, read 2026-11-04.
- xai-org/x-algorithm, home-mixer/params/param.rs, github.com, read 2026-11-04.
- xai-org/x-algorithm, xai-value-model/scoring.rs, github.com, read 2026-11-04.
- xai-org/x-algorithm, home-mixer/models/content_features.rs, github.com, read 2026-11-04.
- xai-org/x-algorithm, home-mixer/scorers/vm_ranker_debias_payload.rs and vm_ranker_request.rs, github.com, read 2026-11-04.
- xai-org/x-algorithm, vm-ranker/params.rs, github.com, read 2026-11-04.
- xai-org/x-algorithm, botmaker-rules/scarecrow/bot/ (rules 3226, 6754, 20719), github.com, read 2026-11-04.
- xai-org/x-algorithm, visibility-filtering/rules/levels.rs, github.com, read 2026-11-04.
- xai-org/x-algorithm, phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto, github.com, read 2026-11-04.
- xai-org/x-algorithm, docs/BIDIRECTIONAL_BOOST_CHANGE.md, github.com, read 2026-11-04.
- xai-org/x-algorithm, phoenix/runners.py at the first commit, aaa167b (20 January 2026), github.com, read 2026-11-04.
- TechCrunch, “X makes it more expensive to post links through its API”, 22 April 2026, techcrunch.com, read 2026-11-04.
- PPC Land, “X drops year-old link penalty, Musk tells Zuckerberg on platform”, 30 July 2026, ppc.land, read 2026-11-04.
- Free Press Journal, “X product head Nikita Bier confirms link penalty removed over a year ago”, 29 July 2026, freepressjournal.in, read 2026-11-04.
- PPC Land, “How X’s algorithm silently kills your links without explicitly penalizing them”, 21 January 2026, ppc.land, read 2026-11-04.



