// Deep dive

Yellowstone gRPC filters explained.

Yellowstone gRPC lets you subscribe to exactly the data you need — accounts, transactions, slots, blocks, or entries. The power is in the filters. This reference covers every filter type, how they combine, and the patterns that matter for trading bots.

The SubscribeRequest

Everything in Yellowstone gRPC starts with a single protobuf message: SubscribeRequest. This message defines what data you want to receive and how it should be filtered. You send it once after opening a bidirectional gRPC stream, and the server begins pushing matching events immediately. The structure is map-based — each data type accepts a map of named filters, where the key is an arbitrary label you choose and the value is the filter configuration for that subscription.

Named filters are powerful because they let you run multiple independent subscriptions on a single connection. You might label one transaction filter "pumpfun" and another "raydium". Each filter operates independently — the server evaluates every incoming event against all of your filters and forwards anything that matches at least one. This avoids the cost and complexity of opening multiple gRPC connections for different data streams.

The six data types you can subscribe to are accounts, transactions, slots, blocks, block_meta, and entries. Each has its own filter message type with fields specific to that data category. The commitment field applies globally to the entire subscription and controls the finality level of all delivered data.

Commitment levels determine when you receive data relative to chain confirmation. PROCESSED (value 0) is the fastest — data arrives the moment the validator processes it, before cluster confirmation. This is ideal for sniping but carries the risk of reverted slots. CONFIRMED (value 1) is the default and the safest choice for trading bots — data arrives after supermajority stake has voted on the slot. FINALIZED (value 2) waits for the slot to be rooted, adding roughly 13 seconds (~32 slots) of delay but guaranteeing that the data is permanent and cannot be reverted under any circumstances.

SubscribeRequest — protobuf structure
message SubscribeRequest {
map<string, SubscribeRequestFilterAccounts> accounts;
map<string, SubscribeRequestFilterSlots> slots;
map<string, SubscribeRequestFilterTransactions> transactions;
map<string, SubscribeRequestFilterBlocks> blocks;
map<string, SubscribeRequestFilterBlocksMeta> blocks_meta;
map<string, SubscribeRequestFilterEntry> entry;
optional CommitmentLevel commitment;
repeated string accounts_data_slice;
optional SubscribeRequestPing ping;
}

The string keys in each map are arbitrary labels you choose. They help you identify which filter matched when processing results. For the full tutorial on connecting and streaming, see the Yellowstone gRPC tutorial.

Transaction filters

SubscribeRequestFilterTransactions is the most commonly used filter for trading bots. It determines which transactions are forwarded to your client based on the accounts they involve and their execution status. Understanding this filter is essential for building any Solana trading application on Yellowstone gRPC.

The filter has five key fields. account_include accepts an array of account addresses — any transaction that involves ANY of these accounts (as a program ID, signer, or referenced key) will match. This is the primary field used for filtering by program. account_exclude rejects transactions that involve any of the listed accounts. account_required requires that ALL listed accounts appear in the transaction — this is stricter than account_include and useful for targeting interactions between specific programs.

The vote field controls whether vote transactions are included. On Solana, vote transactions from validators account for over 50% of all on-chain activity. Set this to false for trading bots — you almost never want vote data cluttering your stream. The failed field controls whether failed transactions are included. Set this to false to only receive successful executions, or leave it unset if you need to analyze failure patterns.

The filter logic is straightforward: account_include is OR (match any), account_required is AND (match all), account_exclude is NOT (reject any). These fields combine with AND across each other — a transaction must satisfy all three conditions simultaneously, plus the vote and failed flags.

