Skip to content

ERC-721 NFT Inspector

Paste an ERC-721 contract and token ID. Get name, symbol, tokenURI, and owner in one call, with the metadata resolved and previewed.

EthereumBaseBNB Smart Chainno signup · no wallet connect · free

The one query that powered this

{
  "name":     dyn(nft.name()),
  "symbol":   dyn(nft.symbol()),
  "tokenURI": dyn(nft.tokenURI(id)),
  "owner":    dyn(nft.ownerOf(id))
}

One expression. Auto-resolved ABI, EIP-1967 unwound, Multicall3 batched. Run this in your own code →

What this tool does

The ERC-721 Inspector reads any ERC-721 NFT contract and returns the name, symbol, tokenURI, and current owner from one expression. It is built for developers and collectors who need to inspect a specific token without writing ABI files or chasing IPFS gateways by hand.

How to use it

  1. Paste the ERC-721 contract address into the form above.
  2. Enter the token ID you want to inspect, then pick a chain.
  3. Run the query and read the name, symbol, owner, tokenURI, and metadata in the result panel.

The result panel shows the collection name and symbol, the current owner address, the raw tokenURI(id) returned by the contract, the resolved metadata URL, and the read block number. Everything happens in one round trip to the contract.

What is happening under the hood

ERC-721 is simpler to query than ERC-1155: every token ID has its own owner and its own tokenURI, already resolved by the contract with no {id} placeholder to substitute. evmquery handles the contract reads in one expression. The frontend handles the gateway fetch for the metadata JSON.

{
  "name":     dyn(nft.name()),
  "symbol":   dyn(nft.symbol()),
  "tokenURI": dyn(nft.tokenURI(id)),
  "owner":    dyn(nft.ownerOf(id))
}
  • name() and symbol() read the collection-level metadata exposed by the ERC-721 Metadata extension.
  • tokenURI(id) returns the final metadata URL for that specific token. evmquery resolves the contract ABI from verified source and decodes the typed result.
  • ownerOf(id) returns an address, while the other fields are strings. CEL maps need a single value type, so every field is wrapped in dyn(...) — this yields a map<string, dyn> and each value serializes as its natural type (the owner comes back as a hex address).
  • Multiple reads are auto-batched by Multicall3, so the cost is one round trip regardless of how many fields you ask for.

Build this yourself

Each of the snippets below makes the same POST call to the evmquery REST API. The expression is the one shown above, with your contract address and inputs filled in.

REST (curl)

curl -X POST https://api.evmquery.com/api/v1/query \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chain": "evm_ethereum",
    "schema": {
      "contracts": { "nft": { "address": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D" } },
      "context": { "id": "sol_int" }
    },
    "expression": "{ \"name\": dyn(nft.name()), \"symbol\": dyn(nft.symbol()), \"tokenURI\": dyn(nft.tokenURI(id)), \"owner\": dyn(nft.ownerOf(id)) }",
    "context": { "id": 1 }
  }'

Python

import requests

resp = requests.post(
    "https://api.evmquery.com/api/v1/query",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "chain": "evm_ethereum",
        "schema": {
            "contracts": {"nft": {"address": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"}},
            "context": {"id": "sol_int"},
        },
        "expression": (
            '{ "name": dyn(nft.name()), "symbol": dyn(nft.symbol()),'
            ' "tokenURI": dyn(nft.tokenURI(id)), "owner": dyn(nft.ownerOf(id)) }'
        ),
        "context": {"id": 1},
    },
    timeout=10,
)
print(resp.json()["result"])

TypeScript

const resp = await fetch("https://api.evmquery.com/api/v1/query", {
	method: "POST",
	headers: {
		Authorization: `Bearer ${process.env.EVMQUERY_API_KEY}`,
		"Content-Type": "application/json",
	},
	body: JSON.stringify({
		chain: "evm_ethereum",
		schema: {
			contracts: {
				nft: { address: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D" },
			},
			context: { id: "sol_int" },
		},
		expression:
			'{ "name": dyn(nft.name()), "symbol": dyn(nft.symbol()), "tokenURI": dyn(nft.tokenURI(id)), "owner": dyn(nft.ownerOf(id)) }',
		context: { id: 1n },
	}),
});
const { result } = await resp.json();

The free tier has no monthly cap. Get a free API key to drop these snippets into your project.

When you would use this

  • Verifying provenance. Confirm who currently owns a specific token before you buy, accept as collateral, or feature it.
  • Auditing a new collection. Quickly verify a contract really implements ERC-721 and inspect the metadata URI before you list or integrate it.
  • Debugging an indexer. Compare the on-chain tokenURI(id) and ownerOf(id) results with what your indexer cached to find where it drifted.
  • Writing ERC-721 docs. Show your readers a working tokenURI and ownerOf example without making them set up a Hardhat console.

FAQ

What is ERC-721?

ERC-721 is the standard for non-fungible tokens. Each token ID on a contract is unique, has its own owner tracked by ownerOf(id), and typically points to its own metadata URI via tokenURI(id).

What is the difference between ERC-721 and ERC-1155?

ERC-721 gives every token ID its own owner and its own tokenURI, with no placeholder substitution needed. ERC-1155 lets one contract hold many token IDs that can be fungible or non-fungible, and its uri(id) returns a template with a literal {id} placeholder the client must substitute.

Why does tokenURI have no {id} placeholder to substitute?

The EIP-721 metadata extension defines tokenURI(uint256) as returning the final URL for that specific token, already resolved server-side by the contract. There is no client-side substitution step like the {id} template in EIP-1155.

Which chains are supported?

The Inspector currently runs against Ethereum, Base, and BNB Smart Chain. Additional EVM chains are being added on the evmquery backend. If you need a specific chain prioritized, contact support.

Does evmquery work with proxy contracts?

Yes. evmquery automatically resolves EIP-1967 transparent and beacon proxies to their implementation, so you call nft.tokenURI(id) against the proxy address and it works. Roughly a third of production contracts use proxies, including most upgradeable ERC-721 collections.

What if the metadata URI uses an IPFS gateway that times out?

The Inspector tries the URI as returned by the contract first. For ipfs:// URIs it falls back through a small list of public gateways. If none respond, the resolved URL is shown so you can open it directly or point your own application at a gateway you control.

Can I use this tool from my own application?

Yes. The same expression and contract address work against the public REST API. The free tier has no monthly cap, and a single inspection counts as one read because Multicall3 batches all the underlying calls into one round trip. Bring your own API key and the rate limit applied to this page no longer applies.

Limits and accuracy

  • The result reflects the latest block at the time of the read. There is no historical replay.
  • The metadata fetch runs from your browser. Some collections gate metadata behind authenticated origins, in which case only the on-chain values are shown.
  • The demo is rate limited per browser. If you hit the limit, grab a free API key and the limit goes away.
  • Image previews are loaded directly from the metadata image URL. If the gateway throttles or the image is missing, the preview is silently hidden.
  • USD pricing, marketplace floor data, and royalty configuration are out of scope. evmquery returns raw on-chain values, not aggregated marketplace data.

Run this query in your own code

No monthly cap on the free tier. No credit card needed.