FortiBlox LogoFortiBlox Docs
NexusWebSocket Streaming

WebSocket Streaming Overview

Real-time blockchain data streaming via WebSocket for transactions, blocks, and account updates

WebSocket Streaming

FortiBlox provides WebSocket streaming for real-time X1 Blockchain data through the Geyser plugin. Stream transactions, blocks, accounts, and slots with sub-100ms latency.

What is WebSocket Streaming?

WebSocket streaming gives you a persistent, bidirectional connection to receive real-time blockchain events as they happen. Unlike polling REST APIs, WebSocket provides push-based updates with minimal latency and efficient bandwidth usage.

Beta Feature - Broadcast Mode

Current Implementation: WebSocket currently broadcasts all network transactions to connected clients. Subscription filtering (by account, program, commitment level) is coming in a future update. Simply connect and you'll receive all transactions automatically.

Key Features

  • Real-time transaction streaming - Get notified of all network transactions instantly
  • Low latency - Sub-100ms event delivery
  • Efficient - Persistent connection for continuous streaming
  • Free tier included - 5 concurrent connections on all plans
  • No credit cost - WebSocket messages don't consume API credits

Use Cases

Real-Time Network Monitoring

  • Monitor all network transactions as they occur
  • Track transaction volume and patterns
  • Build network analytics dashboards
  • Detect unusual network activity

Data Aggregation

  • Collect full transaction data for analysis
  • Build transaction indexes
  • Create historical datasets
  • Power blockchain explorers

Trading Bots

  • React to market conditions in real-time
  • Track high-value transactions instantly
  • Monitor network congestion
  • Filter transactions client-side for specific strategies

Need Account/Program Filtering?

For monitoring specific accounts or programs, use the Geyser REST API to query filtered historical data. WebSocket currently provides the full transaction stream, which you can filter client-side.

Quick Example

// Browser WebSocket (uses query parameter for auth)
const ws = new WebSocket(
  'wss://nexus.fortiblox.com/geyser/ws?api-key=fbx_YOUR_KEY_HERE'
);

ws.onopen = () => {
  console.log('✅ Connected to FortiBlox');
  // Connected! Transactions will stream automatically
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === 'connected') {
    console.log('WebSocket ready:', data.message);
  } else if (data.type === 'transaction') {
    console.log('New transaction:', data.data.signature);
  }
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};
// Node.js with ws library (uses headers for auth)
const WebSocket = require('ws');

const ws = new WebSocket('wss://nexus.fortiblox.com/geyser/ws', {
  headers: {
    'X-API-Key': 'fbx_YOUR_KEY_HERE'
  }
});

ws.on('open', () => {
  console.log('✅ Connected to FortiBlox');
  // Transactions stream automatically - no subscription needed
});

ws.on('message', (data) => {
  const message = JSON.parse(data);

  if (message.type === 'connected') {
    console.log('WebSocket ready:', message.message);
  } else if (message.type === 'transaction') {
    console.log('New transaction:', message.data.signature);
  }
});

ws.on('error', (error) => {
  console.error('WebSocket error:', error);
});
import asyncio
import websockets
import json

async def stream_transactions():
    uri = 'wss://nexus.fortiblox.com/geyser/ws?api-key=fbx_YOUR_KEY_HERE'

    async with websockets.connect(uri) as ws:
        print('✅ Connected to FortiBlox')
        # Transactions stream automatically - no subscription needed

        # Listen for messages
        async for message in ws:
            data = json.loads(message)

            if data['type'] == 'connected':
                print(f"WebSocket ready: {data['message']}")
            elif data['type'] == 'transaction':
                print(f"New transaction: {data['data']['signature']}")

asyncio.run(stream_transactions())
use tokio_tungstenite::{connect_async, tungstenite::Message};
use futures_util::{StreamExt, SinkExt};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = "fbx_YOUR_KEY_HERE";
    let url = format!(
        "wss://nexus.fortiblox.com/geyser/ws?api-key={}",
        api_key
    );

    // Connect to WebSocket
    let (ws_stream, _) = connect_async(&url).await?;
    println!("✅ Connected to FortiBlox");

    let (mut write, mut read) = ws_stream.split();

    // Transactions stream automatically - no subscription needed

    // Listen for messages
    while let Some(msg) = read.next().await {
        match msg {
            Ok(Message::Text(text)) => {
                let data: serde_json::Value = serde_json::from_str(&text)?;

                if data["type"] == "connected" {
                    println!("WebSocket ready: {}", data["message"]);
                } else if data["type"] == "transaction" {
                    println!(
                        "New transaction: {}",
                        data["data"]["signature"]
                    );
                }
            }
            Ok(Message::Close(_)) => {
                println!("Connection closed");
                break;
            }
            Err(e) => {
                eprintln!("WebSocket error: {}", e);
                break;
            }
            _ => {}
        }
    }

    Ok(())
}
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "os/signal"

    "github.com/gorilla/websocket"
)

