> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solanatracker.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Slot & Block Monitoring

> Watch Solana slots and blocks in real time with Yellowstone gRPC — track network health, block production, transaction volume, and commitment status.

## Overview

Slot and block monitoring lets you watch Solana's network in real-time. See when blocks are produced, track network health, and monitor transaction volume as it happens.

<Info>
  **Start here first:** Complete the [Quickstart Guide](/yellowstone-grpc/quickstart) to set up your stream manager.
</Info>

## What You Can Monitor

<Tabs>
  <Tab title="Slots">
    **Watch the network heartbeat**

    Slots are 400ms time windows. Watch them advance to see network health:

    ```typescript theme={null}
        const subscribeRequest: SubscribeRequest = {
          slots: {
            slotSubscribe: {
              filterByCommitment: false // Get all commitment levels
            }
          },
          commitment: CommitmentLevel.CONFIRMED
        };
    ```

    **What you'll see:**

    * Slot number
    * Parent slot
    * Status (processed, confirmed, or finalized)

    <Note>
      **Good for:** Network health dashboards, timing analysis, detecting problems
    </Note>
  </Tab>

  <Tab title="Full Blocks">
    **Get everything in a block**

    See complete blocks with all transactions and account updates:

    ```typescript theme={null}
        const subscribeRequest: SubscribeRequest = {
          blocks: {
            blockSubscribe: {
              accountInclude: [],
              includeTransactions: true,
              includeAccounts: true,
              includeEntries: false
            }
          },
          commitment: CommitmentLevel.CONFIRMED
        };
    ```

    **What you'll see:**

    * Block info
    * All transactions
    * Account changes
    * Timing data

    <Warning>
      **Lots of data:** Full blocks are big. Use filters to reduce the amount of data.
    </Warning>
  </Tab>

  <Tab title="Block Metadata">
    **Just the basics**

    Get block info without all the transaction details:

    ```typescript theme={null}
        const subscribeRequest: SubscribeRequest = {
          blocksMeta: {
            blockMetaSubscribe: {}
          },
          commitment: CommitmentLevel.CONFIRMED
        };
    ```

    **What you'll see:**

    * Block hash
    * Slot number
    * Block height
    * Transaction count
    * Block rewards

    <Tip>
      **Lightweight:** Much less data than full blocks
    </Tip>
  </Tab>
</Tabs>

## Real Examples

### Example 1: Basic Slot Monitor

Watch slots and track network performance:

```typescript theme={null}
import Client, { CommitmentLevel, SubscribeRequest } from "@triton-one/yellowstone-grpc";

class StreamManager {
  private client: Client;

  constructor(
    endpoint: string,
    token: string,
    private onData: (data: any) => void
  ) {
    this.client = new Client(endpoint, token, {
      "grpc.max_receive_message_length": 100 * 1024 * 1024
    });
  }

  async connect(request: SubscribeRequest) {
    const stream = await this.client.subscribe();

    stream.on("data", this.onData);
    stream.on("error", (error) => {
      console.error("Stream error:", error);
    });

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

    return stream;
  }
}

async function monitorSlots() {
  const streamManager = new StreamManager(
    "https://grpc.solanatracker.io",
    process.env.GRPC_API_TOKEN || "your-api-key",
    handleSlotUpdate
  );

  const subscribeRequest: SubscribeRequest = {
    slots: {
      slotSubscribe: {
        filterByCommitment: false
      }
    },
    commitment: CommitmentLevel.PROCESSED
  };

  console.log("Starting slot monitoring...");
  await streamManager.connect(subscribeRequest);
}

const slotStats = {
  totalSlots: 0,
  lastSlot: 0,
  lastTimestamp: Date.now(),
  slotTimes: [] as number[],
  skippedSlots: 0
};

function handleSlotUpdate(data: any): void {
  if (data.slot) {
    const slot = data.slot;
    const currentTime = Date.now();
    
    slotStats.totalSlots++;
    
    console.log(`\n[Slot #${slotStats.totalSlots}]`);
    console.log(`  Slot Number: ${slot.slot}`);
    console.log(`  Parent Slot: ${slot.parentSlot}`);
    console.log(`  Status: ${slot.status.toUpperCase()}`);
    
    // Calculate timing if we have a previous slot
    if (slotStats.lastSlot > 0) {
      const slotDiff = slot.slot - slotStats.lastSlot;
      const timeDiff = currentTime - slotStats.lastTimestamp;
      
      if (slotDiff === 1) {
        // Normal progression
        slotStats.slotTimes.push(timeDiff);
        
        // Keep last 100 slots
        if (slotStats.slotTimes.length > 100) {
          slotStats.slotTimes.shift();
        }
        
        const avgSlotTime = slotStats.slotTimes.reduce((a, b) => a + b, 0) / slotStats.slotTimes.length;
        
        console.log(`  Time Since Last: ${timeDiff}ms`);
        console.log(`  Average (100 slots): ${avgSlotTime.toFixed(1)}ms`);
        
        // Alert on slow slots
        if (timeDiff > 800) {
          console.log(`  ⚠️  SLOW SLOT: Expected ~400ms, got ${timeDiff}ms`);
        }
      } else if (slotDiff > 1) {
        // Skipped slots
        const skipped = slotDiff - 1;
        slotStats.skippedSlots += skipped;
        console.log(`  ⚠️  SKIPPED ${skipped} SLOT(S)`);
        console.log(`  Total Skipped: ${slotStats.skippedSlots}`);
      }
    }
    
    slotStats.lastSlot = slot.slot;
    slotStats.lastTimestamp = currentTime;
    
    // Summary every 100 slots
    if (slotStats.totalSlots % 100 === 0) {
      printSlotSummary();
    }
  }
}

