A fully-typed TypeScript client for the Glassnode API β on-chain and market data for Bitcoin, Ethereum, and hundreds of crypto assets. Responses are runtime-validated with Zod, and it runs in both Node.js and the browser.
import { GlassnodeAPI } from 'glassnode-api';
const api = new GlassnodeAPI({ apiKey: 'YOUR_API_KEY' });
const btcPrice = await api.callMetric('/market/price_usd_close', { a: 'BTC' });- π§© Fully typed β complete TypeScript definitions for every request and response
- β Runtime-validated β responses parsed and validated with Zod, so bad data fails fast
- π Universal β works in Node.js and the browser (UMD + ESM bundles, tree-shakeable)
- π Built-in retries β automatic retry with exponential backoff for
429and5xx - π¦ Bulk endpoints β fetch every asset in a single call with
callBulkMetric() - π― Typed errors β
GlassnodeApiErrorwithstatus,statusText, andisRetryable - πͺΆ Lightweight β a single runtime dependency (
zod) - π Pluggable β inject a custom
fetchimplementation and alogger
- Installation
- Quick Start
- Configuration
- Methods
- Error Handling
- Retries
- Bulk Metrics
- Paid calls with x402
- Browser
- Examples
- Development
- License
# pnpm
pnpm add glassnode-api
# npm
npm install glassnode-api
# yarn
yarn add glassnode-apiYou'll need a Glassnode API key β create one from your Glassnode account.
import { GlassnodeAPI } from 'glassnode-api';
const api = new GlassnodeAPI({
apiKey: 'YOUR_API_KEY',
// apiUrl: 'https://api.glassnode.com', // optional override
});
// Fetch metadata for all supported assets
const assets = await api.getAssetMetadata();
// Fetch metadata for a specific metric
const metric = await api.getMetricMetadata('/distribution/balance_exchanges', { a: 'BTC' });
// List every available metric path
const metrics = await api.getMetricList();
// Call any metric endpoint directly
const data = await api.callMetric('/market/price_usd_close', {
a: 'BTC',
s: '1609459200', // since (unix timestamp)
});new GlassnodeAPI(config)
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
β (required unless x402) |
Your Glassnode API key |
apiUrl |
string |
https://api.glassnode.com |
Base URL for the API |
x402 |
boolean |
false |
Route through the paid x402 endpoint (see Paid calls with x402) |
logger |
(message: string, ...args: unknown[]) => void |
β | Callback for debug logging (e.g. console.log) |
fetch |
typeof fetch |
globalThis.fetch |
Custom fetch implementation (or an x402-wrapped fetch) |
maxRetries |
number |
0 |
Retries for retryable errors (429, 5xx) |
retryDelay |
number |
1000 |
Base delay in ms between retries (doubles each attempt) |
The config is validated at construction time with Zod β an invalid config (e.g. an empty apiKey) throws immediately. When x402 is enabled, apiKey is optional but a payment-capable fetch is required. Failed requests throw a GlassnodeApiError whose message includes the server's error detail (also on .detail).
| Method | Returns | Description |
|---|---|---|
getAssetMetadata() |
Promise<AssetMetadataResponse> |
Metadata for all supported assets |
getMetricMetadata(path, params?) |
Promise<MetricMetadataResponse> |
Metadata for a specific metric |
getMetricList() |
Promise<MetricListResponse> |
List of all available metric paths |
callMetric<T>(path, params?) |
Promise<T> |
Call any metric endpoint directly |
callBulkMetric(path, params?) |
Promise<BulkResponse> |
Call a bulk endpoint (all assets in one response) |
All response types are exported and fully typed.
Failed requests throw a GlassnodeApiError with the HTTP status, the status text, and a human-readable
message. Network failures are re-thrown as an Error with the original error preserved on .cause.
import { GlassnodeAPI, GlassnodeApiError } from 'glassnode-api';
try {
await api.callMetric('/market/price_usd_close', { a: 'BTC' });
} catch (err) {
if (err instanceof GlassnodeApiError) {
console.error(err.status); // e.g. 401
console.error(err.statusText); // e.g. "Unauthorized"
console.error(err.isRetryable); // true for 429 / 5xx
console.error(err.message); // "API request failed (401): Invalid or missing API key"
}
}Enable automatic retries with exponential backoff for rate limits (429) and server errors (5xx):
const api = new GlassnodeAPI({
apiKey: 'YOUR_API_KEY',
maxRetries: 3, // retry up to 3 times
retryDelay: 1000, // 1s, then 2s, then 4s
});Non-retryable errors (e.g. 401, 404) fail immediately without retrying.
callBulkMetric() returns a value for every asset at each timestamp in a single request β ideal for
snapshots across the whole market:
const marketcaps = await api.callBulkMetric('/market/marketcap_usd');
// [{ t: 1609459200, bulk: [{ a: 'BTC', v: 600000000000 }, { a: 'ETH', v: 100000000000 }] }]Glassnode also serves a paid, per-call API over the x402 protocol at
https://x402.glassnode.com β no API key required, you pay per request in USDC on Base
($0.01/metadata call, $0.05/metric call). This is Node-first and opt-in: the crypto stack
(@x402/fetch, @x402/evm, viem) is an optional peer dependency, installed only if you use it.
pnpm add glassnode-api @x402/fetch @x402/evm viemimport { GlassnodeAPI } from 'glassnode-api';
import { createX402Fetch } from 'glassnode-api/x402';
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const api = new GlassnodeAPI({
x402: true, // β https://x402.glassnode.com
fetch: await createX402Fetch({
account,
maxPaymentPerCall: '0.06', // USDC per-call ceiling (default)
}),
});
// Pays $0.05 USDC on Base, transparently:
const mvrv = await api.callMetric('/market/mvrv', { a: 'BTC', i: '24h' });createX402Fetch(options)
| Option | Type | Default | Description |
|---|---|---|---|
account |
LocalAccount |
β (required) | viem account that signs payments |
maxPaymentPerCall |
string |
'0.06' |
Per-call USDC spend ceiling |
fetch |
typeof fetch |
globalThis.fetch |
Base fetch to wrap |
Spend safety:
maxPaymentPerCallcaps a single request β it is not a cumulative budget, so an agent loop can still spend within that ceiling repeatedly. Use a dedicated, funded-but-limited wallet (never your primary key), and load the key from the environment β never hardcode it.
Notes
- Bulk metrics are not available over x402 β
callBulkMetric()only works against the freeapi.glassnode.com. - Other endpoints: target a non-default x402 endpoint (e.g. a testnet) by passing its URL as
apiUrl. - Browser signing is not supported yet (planned).
The library ships prebuilt UMD and ESM bundles, so it also runs directly in the browser without a build step.
<!-- UMD -->
<script src="https://unpkg.com/glassnode-api/dist/glassnode-api.umd.min.js"></script>
<script>
const api = new GlassnodeAPI.GlassnodeAPI({ apiKey: 'YOUR_API_KEY' });
</script><!-- ESM -->
<script type="module">
import { GlassnodeAPI } from 'https://unpkg.com/glassnode-api/dist/glassnode-api.esm.min.js';
const api = new GlassnodeAPI({ apiKey: 'YOUR_API_KEY' });
</script>Your API key is exposed to end users in browser code. Only ship it in trusted, first-party contexts β otherwise proxy Glassnode requests through your own backend.
See the examples directory for detailed usage patterns.
cd examples
cp .env.example .env # add your API key
pnpm dlx ts-node ex.metadata.validation.tspnpm install # install dependencies
pnpm run build && pnpm run build:browser # build Node.js + browser bundles
pnpm test # run tests (Vitest)
pnpm run lint # lint
pnpm run format # format