| name | indexing |
| description | How to read Hyperliquid data — HyperCore via /info API, HyperEVM events, WebSocket subscriptions. Why you cannot just loop through blocks, and what to use instead. |
Hyperliquid Data & Indexing
What You Probably Got Wrong
You try to loop through HyperEVM blocks for data. Scanning blocks is slow and rate-limited. For HyperCore data (order fills, positions, funding), use the /info REST API — it's instant and comprehensive.
You don't know the data lives in two places. HyperCore (perps, spot, order books) has its own API at api.hyperliquid.xyz. HyperEVM has standard EVM events. They're different systems. Know which one has your data.
You try to use eth_getLogs for HyperCore activity. HyperCore trades, fills, and positions don't emit EVM events — they're protocol state. Query them via POST /info.
You treat WebSocket subscriptions as optional. For live trading data (order book, recent trades, fills), use WebSocket at wss://api.hyperliquid.xyz/ws. Polling the REST API for live data is slow and rude.
You store index results onchain. Leaderboards, activity feeds, analytics — these belong offchain. Emit events, index offchain. If you need onchain commitment, store a hash.
Two Data Layers
┌─────────────────────────────────────────────────────────┐
│ HyperCore Data │
│ ├── Perp positions, open orders, fills │
│ ├── Spot balances and trades │
│ ├── Funding rates, mark prices, oracle prices │
│ ├── Account meta (leverage, margin type) │
│ └── Query via: POST https://api.hyperliquid.xyz/info │
├─────────────────────────────────────────────────────────┤
│ HyperEVM Data │
│ ├── ERC-20 balances and transfers │
│ ├── Custom contract events (your contracts) │
│ ├── Smart contract state │
│ └── Query via: JSON-RPC / eth_getLogs / event indexers │
└─────────────────────────────────────────────────────────┘
Reading HyperCore Data
POST /info — The Primary Read API
All reads go to https://api.hyperliquid.xyz/info (mainnet) or https://api.hyperliquid-testnet.xyz/info (testnet).
import axios from 'axios';
const API = 'https://api.hyperliquid.xyz/info';
async function getMeta() {
const { data } = await axios.post(API, { type: 'meta' });
return data;
}
async function getClearinghouseState(address) {
const { data } = await axios.post(API, {
type: 'clearinghouseState',
user: address
});
return data;
}
async function getOpenOrders(address) {
const { data } = await axios.post(API, {
type: 'openOrders',
user: address
});
return data;
}
async () {
{ data } = axios.(, {
: ,
: address
});
data;
}
() {
{ data } = axios.(, {
: ,
coin
});
data;
}
() {
{ data } = axios.(, { : });
data;
}
() {
{ data } = axios.(, {
: ,
: address
});
data;
}
() {
{ data } = axios.(, {
: ,
coin,
startTime
});
data;
}
Python with the Official SDK
from hyperliquid.info import Info
from hyperliquid.utils import constants
info = Info(constants.MAINNET_API_URL)
user_address = "0xYourAddress"
state = info.user_state(user_address)
print(state['assetPositions'])
l2_data = info.l2_snapshot("BTC")
print(l2_data['levels'])
fills = info.user_fills(user_address)
for fill in fills[:10]:
print(f"{fill['coin']} {fill['side']} {fill['sz']} @ {fill['px']}")
mids = info.all_mids()
print(f"BTC mid: {mids.get('BTC')}")
WebSocket Subscriptions
For live data, use wss://api.hyperliquid.xyz/ws.
import WebSocket from 'ws';
const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');
ws.on('open', () => {
ws.send(JSON.stringify({
method: 'subscribe',
subscription: { type: 'l2Book', coin: 'BTC' }
}));
ws.send(JSON.stringify({
method: 'subscribe',
subscription: { type: 'allMids' }
}));
ws.send(JSON.stringify({
method: 'subscribe',
subscription: {
type: 'userFills',
user: '0xYourAddress'
}
}));
ws.send(JSON.stringify({
method: 'subscribe',
subscription: {
type: ,
:
}
}));
});
ws.(, {
msg = .(raw);
(msg. === ) {
{ coin, levels } = msg.;
[bids, asks] = levels;
.();
}
(msg. === ) {
( fill msg..) {
.();
}
}
(msg. === ) {
.(, msg.);
}
});
( {
(ws. === .) {
ws.(.({ : }));
}
}, );
Reading HyperEVM Events (Your Contracts)
For data from your own Solidity contracts, use standard EVM event indexing.
Design Events First
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract TokenLaunch {
event TokenLaunched(
address indexed token,
address indexed creator,
string name,
string symbol,
uint256 timestamp
);
event Trade(
address indexed token,
address indexed trader,
bool isBuy,
uint256 hypeAmount, // HYPE in (buy) or out (sell)
uint256 tokenAmount, // tokens out (buy) or in (sell)
uint256 price, // current price after trade
uint256 timestamp
);
event Graduated(
address indexed token,
uint256 totalHypeRaised,
address lpAddress,
uint256 timestamp
);
}
Querying Events with viem
import { createPublicClient, http, parseAbiItem } from 'viem';
import { defineChain } from 'viem/chains';
const hyperEVM = defineChain({
id: 999,
name: 'HyperEVM',
nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 },
rpcUrls: { default: { http: ['https://rpc.hyperliquid.xyz/evm'] } },
});
const client = createPublicClient({
chain: hyperEVM,
transport: http(),
});
const CONTRACT = '0xYourContractAddress';
const trades = await client.getLogs({
address: CONTRACT,
event: parseAbiItem('event Trade(address indexed token, address indexed trader, bool isBuy, uint256 hypeAmount, uint256 tokenAmount, uint256 price, uint256 timestamp)'),
fromBlock: 0n,
toBlock: 'latest',
});
const tokenTrades = await client.getLogs({
address: ,
: (),
: { : },
: ,
: ,
});
unwatch = client.({
: ,
: (),
: {
( log logs) {
.(, log.);
}
},
});
Building a Simple Indexer with Supabase
import { createPublicClient, http } from 'viem';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_KEY);
const client = createPublicClient({ chain: hyperEVM, transport: http() });
async function indexTrades(fromBlock, toBlock) {
const logs = await client.getLogs({
address: CONTRACT,
events: [TRADE_ABI],
fromBlock,
toBlock,
});
const rows = logs.map(log => ({
tx_hash: log.transactionHash,
block_number: Number(log.blockNumber),
token: log.args.token,
trader: log.args.trader,
is_buy: log.args.isBuy,
hype_amount: log.args.hypeAmount.toString(),
: log...(),
: log...(),
: (log..),
}));
(rows. > ) {
supabase.().(rows, { : });
}
logs.;
}
() {
fromBlock = ();
latestBlock = client.();
( block = fromBlock; block <= latestBlock; block += ) {
toBlock = block + < latestBlock ? block + : latestBlock;
count = (block, toBlock);
.();
(toBlock);
}
}
Supabase Realtime for Live Feeds
Once you're writing events to Supabase, expose them via Realtime:
const channel = supabase
.channel('trades')
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'trades',
}, (payload) => {
console.log('New trade:', payload.new);
updateUI(payload.new);
})
.subscribe();
Key /info Endpoints Reference
| Type | Required Params | Returns |
|---|
meta | none | All perp markets and their properties |
spotMeta | none | All spot assets |
allMids | none | Current mid prices for all assets |
clearinghouseState | user | Positions, margin, withdrawable |
spotClearinghouseState | user | Spot token balances |
openOrders | user | User's open orders |
userFills | user | User's fill history |
orderStatus | user, oid | Single order status |
l2Book | coin | Order book snapshot |
candleSnapshot | coin, interval, startTime, endTime | OHLCV candles |
fundingHistory | coin, startTime | Funding rate history |
userFundingHistory | user, startTime | User's funding payments |
Rules
- HyperCore data →
/info API. Don't use EVM RPC for this.
- Live data → WebSocket. Don't poll REST for live feeds.
- Your contract data →
eth_getLogs + event indexer.
- Store index offchain. Supabase, PostgreSQL, or any database. Never onchain.
- Emit events for everything. If your contract changes state, emit an event. No exceptions.
- Handle reconnects. WebSocket connections drop. Reconnect with exponential backoff and re-subscribe.
- Chunk
eth_getLogs. Query in blocks of 1000-5000. Larger ranges timeout.