function printSlotSummary(): void {
  const avgSlotTime = slotStats.slotTimes.length > 0
    ? slotStats.slotTimes.reduce((a, b) => a + b, 0) / slotStats.slotTimes.length
    : 0;
  const skipRate = (slotStats.skippedSlots / slotStats.totalSlots * 100).toFixed(2);
  
  console.log(`\n=== Slot Summary ===`);
  console.log(`  Total Slots: ${slotStats.totalSlots}`);
  console.log(`  Skipped: ${slotStats.skippedSlots} (${skipRate}%)`);
  console.log(`  Average Slot Time: ${avgSlotTime.toFixed(1)}ms`);
  console.log(`  Expected: ~400ms per slot`);
}

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

### Example 2: Block Metadata Monitor

Track blocks and transaction volume:

```typescript theme={null}
async function monitorBlocks() {
  const streamManager = new StreamManager(
    "https://grpc.solanatracker.io",
    process.env.GRPC_API_TOKEN || "your-api-key",
    handleBlockMeta
  );

  const subscribeRequest: SubscribeRequest = {
    blocksMeta: {
      blockMetaSubscribe: {}
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  console.log("Monitoring blocks...");
  await streamManager.connect(subscribeRequest);
}

const blockStats = {
  totalBlocks: 0,
  totalTransactions: 0,
  totalRewards: 0,
  highActivityBlocks: 0,
  blockTimes: [] as number[],
  lastBlockTime: 0
};

function handleBlockMeta(data: any): void {
  if (data.blockMeta) {
    const meta = data.blockMeta;
    blockStats.totalBlocks++;
    blockStats.totalTransactions += meta.transactionCount || 0;
    
    console.log(`\n[Block #${blockStats.totalBlocks}]`);
    console.log(`  Slot: ${meta.slot}`);
    console.log(`  Block Height: ${meta.blockHeight}`);
    console.log(`  Block Hash: ${meta.blockhash?.slice(0, 16)}...`);
    console.log(`  Transactions: ${meta.transactionCount || 0}`);
    
    // Track block timing
    if (meta.blockTime) {
      const blockTime = new Date(meta.blockTime * 1000);
      console.log(`  Block Time: ${blockTime.toISOString()}`);
      
      if (blockStats.lastBlockTime > 0) {
        const timeDiff = meta.blockTime - blockStats.lastBlockTime;
        blockStats.blockTimes.push(timeDiff);
        
        if (blockStats.blockTimes.length > 50) {
          blockStats.blockTimes.shift();
        }
        
        console.log(`  Time Since Last Block: ${timeDiff}s`);
      }
      
      blockStats.lastBlockTime = meta.blockTime;
    }
    
    // Track rewards
    if (meta.rewards && meta.rewards.length > 0) {
      const totalReward = meta.rewards.reduce((sum: number, r: any) => sum + (r.lamports || 0), 0);
      blockStats.totalRewards += totalReward;
      
      console.log(`  Block Rewards: ${(totalReward / 1e9).toFixed(6)} SOL`);
      console.log(`  Reward Count: ${meta.rewards.length}`);
      
      // Show top rewards
      const sortedRewards = [...meta.rewards]
        .sort((a: any, b: any) => (b.lamports || 0) - (a.lamports || 0))
        .slice(0, 3);
      
      sortedRewards.forEach((reward: any, idx: number) => {
        console.log(`    ${idx + 1}. ${reward.pubkey?.slice(0, 8)}... ${(reward.lamports / 1e9).toFixed(6)} SOL (${reward.rewardType || 'unknown'})`);
      });
    }
    
    // Flag high-activity blocks
    if (meta.transactionCount > 3000) {
      blockStats.highActivityBlocks++;
      console.log(`  🔥 HIGH ACTIVITY: ${meta.transactionCount} transactions`);
    }
    
    // Summary every 50 blocks
    if (blockStats.totalBlocks % 50 === 0) {
      printBlockSummary();
    }
  }
}

