A Hyperliquid vault is a pooled account: depositors receive shares, and their economic position is shares multiplied by share price, not a stored dollar balance. The info API exposes this through two distinct read paths: an account-scoped read that returns a user's share count and attributable equity, and a vault-scoped read that returns the vault's aggregate state including total value and depositor set. Because deposits, withdrawals, and trading PnL all move both total value and outstanding shares, a performance figure computed from raw equity alone conflates cash flows with returns; the only measure that isolates manager performance is share-price change. This article shows how to read both paths, reconcile shares against total shares, derive value per share, snapshot it over time, and separate the failure classes that produce empty results, missing rows, or internally inconsistent responses.
Two Read Paths: Account-Scoped vs Vault-Scoped
The info endpoint exposes two distinct read paths that answer different questions. The account-scoped read returns the caller's or a watched address's positions in vaults, including that address's share count and the equity attributable to it. The vault-scoped read returns the vault's aggregate state, including total value and the depositor set. A caller that wants 'how is this vault doing' and a caller that wants 'what is this user's exposure' must not use the same request.
The Hyperliquid info endpoint Hyperliquid info endpoint documentation lists the request types and their parameters. Treat the exact request names and response fields as documented / varies by API version, and confirm them against the live response before hard-coding. The Hyperliquid RPC endpoints (RPC Assistant) page is a useful starting point for endpoint selection, and the Hyperliquid clearinghouseState: margin and liquidation article covers the perp-side read that is often confused with vault equity.
- Account-scoped read: user's vault positions, share count, attributable equity.
- Vault-scoped read: vault aggregate state, total value, depositor set.
- Do not use one request to answer both questions.
- Confirm request names and fields against the live response.
Vault Equity vs Spot and Perp Account Equity
clearinghouseState reports perp account value and margin, spot balances are a separate surface, and a vault position is a third thing again. Summing them without deduplicating collateral double-counts and produces a wrong total, which is the single most common error in vault dashboards. The vault's collateral is already reflected in the vault's total value; the depositor's claim is a fraction of that, not an additional balance.
If you need a consolidated view, decide explicitly whether you are reporting the vault's total value, the depositor's attributable equity, or both side by side. Reporting both is fine as long as you label them and never add them. The Hyperliquid funding rate mechanics and Hyperliquid oracle price and builder auction info articles cover adjacent reads that are also easy to conflate with vault state.
- clearinghouseState = perp account value and margin.
- Spot balances = separate surface.
- Vault position = third surface; do not sum without deduplication.
- Label vault total value and depositor attributable equity separately.
Reading Vault Aggregate State and Account Position in Node.js
The script below reads a vault's aggregate state and an account's vault position over the info endpoint, reconciles share count against total shares, derives value per share, snapshots it, and prints a table. It uses a single POST per request and keeps the two reads separate so the reconciliation is explicit. Replace the endpoint and request names with the values documented for your API version.
Because the info endpoint answers about current state, the script's snapshot store is the historian. Run it on a schedule and append each reading to a file or database; a single reading is not a performance measurement.
// Node.js 18+ (global fetch). Replace endpoint and request names with your API version.
const ENDPOINT = process.env.HL_INFO_ENDPOINT || 'https://api.hyperliquid.xyz/info';
const VAULT = process.env.HL_VAULT_ADDRESS || '0xVaultAddress';
const ACCOUNT = process.env.HL_ACCOUNT_ADDRESS || '0xAccountAddress';
async function info(body) {
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(body)
});
if (!res.ok) throw new Error('HTTP ' + res.status + ' ' + (await res.text()));
return res.json();
}
function num(x) {
const n = Number(x);
return Number.isFinite(n) ? n : null;
}
async function main() {
// Vault-scoped read: aggregate state. Request name varies by API version.
const vaultState = await info({ type: 'vaultDetails', vaultAddress: VAULT });
// Account-scoped read: this address's vault positions.
const accountState = await info({ type: 'userVaultEquities', user: ACCOUNT });
const totalValue = num(vaultState?.totalValue ?? vaultState?.value);
const totalShares = num(vaultState?.totalShares ?? vaultState?.shares);
const sharePrice = (totalValue !== null && totalShares) ? totalValue / totalShares : null;
const rows = Array.isArray(accountState) ? accountState : (accountState?.vaultEquities || []);
const row = rows.find(r => (r.vaultAddress || r.vault || '').toLowerCase() === VAULT.toLowerCase());
const accountShares = row ? num(row.shares ?? row.vaultShares) : null;
const accountEquity = row ? num(row.equity ?? row.vaultEquity) : null;
const reconciledEquity = (accountShares !== null && sharePrice !== null)
? accountShares * sharePrice : null;
const snapshot = {
ts: new Date().toISOString(),
vault: VAULT,
totalValue, totalShares, sharePrice,
accountShares, accountEquity, reconciledEquity
};
console.log('vault | totalValue | totalShares | sharePrice | accountShares | accountEquity | reconciledEquity');
console.log([
snapshot.vault, snapshot.totalValue, snapshot.totalShares,
snapshot.sharePrice, snapshot.accountShares,
snapshot.accountEquity, snapshot.reconciledEquity
].join(' | '));
// Append to your own snapshot store; this is the historian.
const fs = require('fs');
fs.appendFileSync('vault-snapshots.ndjson', JSON.stringify(snapshot) + '\n');
}
main().catch(e => { console.error(e); process.exit(1); });Building a Time Series and Measuring Performance
A single share-price reading is not a performance measurement. The reader must sample and store readings, and because the info endpoint answers about current state, the reader's own snapshot store is the historian. The measurement method is reproducible: sample at a fixed cadence, store each snapshot, and compute share-price change over the window.
The table below is a template to fill with your own endpoint's results. Do not compare your numbers to anyone else's; derived performance depends on your sampling cadence and is not comparable across implementations.
- Sample at a fixed cadence (for example, every 5 minutes).
- Store each snapshot with a timestamp.
- Compute share-price change over the window.
- Report the cadence alongside the result.
Results Table (fill with your own endpoint's readings)
| Timestamp (UTC) | Vault | Total Value | Total Shares | Share Price | Account Shares | Account Equity | Reconciled Equity |
|-----------------|-------|-------------|--------------|-------------|----------------|----------------|-------------------|
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
Derived performance over the window:
sharePriceChange = (lastSharePrice - firstSharePrice) / firstSharePrice
cadence = <your sampling interval>
note = not comparable across implementationsFailure Classes and Troubleshooting
Separate the failure classes before debugging. A vault identifier that does not exist returns an empty result rather than an error. An account with no position in a vault returns a missing row rather than a zero. An API version whose field names differ from the documentation returns a response that parses but yields nulls. A response that is internally inconsistent was read across two calls during a state transition, which is why a single snapshot should be taken as close to atomically as the API allows.
For order-level failures, the Hyperliquid API error handling and order rejections article covers the rejection surface. For endpoint selection and connectivity, see Hyperliquid RPC endpoints (RPC Assistant) and the Hyperliquid network page.
- Empty result: vault identifier does not exist.
- Missing row: account has no position in the vault.
- Nulls after parse: field names differ from documentation.
- Inconsistent response: reads taken across a state transition.
- Re-read rather than average when reconciliation fails.
Limitations and Tradeoffs
Nothing here is investment advice. Derived performance depends on the reader's own sampling cadence and therefore is not comparable across implementations. Vault fees and manager share terms must be read from the vault's own configuration rather than inferred from equity or share-price movement. Field availability is provider- and version-dependent, so the request names and response fields shown here are documented / varies by API version and must be verified against the live response.
The info endpoint answers about current state, so any historical view is the reader's own construction. That construction is only as good as its cadence and its handling of gaps. If you need a consolidated portfolio view, decide explicitly how you will avoid double-counting collateral across perp, spot, and vault surfaces.
- Not investment advice.
- Derived performance is cadence-dependent and not comparable across implementations.
- Vault fees and manager share terms come from the vault's own configuration.
- Field availability is provider- and version-dependent.
- Historical views are the reader's own construction.
Next Steps for Integration
Start by confirming the request names and response fields against the live response for your API version. Then wire the two read paths into your client, add the reconciliation check, and begin sampling on a fixed cadence. Once you have a few days of snapshots, compute share-price change over the window and report the cadence alongside the result.
For production access, review RPC pricing and the API service page, and browse the OnFinality Learn hub for adjacent Hyperliquid reads. The Hyperliquid network page lists the endpoints and network details you will need.
- Confirm request names and fields against the live response.
- Wire both read paths and add the reconciliation check.
- Sample on a fixed cadence and store snapshots.
- Compute share-price change and report the cadence.
- Review pricing and API service pages for production access.