type ConnectedMessage struct {
    Type    string `json:"type"`
    Message string `json:"message"`
}

type TransactionMessage struct {
    Type      string `json:"type"`
    Timestamp string `json:"timestamp"`
    Data      struct {
        Signature string `json:"signature"`
        Slot      int64  `json:"slot"`
    } `json:"data"`
}

func main() {
    apiKey := "fbx_YOUR_KEY_HERE"
    url := fmt.Sprintf(
        "wss://nexus.fortiblox.com/geyser/ws?api-key=%s",
        apiKey,
    )

    // Connect to WebSocket
    conn, _, err := websocket.DefaultDialer.Dial(url, nil)
    if err != nil {
        log.Fatal("Connection error:", err)
    }
    defer conn.Close()

    fmt.Println("✅ Connected to FortiBlox")
    // Transactions stream automatically - no subscription needed

    // Handle interrupt signal
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    // Listen for messages
    done := make(chan struct{})

    go func() {
        defer close(done)
        for {
            var msg TransactionMessage
            err := conn.ReadJSON(&msg)
            if err != nil {
                log.Println("Read error:", err)
                return
            }

            if msg.Type == "connected" {
                fmt.Printf("WebSocket ready\n")
            } else if msg.Type == "transaction" {
                fmt.Printf("New transaction: %s\n", msg.Data.Signature)
            }
        }
    }()

    // Wait for interrupt or connection close
    select {
    case <-done:
        return
    case <-interrupt:
        fmt.Println("\nDisconnecting...")
        conn.WriteMessage(
            websocket.CloseMessage,
            websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
        )
        return
    }
}

Connection Limits by Tier

TierConcurrent ConnectionsMessages/SecondCredit Cost per Message
Free51000 credits (free!)
Developer55000 credits (free!)
Business2502,0000 credits (free!)
Professional2505,0000 credits (free!)
EnterpriseCustomCustom0 credits (free!)

WebSocket messages are free! Unlike REST API calls, WebSocket messages don't consume credits. You only pay for the connection, which is included in all tiers.

Current Capabilities

What's Available Now

WebSocket currently broadcasts all network transactions in real-time:

  • ✅ All transaction types (votes, transfers, program invocations, token operations)
  • ✅ Complete transaction details (signature, slot, accounts, logs)
  • ✅ Automatic streaming - just connect and receive
  • ✅ Sub-100ms latency

Coming Soon (Roadmap)

These features are in development:

  • 🔜 Subscription filtering - Filter by specific accounts or programs
  • 🔜 Commitment levels - Choose processed/confirmed/finalized
  • 🔜 Block updates - Subscribe to new blocks as they're produced
  • 🔜 Slot progression - Track consensus in real-time
  • 🔜 Account state changes - Monitor specific account updates

Need These Features Now?

For filtered transaction queries by account or program, use the Geyser REST API. It supports historical queries with full filtering capabilities.

Authentication

WebSocket requires API key authentication. Choose the method that works for your platform:

Query Parameter (Browser-friendly)

wss://nexus.fortiblox.com/geyser/ws?api-key=fbx_YOUR_KEY

Header (More secure, Node.js/Python)

headers: { 'X-API-Key': 'fbx_YOUR_KEY' }

Authentication guide →

WebSocket vs REST API

FeatureWebSocketREST API (Geyser)
Latency<100ms~200ms
Data TypeReal-time streamHistorical queries
FilteringClient-side (coming soon: server-side)Server-side (full support)
BandwidthHigh (all transactions)Low (only what you request)
Browser Support✅ Native✅ Native
Credit Cost0 credits1-10 credits/request
Use CaseFull network monitoringSpecific account/program queries

Choosing the Right Tool

Use WebSocket when:

  • You need real-time updates as they happen
  • You're building network analytics or explorers
  • You want to process the full transaction stream
  • You need sub-100ms latency

Use REST API when:

  • You need specific account or program data
  • You want server-side filtering
  • You're querying historical data
  • You want to minimize bandwidth usage

Next Steps

Support

Need help with WebSocket streaming?