function printBlockSummary(): void {
  const avgTxPerBlock = blockStats.totalBlocks > 0
    ? (blockStats.totalTransactions / blockStats.totalBlocks).toFixed(1)
    : 0;
  const avgBlockTime = blockStats.blockTimes.length > 0
    ? (blockStats.blockTimes.reduce((a, b) => a + b, 0) / blockStats.blockTimes.length).toFixed(1)
    : 0;
  const totalRewardsSOL = (blockStats.totalRewards / 1e9).toFixed(4);
  
  console.log(`\n=== Block Summary ===`);
  console.log(`  Total Blocks: ${blockStats.totalBlocks}`);
  console.log(`  Total Transactions: ${blockStats.totalTransactions}`);
  console.log(`  Avg Tx/Block: ${avgTxPerBlock}`);
  console.log(`  High Activity Blocks: ${blockStats.highActivityBlocks}`);
  console.log(`  Avg Block Time: ${avgBlockTime}s`);
  console.log(`  Total Rewards: ${totalRewardsSOL} SOL`);
}

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

### Example 3: Filtered Block Monitor

Watch blocks that contain specific program activity:

```typescript theme={null}
// Replace with programs you want to monitor
const TOKEN_PROGRAM = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
const SYSTEM_PROGRAM = "11111111111111111111111111111111";

async function monitorFilteredBlocks() {
  const streamManager = new StreamManager(
    "https://grpc.solanatracker.io",
    process.env.GRPC_API_TOKEN || "your-api-key",
    handleFilteredBlock
  );

  const subscribeRequest: SubscribeRequest = {
    blocks: {
      filteredBlocks: {
        accountInclude: [TOKEN_PROGRAM, SYSTEM_PROGRAM], // Your programs here
        includeTransactions: true,
        includeAccounts: false,
        includeEntries: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  console.log("Monitoring filtered blocks...");
  await streamManager.connect(subscribeRequest);
}

const filteredStats = {
  totalBlocks: 0,
  totalTransactions: 0,
  successfulTx: 0,
  failedTx: 0,
  totalFees: 0,
  programCounts: new Map<string, number>()
};

function handleFilteredBlock(data: any): void {
  if (data.block) {
    const block = data.block;
    filteredStats.totalBlocks++;
    
    console.log(`\n[Filtered Block #${filteredStats.totalBlocks}]`);
    console.log(`  Slot: ${block.slot}`);
    console.log(`  Block Hash: ${block.blockhash?.slice(0, 16)}...`);
    console.log(`  Transactions in Block: ${block.transactions?.length || 0}`);
    
    if (block.transactions) {
      let blockTxCount = 0;
      let blockFees = 0;
      let successCount = 0;
      let failCount = 0;
      
      block.transactions.forEach((tx: any) => {
        blockTxCount++;
        filteredStats.totalTransactions++;
        
        const success = !tx.meta?.err;
        if (success) {
          successCount++;
          filteredStats.successfulTx++;
        } else {
          failCount++;
          filteredStats.failedTx++;
        }
        
        const fee = tx.meta?.fee || 0;
        blockFees += fee;
        filteredStats.totalFees += fee;
        
        // Track program usage
        const accountKeys = tx.transaction?.message?.accountKeys || [];
        const instructions = tx.transaction?.message?.instructions || [];
        
        instructions.forEach((ix: any) => {
          const programId = accountKeys[ix.programIdIndex];
          if (programId) {
            const count = filteredStats.programCounts.get(programId) || 0;
            filteredStats.programCounts.set(programId, count + 1);
          }
        });
      });
      
      console.log(`  Successful Tx: ${successCount}`);
      console.log(`  Failed Tx: ${failCount}`);
      console.log(`  Block Fees: ${(blockFees / 1e9).toFixed(6)} SOL`);
      console.log(`  Avg Fee: ${(blockFees / Math.max(blockTxCount, 1) / 1e9).toFixed(6)} SOL`);
      
      // Show program distribution in this block
      const programsInBlock = new Map<string, number>();
      block.transactions.forEach((tx: any) => {
        const keys = tx.transaction?.message?.accountKeys || [];
        const instructions = tx.transaction?.message?.instructions || [];
        
        instructions.forEach((ix: any) => {
          const programId = keys[ix.programIdIndex];
          if (programId) {
            const count = programsInBlock.get(programId) || 0;
            programsInBlock.set(programId, count + 1);
          }
        });
      });
      
      console.log(`  Programs Used:`);
      Array.from(programsInBlock.entries())
        .sort((a, b) => b[1] - a[1])
        .slice(0, 3)
        .forEach(([program, count]) => {
          const name = program === TOKEN_PROGRAM ? "Token Program"
            : program === SYSTEM_PROGRAM ? "System Program"
            : program.slice(0, 12) + "...";
          console.log(`    - ${name}: ${count} calls`);
        });
    }
    
    // Summary every 20 blocks
    if (filteredStats.totalBlocks % 20 === 0) {
      printFilteredSummary();
    }
  }
}

