A resolver finds a public Kaspa node so you don’t need a URL up front. Hand one to the RPC client instead of a URL and connect() picks a live node from the Public Node Network (PNN).
For most applications this is all you need:
use kaspa_wrpc_client::{
prelude::{NetworkId, NetworkType},
KaspaRpcClient, Resolver, WrpcEncoding,
};
let client = KaspaRpcClient::new(
WrpcEncoding::Borsh,
None,
Some(Resolver::default()),
Some(NetworkId::new(NetworkType::Mainnet)),
None,
)?;
client.connect(None).await?; const { RpcClient, Resolver } = kaspa;
const rpc = new RpcClient({ resolver: new Resolver(), networkId: 'mainnet' });
await rpc.connect(); from kaspa import Resolver, RpcClient
client = RpcClient(resolver=Resolver(), network_id="mainnet")
await client.connect()For security-critical applications, connect to your own node. The resolver hands you someone else’s node; it can serve stale or wrong answers, and it can go away. See Run a Node.
The network id selects which network to search — mainnet or a testnet. Not every testnet has PNN nodes. See Networks.
Constructor options
// Default: any reachable node.
let resolver = Resolver::default();
// Require TLS (wss://), or point at your own resolver fleet.
let resolver = Resolver::new(None, true);
let resolver = Resolver::new(Some(vec![Arc::new("https://resolver1.example.org".to_string())]), false); // Default: any reachable node.
const resolver = new Resolver();
// Point at your own resolver fleet.
const resolver = new Resolver({ urls: ['https://resolver1.example.org'] }); # Default: any reachable node.
resolver = Resolver()
# Require a TLS-capable node (wss://).
resolver = Resolver(tls=True)
# Point at your own resolver fleet.
resolver = Resolver(urls=["https://resolver1.example.org"])tls— restrict towss://nodes. Off by default, which allows any reachable node.urls— replaces the built-in resolver-service list with your own (see Under the hood).
Querying the resolver directly
You can fetch a URL without constructing a client at all:
let url = resolver.get_url(WrpcEncoding::Borsh, NetworkId::new(NetworkType::Mainnet)).await?;
let node = resolver.get_node(WrpcEncoding::Borsh, NetworkId::new(NetworkType::Mainnet)).await?; const url = await resolver.getUrl(kaspa.Encoding.Borsh, 'mainnet');
const node = await resolver.getNode(kaspa.Encoding.Borsh, 'mainnet'); url = await resolver.get_url("borsh", "mainnet")
node = await resolver.get_node("borsh", "mainnet")get_url returns a WebSocket URL ready to hand to a client constructed with an explicit URL. get_node returns the full node descriptor, including the node’s uid.
Under the hood
You don’t need any of this to use a resolver — it’s here for anyone running their own infrastructure or debugging connectivity.
A resolver doesn’t open WebSockets and doesn’t hold Kaspa node URLs. It holds a list of resolver service HTTP endpoints (see aspectron/kaspa-resolver) that track live PNN nodes and load-balance across them.
On get_url / get_node — which connect() calls internally:
- Pick a configured resolver-service URL at random.
GET {url}/v2/kaspa/{network_id}/{tls_or_any}/wrpc/{encoding}.- Parse the response as a node descriptor and return the URL.
- On failure, try the next service; raise if all fail.
The default resolver ships with the public resolver-service list embedded in the SDK, sourced from Resolvers.toml in kaspa-wrpc-client. Supplying your own urls replaces that list — useful for a private node cluster behind your own resolver fleet. Reading the configured list back returns empty when the embedded defaults are in use, so the concrete URLs can rotate without breaking SDK consumers.
Where to next
- Connecting — direct URLs, retry and timeout options, encoding.
- RPC Calls — what to do once you’re connected.
- Run a Node — the alternative to all of this.