transaction-filter.js — Pump.fun + Raydium
stream.write({
transactions: {
pumpfun: {
vote: false,
failed: false,
account_include: [
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
},
raydium: {
vote: false,
failed: false,
account_include: [
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"
],
},
},
commitment: 1,
});

Two named filters on one connection. The server sends transactions matching either Pump.fun or Raydium — no duplicates, no votes, no failures. For program-specific guides, see Pump.fun streaming and Raydium streaming.

Account filters

SubscribeRequestFilterAccounts lets you watch for changes to specific accounts or to all accounts owned by a particular program. Unlike transaction filters which deliver full transaction data, account filters deliver the updated account state — the data bytes, lamport balance, owner, and slot of the change. This is the right subscription type when you care about the current state of an account rather than the transaction that caused the change.

The primary fields are account and owner. The account field accepts an array of specific account pubkeys to watch — whenever any of these accounts change, you receive the updated state. The owner field accepts program IDs and watches every account owned by those programs. Be careful with owner subscriptions on high-volume programs — subscribing to all accounts owned by the Token Program would flood your stream with millions of updates per minute.

The filters field provides advanced byte-level filtering for narrowing results. memcmp (memory compare) checks specific bytes at a given offset in the account data — this is how you filter all token accounts for a specific mint by comparing the mint pubkey at offset 0. datasize matches accounts of a specific byte length, useful for filtering by account type since different account structs have different sizes. token_account_state filters specifically for SPL Token account states, and lamports filters by SOL balance.

account-filter.js — token accounts by mint (memcmp)
const TOKEN_PROGRAM = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
const TARGET_MINT = "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU";
stream.write({
accounts: {
token_watchers: {
owner: [TOKEN_PROGRAM],
filters: [
{
memcmp: {
offset: 0,
bytes: TARGET_MINT,
}
}
],
},
},
commitment: 1,
});

This watches all token accounts whose mint matches the target address. The memcmp at offset 0 checks the first 32 bytes of SPL Token account data, which is always the mint pubkey. See the TypeScript guide for typed wrappers around these filters.

Slot and block filters

Slot subscriptions are the simplest filter type in Yellowstone gRPC. The SubscribeRequestFilterSlots message has a single optional field: filter_by_commitment. When set to true, the server only emits slot notifications at the commitment level specified in your SubscribeRequest. When unset or false, you receive slot notifications at every commitment level — processed, confirmed, and finalized — as each slot progresses through the confirmation pipeline. Slot subscriptions are essential for health monitoring, latency tracking, and detecting chain congestion or leader schedule gaps.

Block subscriptions via SubscribeRequestFilterBlocks deliver full block data including every transaction in the block. This is a heavy subscription — each block can contain thousands of transactions — and is primarily used for indexing, replaying, or building block explorers. The filter fields let you control whether to include transactions, accounts, and entries within the block payload. For most trading use cases, transaction filters are more efficient than block filters because they only deliver the transactions you care about.

SubscribeRequestFilterBlocksMeta provides lightweight block headers without the full transaction payload — slot number, blockhash, parent slot, block time, and transaction count. This is ideal for analytics dashboards that need block-level metrics without the bandwidth cost of full block data. SubscribeRequestFilterEntry delivers raw shred entries — the sub-block units that validators process. Entry subscriptions are an advanced feature primarily used by validators, MEV infrastructure, and sequencer implementations.

Slots

Health monitoring, latency tracking, congestion detection

Lightweight notifications for each slot as it progresses through processed → confirmed → finalized. Detect leader schedule gaps, track confirmation times, and monitor chain health.

Blocks

Indexing, full replay, block explorers

Complete block data with all transactions, accounts, and entries. Heavy bandwidth — use transaction filters instead unless you need the full block context.

Block_meta

Analytics, dashboards, TPS tracking

Slot number, blockhash, parent slot, block time, and transaction count without the full payload. Perfect for real-time analytics at minimal cost.

Entries

Validators, MEV research, sequencers

Sub-block shred entries as validators process them. Provides the most granular view of on-chain activity — before transactions are grouped into blocks.

Filter combination logic

Understanding how filters combine is the key to writing efficient Yellowstone gRPC subscriptions. There are three levels of combination, and each uses different boolean logic. Getting this wrong means either missing data you need or receiving a firehose of irrelevant events that overwhelms your client.

Within a single filter: fields combine with AND logic. A transaction must satisfy all specified conditions simultaneously — account_include AND account_required AND NOT account_exclude AND the vote flag AND the failed flag. If any condition fails, the transaction is dropped.

Within arrays: values combine with OR logic. If account_include contains ["programA", "programB"], any transaction touching program A OR program B will match. The same applies to account_exclude — if a transaction touches any excluded account, it is dropped.

Multiple named filters: combine with OR logic. If you define a "pump" filter and a "raydium" filter, you receive results matching either filter. The server deduplicates — if a transaction matches both filters, you receive it once.

Filter combination rules
LevelLogicExample
Fields in a filterANDaccount_include + vote:false + failed:false — all conditions must pass
Values in an arrayORaccount_include: [A, B] — transactions touching A or B
Named filtersOR"pump" filter + "raydium" filter — results from either
complex-filter.js — Pump.fun creates + Raydium pools
stream.write({
transactions: {
pump_creates: {
vote: false,
failed: false,
account_include: [
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
],
},
raydium_pools: {
vote: false,
failed: false,
account_include: [
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"
],
},
},
commitment: 0,
});

PROCESSED commitment for fastest delivery. Each named filter is evaluated independently — you receive the union of both result sets on a single stream.

Common filter patterns

These are the filter configurations that trading bot developers use most frequently. Each pattern is optimized for a specific strategy — from sniping new token launches to monitoring portfolios. Use them as starting points and adjust the commitment level and account lists for your needs.

account_include: [Pump.fun program] · vote: false · failed: false · commitment: PROCESSED

Captures every Pump.fun transaction at the earliest possible moment. PROCESSED commitment ensures you see token creates before they reach CONFIRMED — giving you a ~400ms head start on bots that use CONFIRMED.

account_include: [target wallet addresses] · vote: false · commitment: CONFIRMED

Streams every transaction from the wallets you are tracking. CONFIRMED commitment avoids acting on reverted transactions while still delivering data within ~1 second of execution. Include multiple wallet addresses in the array to watch a portfolio of whales.

Arbitrage scanner

Raydium guide →

account_include: [Raydium AMM, Jupiter program] · vote: false · failed: false · commitment: CONFIRMED

Monitors swap activity across the two largest Solana DEX programs. Detecting price discrepancies between Raydium pools and Jupiter routes in the same slot window enables atomic arbitrage opportunities.

account_include: [target token accounts] · vote: false · commitment: PROCESSED

Watches for transactions touching specific token accounts at PROCESSED commitment. Reveals sandwich attacks, frontrunning, and backrunning patterns by showing the exact ordering of transactions within a slot.

Portfolio tracker

Python guide →

accounts subscription · owner: [Token Program] · memcmp: wallet address at offset 32 · commitment: CONFIRMED

Uses account subscriptions instead of transaction filters. Watches all token accounts where the wallet address matches at byte offset 32 (the owner field in SPL Token account data). Receives balance updates for every token the wallet holds.

Frequently asked questions

How do Yellowstone gRPC filters combine?

Within a single filter, fields use AND logic. Within arrays (like account_include), values use OR. Multiple named filters use OR — you get results matching ANY filter.

Can I filter by program ID?

Yes. Add the program ID to the account_include field in a transaction filter. You’ll receive every transaction that involves that program.

What is memcmp in Yellowstone gRPC?

Memory compare (memcmp) lets you filter accounts by checking specific bytes at a given offset. Common use: filter all token accounts for a specific mint by comparing bytes at offset 0.

What commitment level should I use?

CONFIRMED is the default and best for most trading bots. PROCESSED is faster but may include reverted slots. FINALIZED adds ~13 seconds of delay but guarantees permanence.

Let Subglow handle the filtering.

Server-side filtering with pre-parsed JSON output. Define your filters once — we deliver exactly what you need.