function printFilteredSummary(): void {
  const avgTxPerBlock = filteredStats.totalBlocks > 0
    ? (filteredStats.totalTransactions / filteredStats.totalBlocks).toFixed(1)
    : 0;
  const successRate = filteredStats.totalTransactions > 0
    ? (filteredStats.successfulTx / filteredStats.totalTransactions * 100).toFixed(1)
    : 0;
  
  console.log(`\n=== Filtered Block Summary ===`);
  console.log(`  Blocks Processed: ${filteredStats.totalBlocks}`);
  console.log(`  Total Transactions: ${filteredStats.totalTransactions}`);
  console.log(`  Avg Tx/Block: ${avgTxPerBlock}`);
  console.log(`  Success Rate: ${successRate}%`);
  console.log(`  Total Fees: ${(filteredStats.totalFees / 1e9).toFixed(4)} SOL`);
  
  console.log(`\n  Most Used Programs:`);
  Array.from(filteredStats.programCounts.entries())
    .sort((a, b) => b[1] - a[1])
    .slice(0, 5)
    .forEach(([program, count]) => {
      const name = program === TOKEN_PROGRAM ? "Token Program"
        : program === SYSTEM_PROGRAM ? "System Program"
        : program.slice(0, 12) + "...";
      console.log(`    ${name}: ${count} instructions`);
    });
}

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

## Understanding the Data

<Accordion title="Slot Data">
  ```typescript theme={null}
    {
      slot: number;           // Which slot
      parentSlot: number;     // Previous slot  
      status: string;         // "processed", "confirmed", or "finalized"
    }
  ```

  **Slots happen every \~400ms**

  **Status levels:**

  * **Processed:** Just happened
  * **Confirmed:** Majority of network agrees
  * **Finalized:** Can't be undone
</Accordion>

<Accordion title="Block Metadata">
  ```typescript theme={null}
    {
      slot: number;
      blockHeight: number;
      blockhash: string;
      parentBlockhash: string;
      blockTime: number;      // Unix timestamp
      transactionCount: number;
      rewards: Array<{
        pubkey: string;
        lamports: number;
        rewardType: string;   // "fee", "rent", "voting", "staking"
      }>;
    }
  ```

  **Block time:** When the block was made

  **Rewards:** What validators earned
</Accordion>

