Skip to content

Gno.land indexer & GraphQL

The gno.land node has no transaction search. Nodely runs the gno.land tx-indexer next to its archive nodes to fill that gap: search transactions by sender, recipient, realm or message type, and follow new blocks and transactions in real time.

All on the same host as the public RPC, gno.nodely.dev:

Service Endpoint
GraphQL API (queries and subscriptions) https://gno.nodely.dev/graphql/query
GraphQL playground https://gno.nodely.dev/graphql
Indexer JSON-RPC https://gno.nodely.dev/indexer
Indexer websocket (newHeads) wss://gno.nodely.dev/indexer/ws
  • gno.land mainnet (gnoland-1), full history from block 1.
  • No account, no keys. CORS is open, so browser apps can call it directly.
  • The playground documents every query, field and filter.

getTransactions takes a where filter on any transaction field, including message contents. Filters support eq, gt, lt and exists, combined with _and, _or and _not.

There is no result limit, so always scope a search with block_height.

Incoming transfers to an address:

{
getTransactions(where: {
block_height: { gt: 980000 }
messages: { value: { BankMsgSend: { to_address: { eq: "g1..." } } } }
}) {
hash
block_height
success
messages {
value {
... on BankMsgSend { from_address to_address amount }
}
}
}
}

Calls to a realm:

{
getTransactions(where: {
block_height: { gt: 980000 }
messages: { value: { MsgCall: { pkg_path: { eq: "gno.land/r/..." } } } }
}) {
hash
block_height
messages {
value {
... on MsgCall { caller pkg_path func }
}
}
}
}

Packages and realms deployed:

{
getTransactions(where: {
block_height: { gt: 980000 }
messages: { value: { MsgAddPackage: {} } }
}) {
hash
block_height
messages {
value {
... on MsgAddPackage { creator package { name path } }
}
}
}
}

With curl:

Terminal window
curl https://gno.nodely.dev/graphql/query \
-H 'Content-Type: application/json' \
-d '{"query":"{ latestBlockHeight }"}'

Subscriptions run on the same /graphql/query path over a websocket (graphql-transport-ws protocol, which standard GraphQL clients use). They deliver blocks or transactions created after the subscription starts.

subscription {
getBlocks(where: {}) {
height
time
num_txs
}
}

getTransactions works as a subscription too, with the same filters. For example, a wallet can watch for incoming transfers.

{
getSupply(denom: "ugnot") { height total spendable locked }
}

spendable is what data aggregators call the circulating supply.

POST JSON-RPC 2.0 requests to https://gno.nodely.dev/indexer.

Method Params Returns
getTxResultByHash [hash], base64 transaction result, base64 Amino
getTxResult [height, index] transaction result, base64 Amino
getBlock ["height"] block, base64 Amino
getSupply ["ugnot"] { denom, height, total, spendable, locked }
getGasPrice [] [{ denom, low, average, high }]

Transaction and block results come back as base64 Amino binary. Use GraphQL when you want JSON.

Terminal window
curl https://gno.nodely.dev/indexer \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getGasPrice","params":[]}'

Over wss://gno.nodely.dev/indexer/ws you can subscribe to new block headers. This is the push feed the node’s own websocket lacks:

{ "jsonrpc": "2.0", "id": 1, "method": "subscribe", "params": ["newHeads"] }

Each notification carries the header as base64 Amino binary.

Per client IP:

  • 5 requests per second (burst 20 for GraphQL, 40 for JSON-RPC)
  • 8 concurrent requests
  • Requests over the limit get HTTP 429

Need more? Talk to us about dedicated or whitelabel endpoints.