Get Started
Solana RPC Nodes
Dedicated Nodes
Data Streaming & Event Listening
- Overview
- Quickstart
- LaserStream
- Enhanced Websockets (Beta)
- Yellowstone gRPC
- Standard Websockets
- Webhooks
Sending Transactions
Getting Data Using Helius APIs
- Overview
- Get Assets
- Search Assets
- Enhanced Transactions API
- Digital Asset Standard (DAS)
Resources
LaserStream gRPC
Highly configurable real-time data streams using gRPC.
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. You can connect either directly with @yellowstone-grpc
or use the higher-level Helius Laserstream client for added benefits (auto-reconnect, subscription management, error handling, etc.).
Quickstart
Create a New Project
mkdir laserstream-grpc-demo
cd laserstream-grpc-demo
npm init -y
Install Dependencies
npm install helius-laserstream
npm install --save-dev typescript ts-node
npx tsc --init
Obtain Your API Key
Generate a key from the Helius Dashboard.
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: 'YOUR_ENDPOINT', // Replace with your endpoint from https://dashboard.helius.dev/
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
Replace Your Endpoint and API Key
In index.ts
, update the config
object with the actual apiKey
and endpoint
from your Helius Dashboard:
const config: LaserstreamConfig = {
apiKey: 'YOUR_ACTUAL_API_KEY', // Replace with your key
endpoint: 'YOUR_ACTUAL_ENDPOINT', // Replace with your endpoint
}
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
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: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
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: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'
async function main() {
const subscribeRequest: SubscribeRequest = {
accounts: {
accountSubscribe: {
account: ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"], // USDC mint account
owner: [],
filters: []
}
},
accountsDataSlice: [],
commitment: CommitmentLevel.CONFIRMED,
slots: {},
transactions: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {}
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY', // Replace with your key
endpoint: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscribeRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
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: [],
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY', // Replace with your key
endpoint: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'
async function main() {
const subscriptionRequest: SubscribeRequest = {
entry: {},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {
blocks: {
accountInclude: []
}
},
blocksMeta: {},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel.CONFIRMED,
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY', // Replace with your key
endpoint: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'
async function main() {
const subscriptionRequest: SubscribeRequest = {
entry: {},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {},
blocksMeta: {
blockmetadata: {}
},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel.CONFIRMED,
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY', // Replace with your key
endpoint: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'
async function main() {
const subscriptionRequest: SubscribeRequest = {
entry: {
entrySubscribe: {} // Subscribe to all entries
},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {},
blocksMeta: {},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel.CONFIRMED,
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY', // Replace with your key
endpoint: 'YOUR_ENDPOINT', // Replace with your endpoint
}
await subscribe(config, subscriptionRequest, async (data) => {
console.log(data);
}, async (error) => {
console.error(error);
});
}
main().catch(console.error);
Troubleshooting / FAQ
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.
Was this page helpful?