Skip to content

Event filtering

A client controls Dispatch traffic with Lazy Request subscriptions and the Identify ignored_events list. Guild availability, permissions, and sharding also restrict delivery.

TEBHOS has no intents field, no intent close code, and no privileged-intent approval. A client ported from a protocol that uses intents replaces its intent mask with the mechanisms on this page.

The gates

TEBHOS evaluates a guild-scoped Dispatch against these gates in order.

Gate Name What it decides
1 Guild availability Whether the guild dispatches anything except Guild Update
2 Permission and visibility Which sessions may see the event at all
3 Guild subscription state Whether a passive session in a guild with more than 250 members still receives it, as Active and passive guilds lists
4 Session-level filters Whether the shard filter, and then the ignored_events list, drops it inside the session

A guild that an instance operator has marked unavailable (the UNAVAILABLE_FOR_EVERYONE or UNAVAILABLE_FOR_EVERYONE_BUT_STAFF guild feature) fails gate 1. With UNAVAILABLE_FOR_EVERYONE_BUT_STAFF, a staff session receives the guild's full state when it connects and every other session receives an unavailable stub. Gate 1 has no staff exemption, so a staff session also receives nothing but Guild Update while the feature is set.

An account-scoped Dispatch skips gates 1 through 3 and is subject only to gate 4. Direct message traffic, relationship changes, account record changes, and calls arrive that way.

Permission and visibility

The guild resolves each event to one of these recipient sets.

Event class Events Recipients
Channel-scoped Channel Create, Channel Update, Channel Delete, Message Create, Message Delete Bulk, Typing Start, Channel Pins Update, Webhooks Update Sessions that can view the channel
Message-access filtered Message Update, Message Delete, Message Reaction Add, Message Reaction Remove, Message Reaction Remove All, Message Reaction Remove Emoji Sessions that can view the channel and can access that message
Invite Invite Create, Invite Delete Sessions holding MANAGE_CHANNELS on the invite's channel
Audit log Guild Audit Log Entry Create Sessions holding VIEW_AUDIT_LOG in the guild
Guild-wide Everything else Every session connected to the guild

Channel Delete is filtered against the guild state as it was before the deletion, so the sessions that could see the channel are the ones that learn it is gone. Every set excludes a session that has not yet received the guild's initial state.

Channel visibility is VIEW_CHANNEL on the channel, plus extensions. A category is visible when at least one of its children is visible. A user with a live voice connection in a channel keeps virtual access to it when the channel would otherwise stop being visible, for example after a role or overwrite change removes VIEW_CHANNEL, or after a move into a channel the user cannot view. Virtual access applies to every session of that user and ends with the voice connection.

Message access is READ_MESSAGE_HISTORY on the channel. Without it a session still receives events for messages newer than the guild's message_history_cutoff. A guild that sets no cutoff offers no such fallback.

Channel Update Bulk contains only the channels the recipient can view. If none are visible, no event is sent.

Voice State Update takes its own path. The guild sends it straight to the sessions that can view the channel the voice state names, or, when the state names no channel, the channel the user just left.

Some events are fanned out by the API

For a few private or restricted cases the API picks the recipients itself before handing the event to the Gateway. A message, pin, or typing event in a guild channel that is marked private is sent to each member who holds VIEW_CHANNEL there, and TEBHOS client events such as PERMISSION_UPDATED go to the users the API selected. Those events are account-scoped from the Gateway's point of view and pass only gate 4.

Excluding the acting session

Message Reaction Add and Message Reaction Remove accept a session_id query parameter on the originating HTTP request. In a guild channel TEBHOS excludes that session from the resulting Dispatch and strips the field from the payload. Every other mutation delivers its Dispatch to the acting session like any other eligible session.

Active and passive guilds

A user session is passive in every guild until Lazy Request marks that guild active: true, or until Identify names it as initial_guild_id. A bot session is never passive. A guild with 250 members or fewer is active for every session, so the rule below applies only to a passive user session in a guild with more than 250 members.

Such a session receives exactly this set:

