GetBdnBlockStream

The GetBdnBlockStream stream provides low-latency access to new blocks as they’re produced on the Base network. Note that there is a low chance that this stream may include blocks that will not be accepted on chain.

This is a real-time gRPC stream delivering full block headers and bodies (including transactions), intended for searchers, indexers, and other latency-sensitive applications.

This stream is available to Enterprise Elite and Ultra tier users.

Quickstart

Prerequisites

  • Go 1.24.1+

  • op-geth installed (pay attention to use it instread of go-ethereum)

  • gRPC installed (google.golang.org/grpc)

  • .proto file: streamer_api.proto

gRPC Endpoint

base.blxrbdn.com:443
  • No TLS required

  • Authorization required via authorization header

Authentication

Set your authorization header via environment variable:

export AUTH_HEADER="<your-auth-header>"

In gRPC, this will be passed as:

metadata.New(map[string]string{
  "authorization": os.Getenv("AUTH_HEADER"),
})

Example: Test with grpcurl

grpcurl -H "authorization: <AUTH_HEADER>" \
  -H "Content-Type: application/grpc" \
  -d '{}' \
  base.blxrbdn.com:443 \
  streamerapi.Api/GetBdnBlockStream

This will return raw stream data — you can pretty-print it with jq.

GO Example: Listen for New Blocks on Base

🔗 You can get the .proto file here

🔗 You can access the Base streamer client here

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/bloXroute-Labs/base-streamer-client-go/provider"
	streamerapi "github.com/bloXroute-Labs/base-streamer-proto/streamer_api"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/rlp"
	"github.com/joho/godotenv"
)

func main() {
	_ = godotenv.Load()

	err := ListenForBdnBlocks(10)
	if err != nil {
		panic(err)
	}
}

func ListenForBdnBlocks(numberOfBlocks uint64) error {
	grpcClient, err := provider.NewGRPCClient()
	if err != nil {
		return err
	}
	blocksChan := make(chan *streamerapi.GetBdnBlockStreamResponse)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	stream, err := grpcClient.GetBdnBlockStream(ctx)
	if err != nil {
		return fmt.Errorf("failed to get stream with: %v", err)
	}
	stream.Into(blocksChan)

	fmt.Println("waiting on blocks channel")
	for range numberOfBlocks {
		bdnBlock, ok := <-blocksChan
		if !ok {
			// channel closed
			return fmt.Errorf("bdn blocks channel closed")
		}
		updateTime := time.Now()

		blockHeader := &types.Header{}
		err := rlp.DecodeBytes(bdnBlock.BlockHeader, blockHeader)
		if err != nil {
			return fmt.Errorf("failed to RLP decode block header with: %v", err)
		}

		blockBody := &types.Body{}
		err = rlp.DecodeBytes(bdnBlock.BlockBody, blockBody)
		if err != nil {
			return fmt.Errorf("failed to RLP decode block body with: %v", err)
		}

		fmt.Printf("bdn block: %v, %v txns at %v\n", blockHeader.Number.Uint64(), len(blockBody.Transactions), updateTime.UTC())
	}
	return nil
}

Sample output:

waiting on blocks channel  
new block: 12345678, 120 txns at 2025-03-25 12:45:01.234 UTC  
new block: 12345679, 98 txns at 2025-03-25 12:45:13.147 UTC  
...

Troubleshooting

Issue
Possible Cause

Stream closes unexpectedly

Expired token, gRPC connection limits, network/firewall issues

Unmarshal errors

Mismatched Go or op-geth dependency

No output

Ensure proper env variables and endpoint configuration

Last updated