# Yellowstone gRPC

***

Yellowstone gRPC is a structured Solana data stream built on the Geyser model. It exposes real-time blockchain events over gRPC, with support for transactions, transaction status, accounts, slots, blocks, block metadata, and entries streaming.

Yellowstone gRPC has better throughput and latency than the standard Solana WebSocket API because it uses protobuf over gRPC instead of JSON-RPC over WebSocket, supports richer structured payloads, and is better suited for long-lived high-throughput ingestion pipelines.

### What Yellowstone gRPC provides

Yellowstone gRPC gives applications a single bidirectional subscription interface for Solana streaming.

Supported streamed data includes:

* accounts
* slots
* transactions
* transaction status updates
* blocks
* block metadata
* entries

### Use cases

Yellowstone gRPC is designed for applications that continuously consume Solana data and process it server-side.

Typical use cases include:

* indexers
* real-time analytics pipelines
* trading infrastructure
* alerting systems
* event-driven backend services
* database ingestion workers
* queue and stream processors

### gRPC subscription model

Yellowstone uses a bidirectional gRPC stream. The client opens a subscription, sends a `SubscribeRequest`, and then receives matching updates continuously.

A single request can include filters for multiple stream categories at once.

#### Top-level request fields

Common top-level fields include:

* `accounts`
* `slots`
* `transactions`
* `transactions_status`
* `blocks`
* `blocks_meta`
* `entry`
* `accounts_data_slice`
* `commitment`
* `ping`

#### Filter semantics

Yellowstone filters are designed to reduce client-side discard work.

General behavior:

* different filter fields are combined with logical **AND**
* values inside arrays are combined with logical **OR**
* account `filters` are combined with logical **AND**
* empty filters usually mean a broad stream for that category, unless provider-side limits disallow it

#### Commitment levels

Yellowstone supports three commitment levels:

* `processed`
* `confirmed`
* `finalized`

For latency-sensitive ingestion, `processed` is usually the default choice. If you require stronger consensus confidence, `confirmed` or `finalized` may be more appropriate.

#### Supported filters

**Accounts**

Account subscriptions can be filtered by:

* `account`
* `owner`
* `filters`

`filters` follows the same model as `getProgramAccounts`, including `dataSize` and `Memcmp`.

For accounts:

* fields are combined with logical **AND**
* values inside arrays are combined with logical **OR**
* nested `filters` are also treated as logical **AND**

**Transactions**

Transaction subscriptions can be filtered by:

* `vote`
* `failed`
* `signature`
* `account_include`
* `account_exclude`
* `account_required`

For transactions:

* empty filters broadcast all transactions
* fields are combined with logical **AND**
* values inside arrays are combined with logical **OR**

**Slots**

Slots support `filter_by_commitment`, which restricts slot updates to the selected commitment level instead of streaming every slot lifecycle update.

**Blocks**

Block subscriptions support:

* `account_include`
* `include_transactions`
* `include_accounts`
* `include_entries`

**Block metadata**

`blocks_meta` provides block-level metadata without the full block payload.

**Entries**

Entries are a fundamental building block of Proof of History. Each entry contains a unique ID that is the hash of the Entry before it, plus the hash of the transactions within it. Entries cannot be reordered, and its field `num_hashes` represents an approximate amount of time since the last Entry was created.

### Yellowstone gRPC vs WebSocket

The standard Solana WebSocket interface uses JSON-RPC PubSub over WebSocket. Yellowstone uses gRPC over HTTP/2 with protobuf payloads.

In practice, this means Yellowstone is usually a better fit for:

* higher-throughput streaming workloads
* lower-overhead backend ingestion
* typed decoding with protobuf clients
* richer data flows than typical WebSocket subscriptions
* long-lived service-to-service streaming

WebSocket subscriptions are still useful for lightweight apps, dashboards, and simpler live-update flows. Yellowstone is the stronger choice when the stream feeds backend logic, analytics, storage, or trading systems.

***

### Usage limits

{% hint style="info" %}
RPC Fast applies concurrent connection and filter limits to keep Yellowstone gRPC performance predictable under shared high-load usage.
{% endhint %}

#### Max concurrent Yellowstone gRPC connections by plan

One active gRPC connection counts as one stream.

Multiple filters sent over the same connection still count as one stream.

| Plan     | Yellowstone gRPC limit |
| -------- | ---------------------: |
| Stream   |       up to 10 streams |
| Aperture |       up to 25 streams |

#### Filter limits

RPC Fast’s Yellowstone limits are designed for targeted subscriptions rather than unrestricted firehose filters.

**Global**

* Filter name length: up to **128 characters**

**Accounts**

* **1** accounts filter
* Empty filter (match everything) is **not supported**
* Up to **10** pubkeys in `account`
* Up to **10** pubkeys in `owner`
* Up to **2** `accounts_data_slice` ranges

**Slots**

* **1** slots filter

**Transactions**

* **1** transactions filter
* Empty filter (match everything) is **not supported**
* Up to **10** pubkeys in `account_include`
* Up to **10** pubkeys in `account_exclude`
* Up to **10** pubkeys in `account_required`

**Transaction status**

* **1** transaction-status filter
* Empty filter (match everything) is **not supported**
* Up to **10** pubkeys in `account_include`
* Up to **10** pubkeys in `account_exclude`
* Up to **10** pubkeys in `account_required`

**Entries**

* **1** entries filter

**Block metadata**

* **1** block-metadata filter

**Blocks**

* **1** blocks filter
* Up to **10** pubkeys in `account_include`
* Empty `account_include` is **not supported**
* Transactions are included
* Accounts and entries inclusion **is disabled**