Every other Dispatch the guild produces is suppressed, including Message Update, Message Delete, Message Delete Bulk, every reaction event, Invite Create and Invite Delete, Channel Pins Update, Webhooks Update, Guild Member Add, Guild Role Create and Guild Role Delete, Guild Ban Add and Guild Ban Remove, and Guild Emojis Update and Guild Stickers Update.

Voice State Update never reaches this gate, so a passive session in a large guild still receives it for every channel it can view.

A message mentions the session's user when the payload names that user in mentions, names one of that user's roles in mention_roles, sets mention_here, or sets mention_everyone. The guild reads only the first 100 entries of mention_roles.

Every 30 seconds a passive session receives Passive Updates with the changed per-channel last_message_id values and the changed voice states for the channels it can view, so it keeps unread state and voice rosters correct without the suppressed message events. A cycle that finds nothing changed sends nothing.

Typing is decided separately

Typing Start does not follow the rule above. When the session set typing for the guild through Lazy Request, that value alone decides delivery. Without an override the event follows the active state, so a passive session in a large guild does not receive it. The override applies to every session, including a bot session.

Member lists

Guild Member List Update has its own subscription. A session receives it only for a channel it named in member_list_channels, and only while it can view that channel and holds VIEW_CHANNEL_MEMBERS on it. One session holds at most one member list subscription per guild.

Presence subscriptions

A guild dispatches Presence Update only to a session that named the subject in the members array of a Lazy Request, that can view at least one channel the subject can view, and that does not belong to the subject. Friends and group direct message recipients receive presences through the account path.

A session that no longer shares a viewable channel with the subject is dropped from that subject's subscriber set, so a client that regains access MUST resend members. Each members array replaces the session's previous subscription set for that guild.

A bot session holds no friend or group direct message presence subscriptions, so a bot receives presences through this guild path alone.

Ignored events

Identify accepts ignored_events, an array of up to 256 Dispatch event names. TEBHOS upper-cases and deduplicates the names. An absent field and a JSON null both mean the empty list. Any other value that is not an array of strings, and any array of more than 256 entries, closes the connection with 4002 and reason Invalid identify payload. A Dispatch whose t appears in the list is dropped and never enters the replay buffer.

{
  "op": 2,
  "d": {
    "token": "...",
    "properties": {"os": "Linux", "browser": "my-bot", "device": "my-bot"},
    "ignored_events": ["TYPING_START", "PRESENCE_UPDATE", "PROFILE_UPDATE"]
  }
}

Message Create is the one exception. TEBHOS delivers it even when MESSAGE_CREATE is ignored if the message mentions the session's user, using the same test as the passive filter above: a direct mention, a mention of one of the user's roles, mention_here, or mention_everyone.

A suppressed Dispatch consumes no sequence number, so a client MUST NOT expect a gap where the list dropped one.

The list is fixed for the lifetime of the session. Changing it requires a new Identify. The list also applies to the TEBHOS client events, so a bot can drop them by name.

The shard filter

A session that identified with a shard pair whose shard_id is not 0 drops every Dispatch that does not name a guild. A Dispatch names a guild through a non-empty top-level guild_id, or through a non-empty id on a Guild Create, Guild Update, Guild Delete, or Guild Sync payload.

Account-level traffic, direct message traffic, relationship changes, and calls therefore never reach a session on a shard other than 0. Rate Limited, Guild Counts Update, and Channel Member Counts Update carry no top-level guild_id either, so a non-zero shard does not receive them. Send those commands on shard 0.

Sessions on shard 0, and sessions that identified without a shard pair, filter nothing at this gate. The Gateway still filters guilds by shard at Identify, as Sharding describes, so a shard 0 session is connected only to the guilds its shard owns.

What a bot should send

A bot session is never passive, so active changes nothing for it and a typical bot needs no Lazy Request at all. It shapes traffic with ignored_events and pulls members with Request Guild Members.

A bot that does not process typing or reactions saves the most by ignoring TYPING_START, MESSAGE_REACTION_ADD, and MESSAGE_REACTION_REMOVE. Ignoring the TEBHOS client events it does not use, such as PROFILE_UPDATE, SERVER_UPDATED, and NOTIFICATION_UPDATE, removes more noise. Ignoring PRESENCE_UPDATE saves a bot nothing, because a bot receives no presence until it subscribes to one.