ENS Resolver — Name to Address, Reverse Lookup, Avatar avatar

ENS Resolver — Name to Address, Reverse Lookup, Avatar

Pricing

from $1.40 / 1,000 result items

Go to Apify Store
ENS Resolver — Name to Address, Reverse Lookup, Avatar

ENS Resolver — Name to Address, Reverse Lookup, Avatar

Resolve Ethereum Name Service names to addresses and addresses to primary ENS names, with avatar, text records (email, url, twitter, github, description) and content hash. Bulk. Built for agent identity checks. No API key.

Pricing

from $1.40 / 1,000 result items

Rating

0.0

(0)

Developer

Samat Makatov

Samat Makatov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Resolve Ethereum Name Service names in bulk: name.eth → address, address → primary name, with avatar, social handles, any text record, multi-chain addresses, contenthash, registration/expiry dates and on-chain events. Also lists every name an address owns and looks names up in the ENS index by label. Built for identity checks, CRM enrichment and domain monitoring. Uses public Ethereum RPC and the Blockscout ENS index (enstate.rs only as a fallback) — no API key, no proxy, no browser.

Use cases

  • Counterparty identity check — confirm that acme.eth really belongs to the wallet you are about to pay (isPrimaryName, reverse_record_mismatch).
  • CRM / lead enrichment — turn a list of wallet addresses into ENS names, Twitter, GitHub, website and email.
  • Portfolio of names — list every ENS name owned by or pointing to your treasury address, with expiry dates.
  • Renewal alerts — daily run over your brand names; flag expires_within_30d, expired_in_grace_period.
  • Brand checks — is your brand registered as an ENS name, who owns it and when does it expire (uniswap → uniswap.eth).
  • Cross-chain payouts — read BTC / Solana / Base / Arbitrum address records set on a name before sending funds.

Input

FieldTypeDefaultAllowed values / notes
modestringresolveresolve (one item per query), ownedBy (one item per name owned by / resolving to an address), search (one item per registered name: an exact lookup of the label, uniswap → uniswap.eth, not a keyword search). Apify refuses any other value before the run starts, with the list of allowed values.
queriesstring[]— (required)resolve: ENS names (incl. subnames, name.base.eth, name.cb.id) and/or 0x addresses. ownedBy: 0x addresses (anything else is listed in SUMMARY.errors). search: a label or a full name (uniswap, app.uniswap.eth). Duplicates are looked up (and billed) once, compared after ENS normalisation: Vitalik.ETH = vitalik.eth, an address in any letter case, uniswap = uniswap.eth in search.
textRecordsstring[]avatar, url, email, com.twitter, com.github, descriptionAny text-record key, or shortcuts *standard, *services, *all (see Reference); an unknown *shortcut fails the run with a suggestion
coinTypesstring[][]Keys from the coin-type table below (any letter case) or a numeric SLIP-44 coin type. An unknown key fails the run with a suggestion and the list of valid keys.
includeRegistrationbooleantrueOwner, registrant, wrapped owner, registration/expiry dates, days to expiry, grace period, resolver, NFT token id
includeContenthashbooleantrueIPFS / IPNS / Arweave / Swarm contenthash, read from the name's resolver and returned as a URI
verifyReversebooleantrueFor names: check the resolved address's primary name → isPrimaryName
includeEventsbooleanfalseRecent ENS events (registration, renewals, transfers, record updates) with tx hashes
eventsLimitinteger201–100
expiresWithinDaysinteger300–3650; adds flag expires_within_<N>d
lookupOwnedBybooleantrueownedBy: include names owned (or wrapped-owned) by the address
lookupResolvedTobooleantrueownedBy: include names whose ETH record points to the address
onlyActivebooleantrueownedBy / search: skip expired names
maxNamesPerQueryinteger501–500; the index is read 100 names per page, page after page up to this cap
fieldsstring[][]Keep only these top-level fields, in your order. query, name, address, found, fetchedAt are always kept and come first unless you list them. Letter case is forgiven; an unknown name fails the run with a suggestion; a field that only the other mode's rows have is left out with a note.
rpcUrlsJSON array—Your own Ethereum mainnet JSON-RPC URLs, tried before the public ones (optional, for large batches). A secret input: stored encrypted and never written to the log or SUMMARY, because such URLs usually carry a provider key. A malformed entry fails the run (its position is named, not its text).

