Overview

LaserStream’s gRPC offering builds on a Yellowstone-based interface and enhances it with features like historical replay, multi-node failover, and a fully managed environment. LaserStream uses the open source gRPC protocol, ensuring no vendor lock-in and maximum compatibility with existing gRPC implementations. You can connect either directly with @yellowstone-grpc or use the higher-level Helius LaserStream SDK for added benefits (auto-reconnect, subscription management, error handling, etc.).
Performance Notice: If you experience any lag or performance issues with your LaserStream connection, please refer to the Troubleshooting section for common causes and solutions related to client performance and network optimization.

Endpoints & Regions

LaserStream is available in multiple regions worldwide. Choose the endpoint closest to your application for optimal performance:

Mainnet Endpoints

RegionLocationEndpoint
ewrNewark, NJ (near New York)https://laserstream-mainnet-ewr.helius-rpc.com
pittPittsburgh, US (Central)https://laserstream-mainnet-pitt.helius-rpc.com
slcSalt Lake City, US (West Coast)https://laserstream-mainnet-slc.helius-rpc.com
laxLos Angeles, US (West Coast)https://laserstream-mainnet-lax.helius-rpc.com
amsAmsterdam, Europehttps://laserstream-mainnet-ams.helius-rpc.com
fraFrankfurt, Europehttps://laserstream-mainnet-fra.helius-rpc.com
tyoTokyo, Asiahttps://laserstream-mainnet-tyo.helius-rpc.com
sgpSingapore, Asiahttps://laserstream-mainnet-sgp.helius-rpc.com

Devnet Endpoint

NetworkLocationEndpoint
DevnetNewark, NJ (near New York)https://laserstream-devnet-ewr.helius-rpc.com
Network & Region Selection:
  • For production applications, choose the mainnet endpoint closest to your server for best performance. For example, if deploying in Europe, use either the Amsterdam (ams) or Frankfurt (fra) endpoint.
  • For development and testing, use the devnet endpoint: https://laserstream-devnet-ewr.helius-rpc.com.

Quickstart

1

Create a New Project

mkdir laserstream-grpc-demo
cd laserstream-grpc-demo
npm init -y
2

Install Dependencies

npm install helius-laserstream
npm install --save-dev typescript ts-node
npx tsc --init
3

Obtain Your API Key

Generate a key from the Helius Dashboard. This key will serve as your authentication token for LaserStream.
Plan Requirements: LaserStream devnet requires a Developer or Business plan. LaserStream mainnet requires a Professional plan. Ensure your Helius account has the appropriate plan to access LaserStream features.
4

Create a Subscription Script

Create index.ts with the following:
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      client: {
        accountInclude: ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {},
    slots: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    accountsDataSlice: [],
    // Optionally, you can replay missed data by specifying a fromSlot:
    // fromSlot: '224339000'
    // Note: Currently, you can only replay data from up to 3000 slots in the past.
  };

// Replace the values below with your actual LaserStream API key and endpoint
const config: LaserstreamConfig = {
  apiKey: 'YOUR_API_KEY', // Replace with your key from https://dashboard.helius.dev/
  endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // Choose your closest region
}

  await subscribe(config, subscriptionRequest, async (data) => {
    
    console.log(data);

  }, async (error) => {
    console.error(error);
  });
}

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

Replace Your API Key and Choose Your Region

In index.ts, update the config object with:
  1. Your actual API key from the Helius Dashboard
  2. The LaserStream endpoint closest to your server location
const config: LaserstreamConfig = {
  apiKey: 'YOUR_ACTUAL_API_KEY', // Replace with your key from Helius Dashboard
  endpoint: 'https://laserstream-mainnet-fra.helius-rpc.com', // Example: Frankfurt mainnet
  // For devnet: endpoint: 'https://laserstream-devnet-ewr.helius-rpc.com'
}
Network & Region Selection Examples:
  • For Production (Mainnet):
    • Europe: Use fra (Frankfurt) or ams (Amsterdam)
    • US East: Use ewr (New York)
    • US West: Use slc (Salt Lake City)
    • Asia: Use tyo (Tokyo) or sgp (Singapore)
  • For Development (Devnet): Use https://laserstream-devnet-ewr.helius-rpc.com
6

Run and View Results

npx ts-node index.ts
Whenever a confirmed token transaction involves TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA, you’ll see the data in your console.

Subscribe Request

In the subscribe request, you need to include the following general parameters:
Historical Replay: You can optionally include a fromSlot: string field in the main SubscribeRequest object to replay data from a specific slot onwards. Currently, replay is supported for up to 3000 slots in the past.
const subscriptionRequest: SubscribeRequest = {
  commitment: CommitmentLevel.CONFIRMED,
  accountsDataSlice: [],
  transactions: {},
  accounts: {},
  slots: {},
  blocks: {},
  blocksMeta: {},
  entry: {},
}
Next, you’ll need to specify the filters for the data you want to subscribe to, such as accounts, blocks, slots, or transactions.
Define filters for slot updates. The key you use (e.g., mySlotLabel) is a user-defined label for this specific filter configuration, allowing you to potentially define multiple named configurations if needed (though typically one is sufficient).
slots: {
  // mySlotLabel is a user-defined name for this slot update filter configuration
  mySlotLabel: {
    // filterByCommitment: true => Only broadcast slot updates at the specified subscribeRequest commitment
    filterByCommitment: true
    // interslotUpdates: true allows receiving updates for changes occurring within a slot, not just new slots.
    interslotUpdates: true
  }
},
Define filters for account data updates. The key you use (e.g., tokenAccounts) is a user-defined label for this specific filter configuration.If all fields are empty, all accounts are broadcasted. Otherwise:
  • Fields operate as a logical AND.
  • Values within arrays act as a logical OR (except within filters, which operate as a logical AND).
