Skip to content

ENS Omnigraph API

The ENS Omnigraph API is the world’s first and only API providing unified access to the full state of ENSv1 and ENSv2. It’s a single, polymorphic GraphQL API over both ENSv1 and ENSv2 — write your query once and get correct, typed results regardless of which protocol version a given Domain lives in.

ENS Omnigraph diagram

The Omnigraph is delivered by ENSApi on top of the indexed data in ENSDb. It follows the Relay specification, abstracts away the most common ENS-protocol footguns, and exposes enough of the underlying protocol for builders who need to go deep.

When ENSv2 launches in Summer 2026, the two protocol versions coexist — and the Omnigraph keeps your app working against both, at the same time, with no code changes. Both ENSv1 and ENSv2 Domains are indexed concurrently and exposed through a unified schema.

Ask for a Domain by name (domain(by: { name: "vitalik.eth" })) and you get a typed result whether that name lives in ENSv1 or ENSv2 — your code doesn’t have to know which at query time.

  • Multichain in one query — mainnet .eth, Basenames (.base.eth), Lineanames (.linea.eth), and 3DNS names (.box) all in a single unified schema.
  • Typed, no footguns — names and labels are normalized for you, so rendering them in a UI is trivial.
  • The full ENS picture — resolve records, search Domains, list what an address owns, read a complete history of onchain Events, inspect Permissions, and more.
  • Built-in pagination — Relay-spec connections mean infinite scroll and stable pagination work out of the box.

From a wallet address: Ethereum primary name and interpreted profile, plus ENSv1 and ENSv2 ownership counts.

Run in ENSAdmin
GraphQL
query HelloWorld($address: Address!) {
# Load an Account by address
account(by: { address: $address }) {
resolve {
# Resolve the primary name for the account
primaryName(by: { chainName: ETHEREUM }) {
name { interpreted beautified }
resolve {
# Resolve the profile (resolver records)
# for the primary name in the same query
profile {
description
avatar { httpUrl }
addresses { ethereum }
socials {
twitter { handle httpUrl }
github { handle httpUrl }
}
}
}
}
}
# Load the ENSv1 and ENSv2 domains owned by the account
v1DomainsCount: domains(where: { version: ENSv1 }) { totalCount }
v2DomainsCount: domains(where: { version: ENSv2 }) { totalCount }
}
}
Variables
{
"address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
}
Output
{
"data": {
"account": {
"v2DomainsCount": {
"totalCount": 0
},
"v1DomainsCount": {
"totalCount": 514
},
"resolve": {
"primaryName": {
"name": {
"interpreted": "vitalik.eth",
"beautified": "vitalik.eth"
},
"resolve": {
"profile": {
"description": "mi pinxe lo crino tcati",
"avatar": {
"httpUrl": "https://euc.li/vitalik.eth"
},
"addresses": {
"ethereum": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
},
"socials": {
"twitter": {
"handle": "VitalikButerin",
"httpUrl": "https://x.com/VitalikButerin"
},
"github": {
"handle": "vbuterin",
"httpUrl": "https://github.com/vbuterin"
}
}
}
}
}
}
}
}
}

Output matches a point in time snapshot GraphQL response from our alpha ENSNode instance. Live output depends on the configuration of your ENSNode instance and ENS state updates.

Browse more patterns in Examples. When you’re ready to understand the data model underneath, see Core Concepts.