Reference

Text-record shortcuts

ShortcutKeys
*standardavatar, description, display, email, keywords, mail, notice, location, phone, url, header, name
*servicescom.twitter, com.github, com.discord, org.telegram, com.reddit, com.linkedin, com.youtube, io.keybase, eth.ens.delegate, com.farcaster, xyz.farcaster, com.instagram, com.warpcast, xyz.lens
*allboth lists

Any other key (e.g. org.discourse, snapshot) can be passed literally. Global keys are defined in ENSIP-5.

Coin types (coinTypes, ENSIP-9 / ENSIP-11)

KeyCoin typeChain
btc0Bitcoin
ltc2Litecoin
doge3Dogecoin
eth60Ethereum
atom118Cosmos
xrp144XRP
trx195Tron
dot354Polkadot
sol501Solana
bnb714BNB Beacon Chain
optimism2147483658OP Mainnet (EVM 10)
bsc2147483704BNB Smart Chain (EVM 56)
gnosis2147483748Gnosis (EVM 100)
polygon2147483785Polygon (EVM 137)
zksync2147483972ZKsync Era (EVM 324)
base2147492101Base (EVM 8453)
arbitrum2147525809Arbitrum One (EVM 42161)
avalanche2147526762Avalanche C-Chain (EVM 43114)
linea2147542792Linea (EVM 59144)
scroll2148018000Scroll (EVM 534352)

EVM chains use 0x80000000 | chainId; any other SLIP-44 number can be passed as a numeric string.

Flags (flags[], mode=resolve)

FlagMeaning
not_registered.eth name unknown to RPC and to the ENS index — such a name has nothing to return, so it is not an item: it is listed in SUMMARY.notFound
no_forward_resolutionName exists but has no ETH address record
no_primary_nameAddress has no reverse (primary) name — with nothing else resolved it is listed in SUMMARY.notFound instead of being an item
reverse_record_mismatchName points to an address whose primary name is a different name — treat as unverified identity
no_reverse_recordName points to an address that has no primary name
expires_within_<N>dExpires within expiresWithinDays
expired_in_grace_period / expiredExpired less / more than 90 days ago
owner_differs_from_resolved_addressController/owner is not the address the name points to
wrapped_name, offchain_name, subnameNameWrapper name; offchain (CCIP-read) name; subdomain

Examples

1. Verify a payee before sending funds

{ "queries": ["nick.eth", "vitalik.eth"], "verifyReverse": true, "includeRegistration": true, "textRecords": ["url", "com.twitter"] }

2. Enrich a list of wallet addresses for CRM