<Accordion title="Full Block">
  ```typescript theme={null}
    {
      slot: number;
      parentSlot: number;
      blockhash: string;
      previousBlockhash: string;
      transactions: Transaction[];  // All transactions
      accounts: AccountUpdate[];    // Account changes
      entries: Entry[];            // Entries (optional)
    }
  ```

  **Warning:** Full blocks can be several MB
</Accordion>

## How Much Data?

<CardGroup cols={2}>
  <Card title="Slot Monitoring" icon="clock">
    **Very light**

    * Minimal data usage
    * Real-time network pulse
    * Easy to process
    * Great for dashboards
  </Card>

  <Card title="Block Metadata" icon="info">
    **Medium**

    * Moderate data usage
    * Block-level insights
    * Transaction counts
    * Good for analytics
  </Card>

  <Card title="Full Blocks" icon="database">
    **Heavy**

    * High data usage
    * Everything included
    * Needs strong hardware
    * Use filters!
  </Card>

  <Card title="Filtered Blocks" icon="filter">
    **Smart choice**

    * Use accountInclude
    * Turn off what you don't need
    * Focus on specific programs
    * Best balance
  </Card>
</CardGroup>

## What You Can Build

<Tabs>
  <Tab title="Network Monitors">
    **Track network performance**

    * Slot timing dashboards
    * Congestion alerts
    * Consensus tracking
    * Validator stats
    * Skip rate alerts
  </Tab>

  <Tab title="Analytics Tools">
    **Collect blockchain data**

    * Transaction volume charts
    * Fee tracking
    * Block size analysis
    * Activity patterns
    * Reward tracking
  </Tab>

  <Tab title="Sync Tools">
    **Keep apps in sync**

    * Slot-based updates
    * Block confirmations
    * Network state sync
    * Timing sync
  </Tab>
</Tabs>

## Common Problems

<Accordion title="Missing Slots">
  **Problem:** You see gaps in slot numbers

  **Why it happens:**

  * Connection dropped
  * Validator went down
  * Your code is too slow

  **Fix it:**

  * Track gaps and alert
  * Add catch-up code
  * Check your connection
</Accordion>

<Accordion title="Too Much Data">
  **Problem:** Full blocks are overwhelming

  **Fix it:**

  * Use metadata instead
  * Add account filters
  * Turn off unnecessary data
  * Process async
</Accordion>

## Best Practices

<Note>
  **Tips for production:**

  * **Start small** - Use metadata before full blocks
  * **Filter everything** - Use accountInclude to reduce data
  * **Watch timing** - Track slots to spot problems
  * **Handle gaps** - Code for missing slots
  * **Don't block** - Process data async
  * **Match commitment** - Pick the right level for your needs
  * **Track yourself** - Monitor your own performance
  * **Set alerts** - Get notified of problems
</Note>

## Common Questions

<Accordion title="What's a slot?">
  A slot is a 400ms time window. Solana processes transactions in slots. One slot = one potential block (though some slots get skipped).
</Accordion>

<Accordion title="Should I use full blocks or metadata?">
  Start with metadata. It's way lighter and has most of what you need. Only use full blocks if you need every transaction detail.
</Accordion>

<Accordion title="Why are some slots skipped?">
  Validators sometimes miss their turn to produce a block. This is normal and the network handles it automatically. A 5% skip rate is typical.
</Accordion>

<Accordion title="How big are full blocks?">
  A busy block can be several MB. That's why filtering is important - you don't want to download gigabytes of data you don't need.
</Accordion>

<Accordion title="What's the difference between processed, confirmed, and finalized?">
  * **Processed** (\~400ms): Just happened, might change
  * **Confirmed** (\~1 second): Supermajority agrees, probably won't change
  * **Finalized** (\~13 seconds): Locked in, can't change
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="Entry Monitoring" icon="code" href="/yellowstone-grpc/entry-monitoring">
    Even more detailed monitoring
  </Card>

  <Card title="Account Monitoring" icon="wallet" href="/yellowstone-grpc/account-monitoring">
    Watch specific accounts
  </Card>

  <Card title="Real Example" icon="chart-line" href="/yellowstone-grpc/examples/pumpfun-transactions">
    See it in action
  </Card>

  <Card title="Quickstart" icon="rocket" href="/yellowstone-grpc/quickstart">
    Get started
  </Card>
</CardGroup>
