X visibility labels: rules, audiences and feed eligibility | Gyo
How visibility labels affect X recommendations
A visibility label is only one input. Follow the rules, viewer context and caller decisions that determine where a post can appear.
Gyo
A post can be available to its author and followers while facing different rules in recommendations to strangers. That difference deserves a closer look than a single word such as “limited.”
X’s published visibility code separates facts and labels from the rules that consume them, and separates the resulting decision from the action a caller takes. The viewer, surface, relationships and available data all help determine the outcome. A label name alone does not describe the reach of an account.
The previous article reached the visibility checks after ranking. This one opens that part of the process: how the caller selects a policy, how rules use labels, and why two requests for the same post can produce different answers.
Start with the question the caller asks
In the recommendation pipeline, VFCandidateHydrator gathers IDs requiring visibility results. It puts in-network candidates into a request using TimelineHome; other candidates use TimelineHomeRecommendations.
It also collects related posts. Ancestors and quoted posts go into the recommendation-level request, while a repost’s original ID goes into the Home-level request. Each batch is deduplicated before the two requests run concurrently. Viewer identity and context accompany the calls.
There is already more information here than “is this post allowed?” The caller is asking about posts for a particular viewer under particular safety levels, with related material included. A result obtained for another viewer or level is not automatically the answer to this request.
The hydrator can choose between two visibility clients according to configuration. This article follows the published Rust policy implementation and its Home Mixer caller; it does not assume that every deployment always uses the same client or switches.
Home and recommendations use different rule lists
The policy definitions make the distinction concrete. Both TIMELINE_HOME and TIMELINE_HOME_RECOMMENDATIONS include checks around author state, viewer blocks and mutes, takedowns, age gating, exclusive content and media treatment.
The recommendation policy adds groups of author-label and content rules. One of those groups, OON_AUTHOR_LABEL_DROPS, includes spam, compromised-account, read-only, impersonation, abuse and do-not-amplify rules. That group is not in the ordinary Home policy’s author-rule list.
This helps explain how a post can remain available in one context without being eligible in another. It does not establish which rule affected a particular account. First we would need the actual labels, relationships, policy and evaluation result.
FAQ
Does a visibility label always hide a post everywhere?
No. The examined rules depend on their policy registration, audience and conditions. A label can affect recommendations to some viewers while a post remains available in another context. A label name alone does not establish an account-wide outcome.
Why can followers see a post that strangers do not receive?
The Home Mixer caller uses TimelineHome for in-network candidates and TimelineHomeRecommendations for other candidates. The published policies have different rule lists and individual audience conditions. A specific case still requires its actual evaluation result.
Can an allowed post be removed because of a quote or ancestor?
The caller separately checks related-post results. A drop-worthy result for a quote, repost original or qualifying ancestor can set an ancillary-removal flag. A later filter consumes that flag, and tombstone ancestors have an explicit exception.
Does an empty visibility reason prove there is no restriction?
No. Successful evaluations, missing map entries and lookup errors are different states. The implementation also distinguishes complete, partial and failed evaluations. A reason field alone does not reconstruct the full decision.
The contrast is also narrower than “followers can see anything.” Shared checks still exist. Following an author does not erase every rule in the Home policy, and different rules have their own audience conditions.
A label is an input to a rule
The author model keeps account-state features, profile facts and a set of author labels separately. Being protected or suspended is represented differently from holding labels such as SpamHighRecall or DoNotAmplify.
Post safety labels have their own map representation. The implementation can record label presence, selected source strings and whether a label was assigned through a tool action. It does not turn every label directly into a common numeric penalty.
The next step is the consuming rule. A rule specifies an audience, a condition and an action. The audience definitions distinguish everyone, non-authors, non-followers and the author. The rule also has to belong to the selected policy.
Take DO_NOT_AMPLIFY_USER_LABEL_DROP_UNSPECIFIED. Its condition checks the author label, its audience is non-followers, and its action is a drop. Combined with its registration in the recommendation policy, that is a specific mechanism with a specific scope.
The nearby spam-label rule uses a different audience: non-authors. We should not replace both implementations with the same sentence about followers being exempt.
An enum name can tell us what category a rule reads. It cannot tell us why a real account received that category, how accurate the assignment was, or how long it remains. Those are questions about the producing system and actual records, not facts supplied by the consuming rule.
Relationships and viewer settings change the context
Some differences have nothing to do with a classifier assigning a label. The author rules include suspended and deactivated authors, protected accounts, and viewer block and mute relationships. Their conditions and audiences differ.
Other rules read the viewer’s age or sensitive-content settings. For example, the underage-viewer rules combine viewer status with particular media, flag or text/card conditions. The same label need not produce an identical result for every viewer.
The takedown rules check whether a takedown applies in the request country. This source shows how regional scope enters the evaluation. It does not establish the legal basis, validity or geographic scope of any particular real-world request.
So when someone says, “I can open the post, therefore it cannot be restricted,” the useful follow-up is: open it as whom, from which surface and under what request context? Availability in one request is evidence about that request, not a complete survey of all others.
The engine combines decisions rather than adding label penalties
The policy constructor validates rules, orders them by action severity and combines their data requirements. That is different from the registration-order behavior of the candidate filters in part two. Two arrays in the repository do not necessarily share the same execution semantics.
During evaluation, the engine folds rule results into a decision. Its folding code tracks terminal outcomes and supports a tracing observer that can continue recording after a terminal decision. Normal evaluation and a total diagnostic trace can therefore show different amounts of work without implying different policies.
The verdict model has two broad forms: withheld, or shown with optional notice, media restriction and engagement restriction. “Shown” is not synonymous with “shown with no treatment.” A warning or a limitation can coexist with that broad verdict.
The limited-action types include operations such as replying, reposting, liking, copying a link and autoplay. Listing an action type does not prove that it is limited on a given post. It tells us the vocabulary available to decisions that actually impose a restriction.
This layer is not the coefficient calculation from part one. It can determine whether and how content is available rather than merely shaving a little off a ranking score.
The caller still decides what to do with the result
Back in Home Mixer, the visibility hydrator stores an action and an available reason on the candidate. The later VFFilter decides whether that action removes it from this candidate list.
Action attached to the candidate
What this Home Mixer filter does
Drop, Tombstone, NotEvaluated
Removes the candidate
Allow, Interstitial, Avoid, Downrank
Does not remove it in this filter
No attached action
Does not remove it in this filter
The table describes one consumer. It should not be used to conclude that an interstitial, an avoid treatment or a downrank action has no effect anywhere else. It only says that this function does not drop those candidates or directly implement all of their downstream treatment.
Conversely, a high predicted engagement score does not make a Drop action disappear. The two decisions come from different parts of the path. That is why “improve the hook” cannot be assumed to fix every loss of recommendation eligibility.
A quote or ancestor can change the outcome
The request includes related IDs for a reason. The hydrator’s should_drop_ancillary helper checks visibility results for ancestors, the quoted post and a repost’s original. A related result carrying a drop-worthy action can set drop_ancillary_posts.
For ancestors, there is an exception: IDs already recorded as tombstone ancestors are skipped by this helper. We should not flatten that into a rule that every unavailable ancestor always deletes every reply.
Consider an invented candidate whose own result is Allow, but whose quoted post has a Drop result. The helper can mark the candidate for ancillary removal; the subsequent AncillaryVFFilter removes candidates carrying that flag. Inspecting only the candidate’s primary action would miss the reason.
That example follows the helper’s branches. It does not mean every quote of a restricted post always fails, regardless of request, returned results or other context. Those are precisely the inputs we would need to inspect.
Missing evidence is not the same as a clean result
Data retrieval can fail. The visibility engine explicitly carries that distinction through evaluation variants for complete, partial, not-found, deleted and failed cases. The evaluation finish step records defaults relied upon and distinguishes partial results when required hydration has failed.
In the Home Mixer hydrator, a primary lookup error becomes an error update record. A successful response with an action, a missing entry in the result map and a failed lookup are not the same input. The small visibility_fields helper returns no action and no reason when it has no successful result, but that helper alone is not the entire error-handling path.
This is a reason to retain provenance when investigating a decision. An empty reason field does not, on its own, prove that every policy check passed. Nor does a partial evaluation establish that a content violation occurred. We need to know what was evaluated and what data was missing.
What a useful explanation would show
The public Explainer types take a post, optional viewer, country, client and requested routes. Their output can include outcomes per level and provenance. The judgement structure tracks items such as the deciding rule, failed hydration and defaults.
That is a useful shape for evidence: the same post, under a specified viewer and route, with a recorded decision. A bare label screenshot supplies much less context.
There is a separate Home Mixer trace adapter for pipeline counts, enabled components and score information. A pipeline trace can help locate a stage; a policy explanation can help explain a visibility decision. Their presence in the repository does not grant a public reader access to arbitrary private request traces or reconstruct a historical case from a current evaluation.
For an author, the practical question becomes more precise: is the evidence a label assignment, a policy verdict, a pipeline removal, or just lower impressions? Those observations may be related, but they are not interchangeable.
Where this leaves the series
The first five parts followed content from retrieval through prediction and ranking to feed assembly. Visibility policy adds another dimension: distribution can vary by audience, relationship, surface and context even while the post itself stays unchanged.
That gives us a better way to discuss limited reach without making every problem a hidden global account score. Some mechanisms really do remove content from particular requests. Others change presentation or engagement options. A label can feed into either kind of decision, depending on the rule that uses it.
The next article looks at a different source of uncertainty: what the system does when it has little history for the reader, or little exposure data for a candidate. A cold-start adjustment still operates inside the wider retrieval and visibility path; it does not override the whole system.
Source and verification notes
Source-checked on November 3, 2026, against revision b220448, then upstream HEAD. This article follows the Rust visibility policy, selected rules and the Home Mixer caller. It is not an inventory of every policy, label-producing system, deployment override or client treatment.
The Home/recommendation rule-list distinction was checked structurally against the pinned definitions. The quoted-post and tombstone-ancestor examples were checked using isolated extracts of the published caller helpers. No private account labels, historical serving traces or production enforcement outcomes were inspected.