{ "queries": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5"], "textRecords": ["*standard", "*services"], "includeContenthash": false, "fields": ["reverseName", "twitter", "github", "url", "email", "description", "completeness"] }

3. All names owned by our treasury, with expiry

{ "mode": "ownedBy", "queries": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"], "lookupResolvedTo": false, "onlyActive": false, "maxNamesPerQuery": 100 }

4. Renewal monitor with a 60-day window

{ "queries": ["uniswap.eth", "ens.eth"], "expiresWithinDays": 60, "textRecords": ["url"], "verifyReverse": false, "fields": ["registration", "flags"] }

5. Brand check: is the name registered, by whom, until when

{ "mode": "search", "queries": ["uniswap", "app.uniswap.eth"], "onlyActive": false }

6. Cross-chain payout addresses

{ "queries": ["vitalik.eth"], "coinTypes": ["btc", "sol", "base", "arbitrum"], "textRecords": ["avatar"] }

Output

mode: "resolve" — one item per query (trimmed real example):

{
"query": "vitalik.eth", "kind": "name", "name": "vitalik.eth", "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"found": true, "isPrimaryName": true, "reverseName": "vitalik.eth",
"avatar": "https://euc.li/vitalik.eth", "avatarUrl": "https://euc.li/vitalik.eth",
"header": "https://pbs.twimg.com/profile_banners/295218901/1638557376/1500x500", "display": null,
"description": "mi pinxe lo crino tcati", "url": "https://vitalik.ca", "email": null,
"twitter": "VitalikButerin", "github": "vbuterin", "discord": null, "telegram": null, "farcaster": null, "lens": null,
"texts": { "avatar": "https://euc.li/vitalik.eth", "url": "https://vitalik.ca", "description": "mi pinxe lo crino tcati", "com.twitter": "VitalikButerin", "com.github": "vbuterin" },
"addresses": {},
"contenthash": "ipfs://bafybeigqyo555suvqi3scc2izft3mozskktbtkzs2xghoe2rpxetxbbdiq", "resolver": "0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63",
"registration": { "owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "registeredAt": "2017-06-18T08:39:14.000Z", "expiresAt": "2048-04-30T00:13:44.000Z", "daysToExpiry": 7880, "isExpired": false, "inGracePeriod": false, "isWrapped": false, "tokenId": "79233663829379634837589865448569342784712482819484549289560981379859480642508", "…": "…" },
"events": [], "completeness": 85, "flags": [], "warnings": [], "sources": ["rpc", "bens"],
"ensAppUrl": "https://app.ens.domains/vitalik.eth", "fetchedAt": "2026-10-02T19:09:22.058Z"
}
FieldDescription
kindname, address or invalid
name, address, foundNormalized ENS name, resolved/queried address; found = both known (false only for a registered name without an address record, which still carries registration / records)
isPrimaryName, reverseNameReverse-record verification (see flags)
avatar, avatarUrl, headerRaw avatar record and a fetchable URL (ipfs:// and NFT avatars mapped to gateways / ENS metadata service); the header (banner) record
display, description, url, email, twitter, github, discord, telegram, farcaster, lensCommon records, handles cleaned of URL prefixes and @
query, fetchedAtThe query as typed (trimmed); when the row was read (UTC)
textsAll requested text records that are set
addressesRequested multi-chain address records (null when not set)
contenthash, resolverDecentralised website hash as a URI (ipfs:// CIDv1, ipns://, bzz://, ar://; an unknown namespace as raw hex); resolver contract
registrationRegistration & expiry object (null if disabled or not indexed)
eventsRecent ENS events: txHash, timestamp, from, fromName, action
completeness0–100 profile score (address, avatar, description, url, email, socials, contenthash, extra addresses)
ensAppUrlLink to the name in the ENS app
flags, warnings, sourcesTriage flags; failed sub-lookups (the row is still delivered); which sources answered (rpc, bens, enstate)

mode: "ownedBy" / "search" — one item per name: query, relation (owned, resolved_to, owned_and_resolved; null in search), name, address, owner, wrappedOwner, registeredAt, expiresAt, daysToExpiry, isExpired, inGracePeriod, isSubname, protocol, ensAppUrl, source, fetchedAt. A query with no matches is not an item (not charged): it is listed in SUMMARY.notFound.

Use it from code / agents

curl -X POST "https://api.apify.com/v2/acts/yadroo~ens-resolver/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"queries":["vitalik.eth","0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/ens-resolver').call({ queries: ['vitalik.eth'], coinTypes: ['btc', 'sol'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClient
client = ApifyClient(token)
run = client.actor("yadroo/ens-resolver").call(run_input={"mode": "ownedBy", "queries": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]})
items = client.dataset(run["defaultDatasetId"]).list_items().items

MCP: add https://mcp.apify.com to your MCP client (Claude, Cursor, …) and call the yadroo/ens-resolver tool with the same JSON.

Pricing

Pay per event: $0.001 per run start + $0.002 per dataset item. Bronze −10 %, Silver −20 %, Gold and above −30 % on the item price; the start event is the same on every plan; platform usage is included. In resolve mode that is one item per query: resolving 100 names or addresses costs $0.201. In ownedBy / search every returned name is an item, so cap it with maxNamesPerQuery (e.g. an address with 50 names = $0.101). Queries with no result, invalid queries, duplicates and failed lookups are not dataset items and cost nothing — see SUMMARY.

The run never goes over your Maximum cost per run: it stops before the first item it could not pay for, ends with the status "Stopped at your spending limit: N rows delivered", and lists the queries it did not get to in SUMMARY.notProcessed.

Limits & FAQ

  • Sources — forward/reverse resolution, text and address records and the contenthash come from public Ethereum RPC nodes (ENS Universal Resolver, with fallback across several providers); registration, events, ownedBy and search come from the Blockscout ENS index (BENS). enstate.rs is asked only when an RPC record lookup failed, and is skipped for the rest of the run after two failures in a row.
  • Speed & capacity — about 1.3–1.8 s per name in resolve mode with public RPCs and the default options (two runs of 334 names on Apify on 02.10.2026 took 7 and 10 minutes), so the default 15-minute run fits about 400–600 names; every extra coin type, text key or includeEvents adds a little. The run stops starting new queries shortly before its timeout (90 s before the default 15 minutes), saves what it has, ends SUCCEEDED with "Stopped before the run timeout" and lists the queries it did not get to in SUMMARY.notProcessed: run those again, or raise the run timeout. ownedBy / search read the index 100 names per page. Public RPCs rate-limit large batches; failed sub-lookups are listed in warnings and the item is still delivered. For large lists pass your own node in rpcUrls.
  • Restarts — if Apify migrates or restarts the run, it continues after the last finished query; no item is stored or billed twice.
  • Freshness — RPC data is live; the ENS index lags the chain by minutes.
  • Offchain names (*.cb.id, *.base.eth, other CCIP-read names) resolve via RPC; registration data may be missing for them.
  • Search is an exact lookup in the index: a bare label (uniswap, uniswap.eth) is checked under every TLD the index knows for Ethereum, a longer name (app.uniswap.eth) as given. It does not find names that merely contain the word.
  • Errors — Apify refuses an off-list mode before the run starts. An unknown coin type, text-record shortcut or field name, a malformed rpcUrls entry or an empty queries list fails the run at once with a message that names it. Per-query problems never stop the run and are never charged: the SUMMARY record lists invalid names/addresses and failed lookups under errors (with a reason that says what is wrong: wrong length, non-hex character, missing TLD, which lookup failed) and queries with nothing to return under notFound (unregistered names, addresses without a primary name, no matches), with errorCount / notFoundCount. A query is reported as not found only when the sources answered; when a lookup failed it is an error. The run fails only when it saved no item and at least one query failed; a run where every query was simply not found succeeds with 0 items.
  • SUMMARY record — delivered (items saved, also as items), errors / errorCount, notFound / notFoundCount, notProcessed / notProcessedCount (queries a stop left out), queriesDone, duplicatesRemoved, notes (input corrections), stoppedBy (limit, timeout, aborted or null) and the final status. Lists hold the first 100 entries; the counts are exact.
  • Address checksum — mixed-case addresses must pass the EIP-55 checksum. A failed checksum almost always means a typo, so the query is rejected (0x address fails the EIP-55 checksum) instead of silently resolving a different wallet. All-lowercase addresses skip the check.
  • Roadmap — L2 primary names (ENSIP-19), name history diffs for monitoring.

Made by Yadroo. Siblings: wallet-intel · base-token-intel · dexscreener-tokens · bitcoin-mempool · x402-endpoints