Skip to main content

Making Hyperliquid gRPC Requests with Node.js

Updated on
Jan 08, 2026

Overview

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine, perfect for building scalable network applications. Follow the official installation guide to install Node.js. Verify the installation:

node --version
npm --version

Initiating the Node.js Project for Hyperliquid gRPC

Step 1: Initialize Node.js Project

Create a dedicated directory for your Hyperliquid gRPC project and navigate into it:

mkdir hyperliquid-grpc-nodejs
cd hyperliquid-grpc-nodejs
npm init -y

Step 2: Install Dependencies

Install the necessary Node.js dependencies for gRPC and Protocol Buffers:

# Install gRPC and Protocol Buffers packages
npm install @grpc/grpc-js @grpc/proto-loader

# For TypeScript support (optional)
npm install -D typescript @types/node ts-node

# For development
npm install -D nodemon

Step 3: Create Proto Files

Create the proto directory and add the Hyperliquid streaming protocol definition:

# Create proto directory
mkdir -p proto

Create a new file named proto/streaming.proto and add the following content:

syntax = "proto3";
package hyperliquid;

service Streaming {
// Bi-directional streaming
rpc StreamData (stream SubscribeRequest) returns (stream SubscribeUpdate);
rpc Ping (PingRequest) returns (PingResponse);
}

service BlockStreaming {
// Stream replica_cmds (raw blocks)
rpc StreamBlocks (Timestamp) returns (stream Block);
}

// --- Requests ---
message SubscribeRequest {
oneof request {
StreamSubscribe subscribe = 1;
Ping ping = 3;
}
reserved 2;
}

message StreamSubscribe {
StreamType stream_type = 1;
uint64 start_block = 2;

// Generic filters - field name to allowed values
// Recursively searches each event for matching field/value pairs
// Example: {"coin": ["ETH", "BTC"], "user": ["0x123..."], "type": ["deposit"]}
map<string, FilterValues> filters = 3;

// Optional name for this filter
// Allows multiple independent filters per stream (OR logic)
string filter_name = 4;
}

// Container for filter values
message FilterValues {
repeated string values = 1;
}

message Ping { int64 timestamp = 1; }

// --- Responses ---
message SubscribeUpdate {
oneof update {
StreamResponse data = 1;
Pong pong = 2;
}
}

message StreamResponse {
uint64 block_number = 1;
uint64 timestamp = 2; // Server ingress timestamp

// Raw JSON data from the file (Exact replica of source)
string data = 3;
}

// --- Data Types ---
enum StreamType {
UNKNOWN = 0;
TRADES = 1;
ORDERS = 2;
BOOK_UPDATES = 3;
TWAP = 4;
EVENTS = 5;
BLOCKS = 6;
WRITER_ACTIONS = 7;
}

message Block {
string data_json = 1;
}

message Pong { int64 timestamp = 1; }
message Timestamp { int64 timestamp = 1; }
message PingRequest { int32 count = 1; }
message PingResponse { int32 count = 1; }

Step 4: Create Main Application (JavaScript)

Create your main application file to test the connection:

Create index.js:

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const path = require('path');

// Configuration
const GRPC_ENDPOINT = 'your-grpc-endpoint:port';
const AUTH_TOKEN = 'your-auth-token';

// Load proto file
const packageDefinition = protoLoader.loadSync(
path.join(__dirname, 'proto/streaming.proto'),
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
}
);

const hyperliquidProto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;

// Create gRPC client with TLS
function createClient() {
const credentials = grpc.credentials.createSsl();

const client = new hyperliquidProto.Streaming(
GRPC_ENDPOINT,
credentials,
{
'grpc.max_receive_message_length': 100 * 1024 * 1024, // 100MB
}
);

return client;
}

// Create metadata with auth token
function createMetadata() {
const metadata = new grpc.Metadata();
metadata.add('x-token', AUTH_TOKEN);
return metadata;
}

// Test connectivity with ping
function testPing(client) {
return new Promise((resolve, reject) => {
const metadata = createMetadata();

client.Ping({ count: 1 }, metadata, (error, response) => {
if (error) {
reject(new Error(`Ping failed: ${error.message}`));
return;
}

console.log('✅ Ping successful:', response);
resolve(response);
});
});
}

// Main function
async function main() {
try {
console.log(`Testing connection to: ${GRPC_ENDPOINT}`);

// Create client
const client = createClient();

// Test connectivity
await testPing(client);

console.log('✅ Connection test completed successfully!');

// Close the client
client.close();

} catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}
}

// Run the application
main();

Step 5: Create TypeScript Version (Optional)

If you prefer TypeScript, create index.ts:

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import * as path from 'path';

// Configuration
const GRPC_ENDPOINT = 'your-grpc-endpoint:port';
const AUTH_TOKEN = 'your-auth-token';

// Load proto file
const packageDefinition = protoLoader.loadSync(
path.join(__dirname, 'proto/streaming.proto'),
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
}
);

const hyperliquidProto = grpc.loadPackageDefinition(packageDefinition) as any;

interface PingRequest {
count: number;
}

interface PingResponse {
count: number;
}

// Create gRPC client with TLS
function createClient(): any {
const credentials = grpc.credentials.createSsl();

const client = new hyperliquidProto.hyperliquid.Streaming(
GRPC_ENDPOINT,
credentials,
{
'grpc.max_receive_message_length': 100 * 1024 * 1024, // 100MB
}
);

return client;
}

// Create metadata with auth token
function createMetadata(): grpc.Metadata {
const metadata = new grpc.Metadata();
metadata.add('x-token', AUTH_TOKEN);
return metadata;
}

// Test connectivity with ping
function testPing(client: any): Promise<PingResponse> {
return new Promise((resolve, reject) => {
const metadata = createMetadata();

client.Ping({ count: 1 }, metadata, (error: grpc.ServiceError | null, response: PingResponse) => {
if (error) {
reject(new Error(`Ping failed: ${error.message}`));
return;
}

console.log('✅ Ping successful:', response);
resolve(response);
});
});
}

// Main function
async function main(): Promise<void> {
try {
console.log(`Testing connection to: ${GRPC_ENDPOINT}`);

// Create client
const client = createClient();

// Test connectivity
await testPing(client);

console.log('✅ Connection test completed successfully!');

// Close the client
client.close();

} catch (error) {
console.error('❌ Error:', (error as Error).message);
process.exit(1);
}
}

// Run the application
main();

Step 6: Update package.json Scripts

Add helpful scripts to your package.json:

{
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"ts:start": "ts-node index.ts",
"ts:dev": "nodemon --exec ts-node index.ts",
"build": "tsc"
}
}

Step 7: Create TypeScript Config (if using TypeScript)

If using TypeScript, create tsconfig.json:

{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "dist"]
}

Step 8: Run the Application

Build and execute your application to test the gRPC connection:

For JavaScript:

npm start
# or for development with auto-reload
npm run dev

For TypeScript:

npm run ts:start
# or for development with auto-reload
npm run ts:dev

Step 9: Verify Setup

Confirm that your setup is working correctly by checking the output:

Testing connection to: docs-demo.hype-mainnet.quiknode.pro:10000
Ping successful: { count: 1 }
Connection test completed successfully!

If everything is set up correctly, you should see:

  • Connection established to the gRPC endpoint
  • Successful ping response
  • No compilation or runtime errors

We ❤️ Feedback!

If you have any feedback or questions about this documentation, let us know. We'd love to hear from you!

Share this doc