> For the complete documentation index, see [llms.txt](https://docs.nighty.one/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nighty.one/custom-features-tab/filters.md).

# Filters

Filters are the **first layer** of narrowing a feature down to exactly what you want.

An event like "New Message" fires for *every* message your account can see - every server, every channel, every person, every bot. That's almost never what you want. Filters are how you say **"only these places, only these people."**

{% hint style="info" %}
![](/files/xgOAU0tFZjfoeLhoHA3U)

**Think of a filter as a bouncer at the door.** Before your feature does anything at all, the bouncer looks at what just happened and decides whether it even gets to come in.
{% endhint %}

## Filters run first, and they're all-or-nothing

When an event arrives, filters are checked **before anything else** - before your conditions, and long before any action runs.

Two rules to remember:

{% hint style="warning" %}
**1. Every filter must pass.** If you add five filters, all five have to agree. There's no "or" between them - one "no" and the feature stops right there.

**2. If a filter blocks, nothing happens at all.** No actions, and it doesn't count against your [execution limits](/custom-features-tab/execution-limits.md). The event is simply dropped.
{% endhint %}

That second point is why filters are the *right* place to rule things out. A filter is the cheapest possible "no."

## Filters only work on the event's own parameters

Filters can only be applied to the **built-in parameters that come with your event** - the ones from [Events and Parameters Page](/custom-features-tab/understanding-events-and-parameters.md), like `user`, `channel`, `guild`, `member`, `message`, `role`.

They **cannot** use parameters you create yourself with **"Add a parameter."**

{% hint style="info" %}
If you need to narrow something down using a parameter you added yourself, that belongs in **conditions**, not filters. Conditions run later, once everything is loaded.
{% endhint %}

## Whitelists and blacklists

This is what most people use filters for. Every major parameter supports two filters:

| Filter           | What it does                                                |
| ---------------- | ----------------------------------------------------------- |
| **ID Whitelist** | *Only* allows the IDs you list. Everything else is blocked. |
| **ID Blacklist** | Blocks the IDs you list. Everything else is allowed.        |

Pick whichever makes a shorter list. Want it to work in 2 servers out of 40? Use a whitelist. Want it everywhere except 2 servers? Use a blacklist.

## ⚠️ Always add "Ignore self" - the infinite loop trap

**This is the single most important thing on this page.**

Here's how people break things:

You build a feature: *"when a new message appears, reply to it."*

{% stepper %}
{% step %}

## Someone sends a message

Your feature replies.
{% endstep %}

{% step %}

## Your reply is also a new message

The New Message event fires again - for your own reply.
{% endstep %}

{% step %}

## Your feature replies to its own reply

Go to step 2. Forever.
{% endstep %}
{% endstepper %}

That's an **infinite loop**, and your account is the one sending all those messages. It's the fastest way to get rate-limited.

**The fix takes five seconds:** add the **Ignore self** filter on the `user` parameter. Now your feature skips anything you sent yourself, and the loop can never start.

{% hint style="success" %}
**Every feature that sends, replies, edits, or reacts should have "Ignore self" on it.** Add it first, before you build anything else. Make it a habit.
{% endhint %}

### What about "Only self"?

Some features are meant to react to **you** - you type a keyword and something happens. Those use **Only self** instead, which allows *only* your own messages and blocks everyone else.

But be careful, because **"Only self" does not protect you from the loop** - it does the opposite. It means your own messages are the ones that trigger the feature, which is exactly the situation the loop needs.

If you're using **Only self**, the thing that has to break the loop is your **conditions**: the feature must only fire on something your own output can't match.

{% hint style="success" %}
**Safe:** trigger when the message is exactly `!ping`, reply with `pong`. `pong` isn't `!ping`, so the loop stops after one step.
{% endhint %}

{% hint style="danger" %}
**Dangerous:** trigger when the message contains `hello`, reply with `hello there`. Your reply contains `hello`, so it triggers itself - loop.
{% endhint %}

{% hint style="warning" %}
**The short version:** every feature gets either **Ignore self** or **Only self**. "Ignore self" ends the loop by itself. "Only self" means *you* are responsible for making sure your feature can't re-trigger on its own output.
{% endhint %}

## What happens when a parameter isn't there

From [Events and Parameters Page](/custom-features-tab/understanding-events-and-parameters.md): not every parameter exists on every event. A DM has no `guild` and no `member`.

So what does a filter do when the thing it's supposed to check isn't there? It follows one simple, consistent rule:

{% hint style="info" %}
**"Only" and "Whitelist" filters block. "Ignore" and "Blacklist" filters allow.**
{% endhint %}

The logic is that each filter fails in its *safe* direction. A whitelist exists to be restrictive, so when it can't confirm a match it says no. A blacklist exists to remove specific things, so when there's nothing to remove it says yes.

Written out:

| Filter                                                      | Parameter missing → |
| ----------------------------------------------------------- | ------------------- |
| Only self / Only bots / Only friends                        | ❌ Blocks            |
| Only in servers / Only in DMs                               | ❌ Blocks            |
| ID Whitelist *(any parameter)*                              | ❌ Blocks            |
| Ignore self / Ignore bots / Ignore friends / Ignore blocked | ✅ Allows            |
| ID Blacklist *(any parameter)*                              | ✅ Allows            |

This matters in practice. A **server ID whitelist** blocks DMs - there's no server to match, so nothing gets through. A **server ID blacklist** allows DMs - there's no server to block. Same list of IDs, opposite result in DMs.

{% hint style="info" %}
If you want a feature to work in servers *and* DMs, don't reach for a server whitelist. Use a channel whitelist instead - channel IDs exist everywhere, including DMs and group DMs.

You can also use the "Channel Type" condition.
{% endhint %}

## Combinations that work well

<table><thead><tr><th width="254">Goal</th><th>Filters to use</th></tr></thead><tbody><tr><td>Reply to people without looping</td><td><strong>Ignore self</strong> + <strong>Ignore bots</strong></td></tr><tr><td>Only work in one channel</td><td><strong>Ignore self</strong> + channel <strong>ID Whitelist</strong></td></tr><tr><td>Only work in your own servers</td><td><strong>Ignore self</strong> + server <strong>ID Whitelist</strong></td></tr><tr><td>Personal command you type yourself</td><td><strong>Only self</strong> <em>(plus a condition your output can't match) + Global execution limit (1 per 5 seconds)</em></td></tr><tr><td>Ignore one annoying person everywhere</td><td>user <strong>ID Blacklist</strong></td></tr><tr><td>React to bot announcements only</td><td><strong>Only bots</strong> + channel <strong>ID Whitelist</strong></td></tr><tr><td>DM auto-reply</td><td><strong>Ignore self</strong> + <strong>Ignore bots</strong> + <strong>Only in DMs</strong></td></tr><tr><td>Weekday-only feature</td><td><strong>Ignore self</strong> + <strong>Run on Weekdays</strong></td></tr></tbody></table>

Start with **Ignore self**, add **Ignore bots**, then narrow the place down with a whitelist. That covers the large majority of features.
