Back to Blog

Twitter Filter Rule Reference: Fields and Operators

Twitter Filter uses a simple expression language to match tweets in your timeline. Each rule has a condition (expression) and an action (mark, hide, or block). This page is the complete reference for writing rules.

Actions#

ActionEffect
markYellow border + reduced opacity, with a label showing the matched rule
hideCompletely hides the tweet from the timeline
blockHides the tweet immediately and blocks the account after a configurable delay (default 3s). A toast notification appears with an Undo button to cancel before the block executes

Warning: The block action will block real accounts on your behalf. Use with caution. The delay + undo mechanism helps prevent accidental blocking.

Available Fields#

User fields#

FieldTypeDescription
user.idstring / nullNumeric user ID
user.namestringDisplay name
user.screen_namestringUsername / handle (without @)
user.descriptionstring / nullBio
user.locationstring / nullUser-defined location (free text, not GPS — users can write anything here)
user.urlstring / nullProfile URL
user.avatarstring / nullAvatar image URL
user.default_profilebooleanHas default profile (never customized banner)
user.default_profile_imagebooleanHas default profile image (egg avatar)
user.blue_verifiedbooleanPaid blue checkmark
user.verifiedbooleanGray/gold verification badge
user.verified_typestring / nulle.g. “Business”, “Government”
user.followersnumber / nullFollower count
user.followingnumber / nullFollowing count
user.statuses_countnumber / nullTotal tweets posted
user.created_atstring / nullAccount creation date (ISO format)

Relationship & privacy fields#

FieldTypeDescription
user.protectedbooleanAccount is protected (locked)
user.is_followingbooleanYou follow this user
user.followed_bybooleanThis user follows you
user.blockingbooleanYou are blocking this user
user.blocked_bybooleanThis user is blocking you
user.mutingbooleanYou are muting this user

Tweet fields#

FieldTypeDescription
tweet.textstringTweet text content
tweet.is_replybooleanIs a reply
tweet.has_linksbooleanContains links
tweet.has_mediabooleanContains images/videos
tweet.langstring / nullBCP 47 language code (e.g. "en", "ja", "zh"). Special values: "und" (undetermined), "zxx" (no linguistic content)
tweet.is_promotedbooleanWhether this is a promoted (ad) tweet

Community signal fields#

Resolved asynchronously from X’s own “About this account” data and shared across users via a community cache — unlike every field above, these aren’t available synchronously from the timeline response. A rule using one of these fields simply doesn’t match a given tweet until resolution completes (which can take a moment the first time you encounter an account), and block cannot be used with a condition that references them — this data can be wrong or spoofed (e.g. via VPN), so pair it with hide and combine it with another structural condition rather than using it standalone. The first time you save, edit, or subscribe to a rule using one of these fields, a one-time dialog explains what gets shared.

FieldTypeDescription
user.based_instring / nullX’s inferred current location for the account — a country or region/continent name
user.based_in_granularity"country" / "region" / nullWhether based_in resolved to a specific country or only a broader region
user.likely_proxyboolean / nullX’s own suspicion that the account is using a proxy/VPN — weak, noisy signal; never use standalone
user.connected_regionstring / nullApp Store/Play payment region — more stable than based_in, harder to spoof
user.connected_platformstring / nullWhich store/platform connected_region came from, e.g. "App Store", "Android App", "Web"

null is a normal, legitimate value here (not an error) — it means the account resolved successfully but genuinely has no value for that field, which is common for political/diplomatic/major-org accounts (based_in) or accounts connected via the web rather than an app (connected_region/connected_platform). It works with ==/!= like any other value.

Operators#

OperatorDescription
==, !=Equality / inequality
<, >, <=, >=Numeric comparison
&&, ||Logical AND / OR
!Logical NOT
+, -, *, /Arithmetic
containsCase-insensitive substring match
matchesRegex match (Unicode mode — \p{...} property escapes supported, e.g. \p{Extended_Pictographic})

Built-in Functions#

FunctionDescription
is_null(val)Check if value is null/undefined
len(val)String length (returns 0 for non-strings)
days_since(date)Days elapsed since an ISO date string (returns Infinity for invalid dates)
lower(val)Convert string to lowercase

Null Handling#

Some fields can be null (e.g. user.followers, user.description). Here’s how null behaves:

  • Arithmetic (+, -, *, /): if either side is null, result is null
  • Comparison (<, >, <=, >=): if either side is null, result is false
  • Equality (==, !=): works normally — user.description == null returns true when bio is empty
  • String ops (contains, matches): return false if either side is not a string
  • Use is_null(val) to explicitly check for null values

Community signal fields are different: an unresolved community signal field isn’t null — the whole rule is skipped for that tweet until resolution completes (no match, no error, just tried again once the data arrives). null only shows up for these fields after resolution succeeds, meaning the account genuinely has no value there — at that point it behaves like any other nullable field above.

Examples#

Keyword filtering#

Filter tweets or bios containing specific keywords:

tweet.text contains 'crypto' || user.description contains 'crypto'

Suspicious accounts#

Low follower ratio combined with a new account:

user.followers / user.following < 0.01 && days_since(user.created_at) < 30

Bot-like username pattern#

Usernames that are letters followed by 8 or more digits (e.g. sarah83927482):

user.screen_name matches '^[a-zA-Z]+\d{8,}$'

Default or missing avatar#

Catch accounts that never set a profile picture:

user.default_profile_image == true

Hide non-English tweets#

tweet.lang != 'en'

Hide blocked users that still appear in timeline#

user.blocking == true

Hide promoted (ad) tweets#

tweet.is_promoted == true

Hide tweets from users you’re muting#

In case muted tweets leak through:

user.muting == true

Low-follower accounts flagged as likely proxy/VPN users#

Combine a weak community signal with a structural one rather than using it standalone (action hide, never block):

user.likely_proxy == true && user.followers < 20

Mark protected accounts that don’t follow you#

user.protected == true && user.followed_by == false

Only show tweets from accounts you follow#

Hide everything from accounts you don’t follow:

user.is_following == false

Emoji-only replies#

Catch replies that contain only emoji and whitespace (commonly used by spam bots):

tweet.is_reply && tweet.text matches '^(@\w+\s+)*[\p{Emoji}\p{Emoji_Component}\s]+$' && len(tweet.text) > 7 && user.followers < 50

Complex: new unverified account with spam keywords#

Combine multiple conditions:

days_since(user.created_at) < 7
  && user.blue_verified == false
  && (tweet.text contains 'free' && tweet.text contains 'mint')

Tips#

  • Whitelist: Your own tweets and tweets from users you follow are always skipped — they will never be matched by any rule.
  • Rule priority: When multiple rules match the same tweet, the most severe action wins (block > hide > mark).
  • Screen name lists: Each rule can also have a list of usernames that it matches against directly, without needing a condition expression.
  • Testing rules: Set the action to mark first — matched tweets get a yellow border so you can see exactly what’s being caught. Once you’re happy with the results, switch to hide or block.