accounts: {
  // tokenAccounts is a user-defined label for this account filter configuration
  tokenAccounts: {
    // Matches any of these public keys (logical OR)
    account: ["9SHQTA66Ekh7ZgMnKWsjxXk6DwXku8przs45E8bcEe38"],
    // Matches owners that are any of these public keys
    owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
    // Filters - all must match (AND logic)
    filters: [
      { dataSize: 165 },
      {
        memcmp: {
          offset: 0,
          data: { base58: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
        }
      }
    ]
  }
},
Define filters for transaction updates. The key you use (e.g., myTxSubscription) is a user-defined label for this specific filter configuration.If all fields are left empty, all transactions are broadcasted. Otherwise:
  • Fields operate as a logical AND.
  • Values within arrays are treated as a logical OR (except for accountRequired, where all must match).
transactions: {
  // myTxSubscription is a user-defined label for this transaction filter configuration
  myTxSubscription: {
    vote: false,
    failed: false,
    signature: "",
    // Transaction must include at least one of these public keys (OR)
    accountInclude: ["86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"],
    // Exclude if it matches any of these
    accountExclude: [],
    // Require all accounts in this array (AND)
    accountRequired: []
  }
},
Define filters for block updates. The key you use (e.g., myBlockLabel) is a user-defined label for this specific filter configuration.
blocks: {
  // myBlockLabel is a user-defined label for this block filter configuration
  myBlockLabel: {
    // Only broadcast blocks referencing these accounts
    accountInclude: ["86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"],
    includeTransactions: true,
    includeAccounts: false,
    includeEntries: false
  }
},
This functions similarly to Blocks but excludes transactions, accounts, and entries. The key you use (e.g., blockmetadata) is a user-defined label for this subscription. Currently, no filters are available for block metadata—all messages are broadcasted by default.
blocksMeta: {
  blockmetadata: {}
},
Subscribe to ledger entries. The key you use (e.g., entrySubscribe) is a user-defined label for this subscription. Currently, there are no filters available for entries; all entries are broadcasted.
entry: {
  entrySubscribe: {}
},

Code Examples (LaserStream SDK)

import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
    const subscriptionRequest: SubscribeRequest = {
        transactions: {},
        commitment: CommitmentLevel.CONFIRMED,
        accounts: {},
        slots: {
            slot: { filterByCommitment: true },
        },
        transactionsStatus: {},
        blocks: {},
        blocksMeta: {},
        entry: {},
        accountsDataSlice: [],
    };

    const config: LaserstreamConfig = {
        apiKey: 'YOUR_API_KEY', // Replace with your key
        endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // Choose your closest region
    }

    await subscribe(config, subscriptionRequest, async (data) => {
        console.log(data);
    }, async (error) => {
        console.error(error);
    });
}

main().catch(console.error);

SDK Options

We provide official SDKs for multiple programming languages: For other languages or custom implementations, you can use the Yellowstone gRPC proto files directly to generate gRPC clients for your preferred language.

Troubleshooting / FAQ

A: Performance issues with LaserStream connections are typically caused by:
  • Javascript Client Slowness: The JavaScript client may lag behind when processing too many messages or consuming too much bandwidth. Consider filtering your subscriptions more narrowly to reduce message volume or using another language.
  • Limited local bandwidth: Heavy subscriptions can overwhelm clients with limited network bandwidth. Monitor your network usage and consider upgrading your connection or reducing subscription scope.
  • Geographic distance: Running subscriptions against servers that are geographically far away can cause performance issues. TCP packets may get dropped on long routes, and you’re limited by the slowest intermediate network path. Solution: Choose the LaserStream endpoint closest to your server location from our available regions (see Endpoints & Regions above).
  • Client-side processing bottlenecks: Ensure your message processing logic is optimized and doesn’t block the main thread for extended periods.
Debugging Client Lag: To help you debug client, we built a tool to test for the max bandwidth from your node to a Laserstream gRPC server. To use it run:
cargo install helius-laserstream-bandwidth
helius-laserstream-bandwidth --laserstream-url $LASERSTREAM_URL --api-key $API_KEY
The output returns the max network capacity between your server and the Laserstream server. At a minimum, you need 10MB/s to subscribe to all transaction data and 80MB/s to subscribe to all account data. We recommend having at least 2x the required capacity for optimal performance.
A: Verify your API key and endpoint are correct and that your network allows outbound gRPC connections to the specified endpoint. Check the Helius status page for any ongoing incidents.
A: Double-check the logical operators (AND/OR) described in the filter sections. Ensure public keys are correct. Review the commitment level specified in your request.
A: Yes, you can define filter configurations under multiple keys (e.g., accounts, transactions) within the same SubscribeRequest object.
A: We don’t implement consumer groups. Instead, LaserStream delivers the same outcomes teams want: resume, replay, and multi-node reliability without a coordination layer (and the latency/overhead that comes with it). We believe consumer groups are not needed for most workloads and they add latency and operational overhead. As an example a single LaserStream gRPC connection can emit up to 10× Solana’s transaction + account data, and most clients subscribe to a small, filtered slice. Using consumer groups in this case burns performance headroom and introduces another point of failure.