Summary
Bittensor is a decentralized machine learning network where miners serve models and validators score them, all coordinated on the Finney mainnet built by the OpenTensor Foundation. To read chain state, submit extrinsics, or track subnet activity, your application needs a reliable RPC endpoint that speaks Substrate JSON-RPC over HTTP and WebSocket. This page explains how to connect, what to check before you commit, and how to keep your integration stable as subnets and traffic grow.
Bittensor is a decentralized network for machine learning, coordinated by the OpenTensor Foundation and running on the Finney mainnet. Miners register models on subnets, validators score those models, and TAO flows between them according to the network's incentive mechanism. If you are building a dashboard, a subnet explorer, a validator tool, or a miner monitoring script, you need to read and write to that chain — which means you need an RPC endpoint.
This page focuses on the practical side: how to connect to Bittensor over JSON-RPC, what to check before you pick an endpoint, and how to keep your integration stable as subnets and traffic grow. It is written for developers who already understand the basics of Substrate-based chains and want a working connection plus a clear way to decide between public, shared, and dedicated infrastructure.
Which Bittensor endpoint fits your workload?
Before you copy an endpoint, match it to what your application actually does. Bittensor traffic is unusual because a lot of it is read-heavy polling of subnet state, metagraph data, and stake balances, often at high frequency.
| Workload | Typical calls | What to prioritize |
|---|---|---|
| Subnet explorer or dashboard | chain_getBlock, state_getStorage, metagraph reads | Consistent throughput and stable latency under many concurrent reads |
| Miner or validator monitoring | system_health, author_pendingExtrinsics, balance reads | Frequent polling without hitting shared rate limits |
| Wallet or staking UI | author_submitExtrinsic, system_dryRun | Reliable write path and predictable confirmation handling |
| Indexer or analytics pipeline | Historical block and event reads | Archive access and the ability to backfill from genesis |
| Real-time alerting | New block and event subscriptions | WebSocket support with reconnect handling |
If your workload is exploratory — a script that runs a few times a day — a public endpoint is usually enough to start. If you are running a dashboard with many users, a monitoring loop that polls every few seconds, or an indexer that needs historical state, a shared or dedicated endpoint will save you from the failure modes described later in this article.
OnFinality provides Bittensor (Finney) RPC over both HTTP and WebSocket, alongside a range of other supported RPC networks. You can compare plans on the RPC pricing page, or move to isolated resources with a dedicated node if you need predictable capacity.
Chain settings at a glance
Bittensor is a Substrate-based chain, so it uses the standard Substrate JSON-RPC interface rather than the Ethereum JSON-RPC method set. Keep these settings handy when configuring wallets, SDKs, and monitoring tools.
| Setting | Value |
|---|---|
| Network | Bittensor Finney Mainnet |
| Native currency | TAO (9 decimals) |
| Transport | HTTP and WebSocket |
| RPC interface | Substrate JSON-RPC |
| Public HTTP endpoint | https://bittensor-finney.api.onfinality.io/public |
| Public WebSocket endpoint | wss://bittensor-finney.api.onfinality.io/public-ws |
Because the native currency uses 9 decimals, remember to scale TAO amounts by 1e9 when you convert between planck-style integers and human-readable values. A common bug in Bittensor tooling is displaying raw balances without that scaling, which makes stake and emission numbers look wrong by nine orders of magnitude.
Making your first JSON-RPC calls
Substrate chains expose a small set of core methods that most tooling relies on. Start with a health check and a chain identity read to confirm your endpoint is live and pointed at the right network.
# Confirm the node is healthy and synced
curl -s https://bittensor-finney.api.onfinality.io/public \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}'
# Read the chain name to verify you are on Finney mainnet
curl -s https://bittensor-finney.api.onfinality.io/public \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"system_chain","params":[]}'
A healthy response returns isSyncing: false and a peer count. If isSyncing is true, the node is still catching up and reads may be stale — do not treat its state as final.
For application code, the Polkadot.js API is the most common way to talk to Bittensor. It handles the metadata, type registry, and SCALE encoding for you, which matters because raw state_getStorage calls require you to know storage keys and types.
import { ApiPromise, WsProvider } from '@polkadot/api';
const provider = new WsProvider('wss://bittensor-finney.api.onfinality.io/public-ws');
const api = await ApiPromise.create({ provider });
const [chain, health] = await Promise.all([
api.rpc.system.chain(),
api.rpc.system.health(),
]);
console.log('Chain:', chain.toString());
console.log('Syncing:', health.isSyncing.toString());
// Read the current block number
const header = await api.rpc.chain.getHeader();
console.log('Latest block:', header.number.toNumber());
Once connected, you can query subnet and stake state through the runtime modules. The exact storage keys and call names depend on the current runtime, so always read them from the live metadata rather than hard-coding values from an old tutorial.
Reading subnet and metagraph data
Most Bittensor applications care about subnet-level data: which neurons are registered, what their incentive and emission values are, and how stake is distributed. This data lives in runtime storage and is best accessed through the API's typed queries rather than raw storage keys.
// Iterate registered neurons on a subnet (structure depends on runtime version)
const entries = await api.query.subtensorModule.neurons.entries(1);
for (const [key, value] of entries) {
const uid = key.args[1].toString();
console.log('UID:', uid, 'Incentive:', value.incentive.toString());
}
Two practical notes. First, metagraph reads can be large — iterating every neuron on a busy subnet returns a lot of data, so paginate or filter where the runtime allows it. Second, subnet identifiers and module names have changed across runtime upgrades. Pin your client library version and test after every network upgrade, because a renamed storage item will silently break a query that used to work.
WebSocket subscriptions for live data
If you are building anything that reacts to new blocks or events — an alerting bot, a live dashboard, a miner that watches for registration changes — polling over HTTP will not scale well. Use a WebSocket subscription instead.
const provider = new WsProvider('wss://bittensor-finney.api.onfinality.io/public-ws');
const api = await ApiPromise.create({ provider });
// React to every new block
const unsub = await api.rpc.chain.subscribeNewHeads((header) => {
console.log('New block:', header.number.toNumber());
});
// React to specific events as they are included
const unsubEvents = await api.query.system.events((events) => {
events.forEach(({ event }) => {
if (api.events.subtensorModule?.RegistrationAllowed?.is(event)) {
console.log('Registration event detected');
}
});
});
WebSocket connections drop. Networks blip, laptops sleep, and load balancers recycle connections. Always implement reconnect logic with backoff, and re-subscribe after reconnecting. A subscription that silently stops delivering blocks is worse than an error, because your application keeps running on stale data.
Common failure modes and how to debug them
Most Bittensor RPC problems fall into a handful of patterns. Here is how to recognize and fix them.
| Symptom | Likely cause | What to do |
|---|---|---|
isSyncing: true for a long time | Node is behind or catching up | Wait, or switch to a fully synced endpoint |
| Reads return stale block numbers | Endpoint is lagging the chain head | Compare block height across two endpoints |
state_getStorage returns null | Wrong storage key or renamed module | Read keys from live metadata, not old docs |
| Balances look off by 1e9 | Missing decimal scaling for TAO | Scale raw values by 1e9 before display |
| WebSocket stops delivering | Dropped connection, no reconnect | Add backoff reconnect and re-subscribe |
| Intermittent 429 responses | Shared endpoint rate limiting | Reduce polling frequency or move to a dedicated endpoint |
| Extrinsic rejected | Nonce or fee issue | Re-read nonce, check balance, use system_dryRun |
A quick diagnostic habit: when something looks wrong, query system_health and chain_getHeader on two different endpoints and compare. If the block heights differ, you have a sync or lag problem, not a bug in your code.
Evaluating a Bittensor RPC provider
Once you move past a quick prototype, the endpoint becomes part of your production surface. These are the criteria that actually matter for Bittensor workloads.
| Criterion | Why it matters for Bittensor |
|---|---|
| HTTP and WebSocket support | Substrate tooling uses both; polling-only endpoints limit real-time features |
| Archive access | Indexers and analytics need historical state, not just the chain head |
| Throughput under concurrent reads | Metagraph and subnet queries are read-heavy and bursty |
| Rate limit transparency | You need to know when you will be throttled before it happens |
| Runtime upgrade handling | Bittensor upgrades change storage and modules; the provider must keep nodes current |
| Failover options | A single endpoint is a single point of failure for your app |
| Support responsiveness | Substrate debugging benefits from a provider that understands the stack |
OnFinality runs Bittensor (Finney) RPC as part of a broader network portfolio, so you can keep your Substrate and EVM integrations on consistent tooling. If you want to compare this against other chains and providers, the how to choose an RPC provider article walks through the general evaluation framework.
Build versus buy for Bittensor infrastructure
Running your own Bittensor node gives you full control, but it comes with real operational cost: disk space for chain history, ongoing sync and upgrade maintenance, monitoring, and the expertise to debug Substrate issues. For a team whose product is a subnet, a miner, or an analytics tool, that is often time spent away from the thing you actually ship.
A managed RPC endpoint removes most of that overhead. You get a maintained connection to Finney mainnet, HTTP and WebSocket access, and a support path when something breaks. The tradeoff is that you depend on the provider for availability and rate limits, which is why the evaluation criteria above matter.
A middle path is a dedicated node: isolated resources for your workload without the burden of running the hardware yourself. That is usually the right step when your traffic is predictable and high, or when shared rate limits start to interfere with your polling loops.
Key Takeaways
- Bittensor runs on the Finney mainnet and uses Substrate JSON-RPC over HTTP and WebSocket, not the Ethereum method set.
- Match your endpoint choice to your workload: exploratory scripts can use a public endpoint, while dashboards, monitors, and indexers need shared or dedicated capacity.
- Always verify
system_healthandsystem_chainbefore trusting an endpoint, and compare block heights across endpoints when something looks stale. - Scale TAO values by
1e9and read storage keys from live metadata, because runtime upgrades rename modules and storage items. - Use WebSocket subscriptions for real-time data, and always implement reconnect logic with backoff.
- Evaluate providers on transport support, archive access, throughput, rate limit transparency, upgrade handling, and failover.
Frequently Asked Questions
Is Bittensor an EVM chain?
No. Bittensor is a Substrate-based chain, so it uses Substrate JSON-RPC methods such as system_health, chain_getHeader, and state_getStorage. Ethereum tools like eth_getBalance do not apply here; use the Polkadot.js API or another Substrate client instead.
What is the difference between Bittensor and Finney?
Bittensor is the network and the project, while Finney is the name of the mainnet. When you connect to a Bittensor RPC endpoint, you are connecting to Finney mainnet and reading its chain state.
Can I use a public RPC endpoint for production?
Public endpoints are fine for prototyping and low-frequency scripts. For production dashboards, monitoring loops, or indexers, shared or dedicated endpoints give you more predictable throughput and fewer surprises from rate limits.
Why do my TAO balances look wrong?
TAO uses 9 decimals. If you display raw integer values without scaling by 1e9, balances and emissions will appear far too large. Always convert before showing values to users.
How do I get real-time Bittensor data?
Use a WebSocket endpoint and subscribe to new heads or system events. Implement reconnect logic with backoff, and re-subscribe after each reconnect so your application does not run on stale data.
Where can I find OnFinality's Bittensor endpoint details?
See the Bittensor network page for endpoint and transport details, and the RPC pricing page to compare plans. A full list of chains is available on the supported RPC networks page.