### Keep-alive and long-lived subscriptions

Long-lived gRPC subscriptions should enable both transport-level and application-level keepalive.

RPC Fast recommends:

* TCP keepalive enabled
* HTTP/2 keepalive enabled
* handling Yellowstone `ping` messages on the stream

This helps reduce disconnects caused by load balancers, proxies, NAT timeouts, and idle connection cleanup.

***

### Code examples

Replace `YOUR-TOKEN-HERE` with your Yellowstone gRPC token.

{% tabs %}
{% tab title="Rust" %}

```rust
use futures::StreamExt;
use std::collections::HashMap;
use std::time::Duration;
use yellowstone_grpc_client::{ClientTlsConfig, GeyserGrpcClient};
use yellowstone_grpc_proto::geyser::{
    subscribe_update::UpdateOneof,
    CommitmentLevel,
    SubscribeRequest,
    SubscribeRequestFilterTransactions,
};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();

    let mut client = GeyserGrpcClient::build_from_shared("https://solana-yellowstone-grpc.rpcfast.com:443")?
        .x_token(Some("YOUR-TOKEN-HERE"))?
        .http2_keep_alive_interval(Duration::from_secs(30))
        .keep_alive_timeout(Duration::from_secs(10))
        .keep_alive_while_idle(true)
        .tcp_keepalive(Some(Duration::from_secs(30)))
        .tcp_nodelay(true)
        .tls_config(ClientTlsConfig::new().with_native_roots())?
        .connect()
        .await?;

    let mut tx_filters = HashMap::new();
    tx_filters.insert(
        "raydium".to_string(),
        SubscribeRequestFilterTransactions {
            vote: Some(false),
            failed: Some(false),
            signature: None,
            account_include: vec![
                "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string(),
            ],
            account_exclude: vec![],
            account_required: vec![],
        },
    );

    let request = SubscribeRequest {
        transactions: tx_filters,
        commitment: Some(CommitmentLevel::Processed as i32),
        ..Default::default()
    };

    let (_sink, mut stream) = client.subscribe_with_request(Some(request)).await?;

    println!("Yellowstone stream started");

    while let Some(message) = stream.next().await {
        let message = message?;

        if let Some(UpdateOneof::Transaction(tx_update)) = message.update_oneof {
            println!("slot={}", tx_update.slot);

            if let Some(tx) = tx_update.transaction {
                if !tx.signature.is_empty() {
                    println!(
                        "signature={}",
                        bs58::encode(&tx.signature).into_string()
                    );
                }
            }
        }
    }

    Ok(())
}
```

{% endtab %}

{% tab title="TypeScript" %}

```ts
import Client, {
  CommitmentLevel,
  SubscribeRequest,
  ChannelOptions,
} from "@triton-one/yellowstone-grpc";
import bs58 from "bs58";

const X_TOKEN = "YOUR-TOKEN-HERE";

async function main() {
  const channelOptions: ChannelOptions = {
    grpcHttp2KeepAliveInterval: 30_000,
    grpcKeepAliveTimeout: 10_000,
    grpcKeepAliveWhileIdle: true,
    grpcTcpKeepalive: 1,
  };

  const client = new Client(
    "https://yellowstone-grpc.rpcfast.com:443",
    X_TOKEN,
    channelOptions
  );

  await client.connect();

  const stream = await client.subscribe();

  stream.on("data", (update) => {
    if (update.transaction?.transaction?.transaction?.signatures?.length) {
      const signature = bs58.encode(
        update.transaction.transaction.transaction.signatures[0]
      );
      console.log("signature:", signature);
      console.log("slot:", update.transaction.slot);
    }

    if (update.ping) {
      const pong: SubscribeRequest = {
        ping: { id: update.ping.id },
        accounts: {},
        slots: {},
        transactions: {},
        transactionsStatus: {},
        blocks: {},
        blocksMeta: {},
        entry: {},
        accountsDataSlice: [],
      };
      stream.write(pong, () => {});
    }
  });

  stream.on("error", (err) => {
    console.error("stream error:", err);
  });

  const request: SubscribeRequest = {
    transactions: {
      raydium: {
        vote: false,
        failed: false,
        accountInclude: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"],
        accountExclude: [],
        accountRequired: [],
      },
    },
    accounts: {},
    slots: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    accountsDataSlice: [],
    commitment: CommitmentLevel.PROCESSED,
  };

  await new Promise<void>((resolve, reject) => {
    stream.write(request, (err: Error | null | undefined) => {
      if (err) reject(err);
      else resolve();
    });
  });
}

main().catch(console.error);
```

{% endtab %}

{% tab title="grpcurl" %}

```bash
grpcurl \
  -proto geyser.proto \
  -H "x-token: YOUR-TOKEN-HERE" \
  -d '{
    "transactions": {
      "raydium": {
        "vote": false,
        "failed": false,
        "account_include": [
          "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"
        ]
      }
    },
    "accounts": {},
    "slots": {},
    "transactions_status": {},
    "blocks": {},
    "blocks_meta": {},
    "accounts_data_slice": [],
    "commitment": "PROCESSED"
  }' \
  yellowstone-grpc.rpcfast.com:443 \
  geyser.Geyser/Subscribe
```

{% endtab %}
{% endtabs %}

***

### Summary

Yellowstone gRPC is RPC Fast’s developer-oriented streaming interface for Solana backends that need:

* structured real-time data
* server-side filtering
* richer payloads than standard WebSocket subscriptions
* low client-side parsing overhead
* stable long-lived streaming over gRPC

For backend services that ingest, enrich, persist, or react to Solana events continuously, Yellowstone gRPC is generally the preferred integration surface.
