Skip to main content

Filters

Filters are JSON objects used to request events from relays. Understanding filters is essential for building efficient Nostr applications.

Filter Structure

{
"ids": ["<event-id>", "..."],
"authors": ["<pubkey>", "..."],
"kinds": [1, 6, 7],
"#e": ["<event-id>", "..."],
"#p": ["<pubkey>", "..."],
"#t": ["nostr", "development"],
"since": 1700000000,
"until": 1700086400,
"limit": 100
}

Filter Fields

ids

Match specific event IDs. Can use prefixes.

{"ids": ["abc123...", "def456..."]}

authors

Match events from specific public keys.

{"authors": ["pubkey1...", "pubkey2..."]}

kinds

Match specific event kinds.

{"kinds": [1]}           // Only kind 1
{"kinds": [1, 6, 7]} // Kinds 1, 6, or 7

Tag Filters (#)

Match events containing specific tag values. Use #<tagname>.

{"#e": ["event-id"]}      // Events referencing this event
{"#p": ["pubkey"]} // Events mentioning this pubkey
{"#t": ["bitcoin"]} // Events with this hashtag
{"#a": ["30023:pk:slug"]} // Events referencing this address

since

Only events created after this timestamp (inclusive).

{"since": 1700000000}     // Events after Nov 14, 2023

until

Only events created before this timestamp (inclusive).

{"until": 1700086400}     // Events before Nov 15, 2023

limit

Maximum number of events to return.

{"limit": 100}            // Return at most 100 events

Filter Logic

Within a Filter: AND

All conditions in a single filter are AND-ed:

{
"authors": ["alice-pubkey"],
"kinds": [1],
"since": 1700000000
}
// Events from Alice, kind 1, after timestamp

Multiple Filters: OR

Multiple filters in a REQ are OR-ed:

["REQ", "my-sub",
{"authors": ["alice"], "kinds": [1]},
{"authors": ["bob"], "kinds": [1]}
]
// Notes from Alice OR notes from Bob

Within Arrays: OR

Values within an array are OR-ed:

{"kinds": [1, 6, 7]}      // kind 1 OR 6 OR 7
{"authors": ["a", "b"]} // author a OR author b

Common Patterns

User's Feed

Get notes from followed users:

const filter = {
kinds: [1],
authors: followedPubkeys, // Array of pubkeys
limit: 50,
since: Math.floor(Date.now() / 1000) - 86400 // Last 24 hours
};

User Profile

Get user's metadata:

const filter = {
kinds: [0],
authors: [userPubkey],
limit: 1
};

Thread/Replies

Get all replies to an event:

const filter = {
kinds: [1],
"#e": [eventId]
};

User Activity

Get a user's recent activity:

const filter = {
kinds: [1, 6, 7], // notes, reposts, reactions
authors: [userPubkey],
limit: 100
};

Find events with a specific hashtag:

const filter = {
kinds: [1, 30023], // notes and articles
"#t": ["nostr"],
limit: 50
};

Global Feed

Get recent public notes:

const filter = {
kinds: [1],
limit: 50
};

Subscription Management

Creating Subscriptions

import { SimplePool } from 'nostr-tools';

const pool = new SimplePool();
const relays = ['wss://relay.damus.io', 'wss://nos.lol'];

// Subscribe with callback
const sub = pool.subscribeMany(
relays,
[{ kinds: [1], limit: 10 }],
{
onevent(event) {
console.log('Received:', event);
},
oneose() {
console.log('End of stored events');
}
}
);

// Later: close subscription
sub.close();

Querying (One-shot)

// Get events and close automatically
const events = await pool.querySync(
relays,
{ kinds: [1], limit: 10 }
);

Performance Tips

Use Limits

Always include limit to avoid overwhelming responses:

{"kinds": [1], "limit": 100}

Use Time Bounds

Constrain queries with since and until:

const oneHourAgo = Math.floor(Date.now() / 1000) - 3600;
const filter = {
kinds: [1],
since: oneHourAgo,
limit: 50
};

Be Specific

More specific filters = faster responses:

// Bad: Gets everything
{"kinds": [1]}

// Good: Specific to what you need
{"kinds": [1], "authors": [pubkey], "limit": 20}

Prefix Matching

IDs and authors support prefix matching for efficiency:

{"ids": ["abc"]}       // Matches any ID starting with "abc"
{"authors": ["a1b2"]} // Matches any pubkey starting with "a1b2"

Multiple Subscriptions

Clients can have multiple active subscriptions:

// Feed subscription
pool.subscribeMany(relays, [feedFilter], {
onevent: handleFeedEvent
});

// Notification subscription
pool.subscribeMany(relays, [notificationFilter], {
onevent: handleNotification
});

// Profile subscription
pool.subscribeMany(relays, [profileFilter], {
onevent: handleProfile
});

Relay Behavior

Different relays may have different:

  • Storage limits - May not have old events
  • Rate limits - May throttle requests
  • Filtering policies - May not serve all kinds
  • Query limits - May cap limit values

Always connect to multiple relays for reliability.

See Also