This is the full developer documentation for ENSNode # Hosted ENSNode Instances ## Get Started Quickly [Section titled “Get Started Quickly”](#get-started-quickly) NameHash Labs provides hosted instances of ENSNode for developers building on ENS and looking to get started quickly. These instances are currently provided free of charge with no API key required, have no rate limiting, and are maintained and monitored by the NameHash Labs team. Version compatibility with hosted instances [Our hosted ENSNode instances](/docs/hosted-instances) currently run ENSNode `1.15.2`. The Omnigraph GraphQL schema is bundled inside the SDK and consumed by the `gql.tada` TypeScript plugin to type your queries, so pin an **exact** version (no `^` or `~`) of `enssdk@1.15.2` (and `enskit@1.15.2` when using React) to keep your generated types matched to the deployed schema. Use these exact install commands: ``` npm install enssdk@1.15.2 # or, for React apps: npm install enskit@1.15.2 enssdk@1.15.2 ``` ### ENS Namespaces [Section titled “ENS Namespaces”](#ens-namespaces) Each ENSNode instance is configured for a specific **ENS namespace**. An ENS namespace identifies which ENS protocol deployment ENSNode will provide data for (ex: mainnet or sepolia). Each ENS namespace is associated with a particular ENS Root Registry deployment, which may or may not have completed the transition from ENSv1 (only) to ENSv1 + ENSv2 (both v1 and v2 concurrently activated together). ENSNode supports all of the following ENS namespaces: * `mainnet` * Currently ENSv1 only and not also ENSv2 yet. * `sepolia` * Currently ENSv1 only and not also ENSv2 yet. * `sepolia-v2` * Now ENSv1 + ENSv2 — An *all new* deployment of ENS to Sepolia that is already upgraded to ENSv1 + ENSv2 and is independent of the traditional `sepolia` ENS namespace listed above which currently remains ENSv1 only. * `ens-test-env` * Now ENSv1 + ENSv2 — A deployment of ENSv1 + ENSv2 to a local Anvil chain for development and testing. About the ens-test-env For details see [ens-test-env](https://github.com/ensdomains/ens-test-env) and [contracts-v2](https://github.com/ensdomains/contracts-v2). Teams working on the core ENS protocol and core ENS infrastructure such as ENS Labs and NameHash Labs are using this ENSNode configuration to support ENSv2 development. More details about ENS namespaces can be found inside [ENSNode’s datasources package](https://github.com/namehash/ensnode/tree/main/packages/datasources). ### ENSNode Plugins [Section titled “ENSNode Plugins”](#ensnode-plugins) Each ENSNode instance is also configured for a specific set of activated [ENSNode plugins](/docs/integrate/integration-options/ensnode-plugins). The activated plugins determine the specific indexed data model and data records ENSIndexer will produce in ENSDb and therefore which APIs and data records ENSApi will make available to query. ## ENSv1 + ENSv2 Instances [Section titled “ENSv1 + ENSv2 Instances”](#ensv1--ensv2-instances) These instances are associated with an ENS namespace that has upgraded to ENSv1 + ENSv2 and demonstrate the latest support in ENSNode for ENSv1 and ENSv2 being concurrently activated together. ### ENSNode ‘v2 Sepolia’ [Section titled “ENSNode ‘v2 Sepolia’”](#ensnode-v2-sepolia) v2 Sepolia The `sepolia-v2` namespace is undergoing active development by the ENS Labs team who is continuing to release updated ENSv2 contracts. It should be considered experimental. | | | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Hosted at | [ Connect with ENSAdmin](https://admin.ensnode.io/connection?connection=https%3A%2F%2Fapi.v2-sepolia.ensnode.io) | | ENSNode Version | v1.15.2 | | ENS Namespace | sepolia-v2 | | ENS Versions | ENSv1 + ENSv2 (concurrently activated together) | | ENSNode Plugins | [unigraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [protocol-acceleration](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [subgraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins) | | ENSApi Services | * ENS Omnigraph API ✅ *Activated.* Powered by a polymorphic GraphQL API with native support for both ENSv1 and ENSv2. When ENSv2 launches in Summer 2026, data from two protocol versions coexist — and the ENS Omnigraph API will keep your app working against both, at the same time, with no code changes. Domains from ENSv1 and ENSv2 are indexed concurrently and exposed through a unified schema. * ENS Protocol Acceleration ✅ *Available.* Accelerate most of your ENS protocol resolution requests while maintaining full compliance with all ENS protocol standards and best practices. * ENS Subgraph API 🚨 *API-level Subgraph Compatibility.* This ENSNode instance has a fully backwards compatible ENS Subgraph GraphQL API. However, additional plugins have been activated which index a superset of data into the subgraph data model in ENSDb. This superset of indexed data means that the data returned for some ENS Subgraph API queries may be different. ENSv2 launch completed. Subgraph API now unreliable. ENSv2 has launched on the `sepolia-v2` ENS namespace. This means the legacy ENS Subgraph no longer returns reliable data. Transition your apps now to the new [ENS Omnigraph API](/docs/integrate/omnigraph) to be ENSv2 ready. | ## ENSv1 Only Instances (not also ENSv2 yet) [Section titled “ENSv1 Only Instances (not also ENSv2 yet)”](#ensv1-only-instances-not-also-ensv2-yet) These instances are associated with an ENS namespace that has *NOT* upgraded to support ENSv1 and ENSv2 concurrently yet and are still operating exclusively under ENSv1. These demonstrate how [*the ENS Omnigraph API*](/docs/integrate/omnigraph), [*enssdk*](/docs/integrate/integration-options/enssdk), [*enskit*](/docs/integrate/integration-options/enskit), and [the full stack of ENSNode services](/docs/services) provide support to developers to become ENSv2 ready even before ENSv2 launches. ### Alpha-style Deployments [Section titled “Alpha-style Deployments”](#alpha-style-deployments) These ENSNode instances do not constrain themselves to exclusively activating the `subgraph` plugin. They activate additional plugins such as the `unigraph` plugin to demonstrate the latest capabilities of ENSNode including [*the new ENS Omnigraph API*](/docs/integrate/omnigraph). #### ENSNode ‘Alpha’ [Section titled “ENSNode ‘Alpha’”](#ensnode-alpha) | | | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Hosted at | [ Connect with ENSAdmin](https://admin.ensnode.io/connection?connection=https%3A%2F%2Fapi.alpha.ensnode.io) | | ENSNode Version | v1.15.2 | | ENS Namespace | mainnet | | ENS Versions | ENSv1 only (not also ENSv2 yet) | | ENSNode Plugins | [unigraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [protocol-acceleration](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [subgraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [basenames](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [lineanames](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [threedns](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [registrars](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [tokenscope](/docs/integrate/integration-options/ensnode-plugins#existing-plugins) | | ENSApi Services | * ENS Omnigraph API ✅ *Activated.* Demonstrates the ENS Omnigraph's ability to support ENSv1 only before ENSv2 launches and both ENSv1 and ENSv2 are concurrently active. Until ENSv2 launches on this namespace, only ENSv1 domains will be available. As soon as ENSv2 launches on this namespace both ENSv1 and ENSv2 domains will be available. * ENS Protocol Acceleration ✅ *Available.* Accelerate most of your ENS protocol resolution requests while maintaining full compliance with all ENS protocol standards and best practices. * ENS Subgraph API ✅ *API-level Subgraph Compatibility.* This ENSNode instance has a fully backwards compatible ENS Subgraph GraphQL API. However, additional plugins have been activated which index a superset of data into the subgraph data model in ENSDb. This superset of indexed data means that the data returned for some ENS Subgraph API queries may be different. ENSv2 launches soon. Subgraph API soon unreliable. ENSv2 launches soon! As soon as ENSv2 launches on the `mainnet` ENS namespace, the legacy ENS Subgraph will no longer return reliable data. Transition your apps now to the new [ENS Omnigraph API](/docs/integrate/omnigraph) to be ENSv2 ready. | #### ENSNode ‘Alpha-Sepolia’ [Section titled “ENSNode ‘Alpha-Sepolia’”](#ensnode-alpha-sepolia) | | | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Hosted at | [ Connect with ENSAdmin](https://admin.ensnode.io/connection?connection=https%3A%2F%2Fapi.alpha-sepolia.ensnode.io) | | ENSNode Version | v1.15.2 | | ENS Namespace | sepolia | | ENS Versions | ENSv1 only (not also ENSv2 yet) | | ENSNode Plugins | [unigraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [protocol-acceleration](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [subgraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [basenames](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [lineanames](/docs/integrate/integration-options/ensnode-plugins#existing-plugins), [registrars](/docs/integrate/integration-options/ensnode-plugins#existing-plugins) | | ENSApi Services | * ENS Omnigraph API ✅ *Activated.* Demonstrates the ENS Omnigraph's ability to support ENSv1 only before ENSv2 launches and both ENSv1 and ENSv2 are concurrently active. Until ENSv2 launches on this namespace, only ENSv1 domains will be available. As soon as ENSv2 launches on this namespace both ENSv1 and ENSv2 domains will be available. * ENS Protocol Acceleration ✅ *Available.* Accelerate most of your ENS protocol resolution requests while maintaining full compliance with all ENS protocol standards and best practices. * ENS Subgraph API ✅ *API-level Subgraph Compatibility.* This ENSNode instance has a fully backwards compatible ENS Subgraph GraphQL API. However, additional plugins have been activated which index a superset of data into the subgraph data model in ENSDb. This superset of indexed data means that the data returned for some ENS Subgraph API queries may be different. ENSv2 launches soon. Subgraph API soon unreliable. ENSv2 launches soon! As soon as ENSv2 launches on the `sepolia` ENS namespace, the legacy ENS Subgraph will no longer return reliable data. Transition your apps now to the new [ENS Omnigraph API](/docs/integrate/omnigraph) to be ENSv2 ready. | ### Subgraph-style Deployments [Section titled “Subgraph-style Deployments”](#subgraph-style-deployments) These ENSNode instances focus on maximizing backwards compatibility with the ENS Subgraph. Therefore they exclusively activate the `subgraph` plugin and no others. #### ENSNode ‘Mainnet’ [Section titled “ENSNode ‘Mainnet’”](#ensnode-mainnet) | | | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Hosted at | [ Connect with ENSAdmin](https://admin.ensnode.io/connection?connection=https%3A%2F%2Fapi.mainnet.ensnode.io) | | ENSNode Version | v1.15.2 | | ENS Namespace | mainnet | | ENS Versions | ENSv1 only (not also ENSv2 yet) | | ENSNode Plugins | [subgraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins) | | ENSApi Services | * ENS Omnigraph API ❌ *Not activated.* This ENSNode instance optimizes for maximum compatibility with the ENS Subgraph. Therefore it exclusively activates the *subgraph* plugin and does not activate the *unigraph* plugin that the ENS Omnigraph API requires. * ENS Protocol Acceleration ❌ *Unavailable.* Your ENS protocol resolution requests will be serviced in full compliance with all ENS protocol standards and best practices. However, this ENSNode instance did not activate the *protocol-acceleration* plugin and therefore ENS resolution requests will be serviced accurately but without acceleration. * ENS Subgraph API ✅ *Full Subgraph Compatibility.* This ENSNode instance has a fully backwards compatible ENS Subgraph GraphQL API at both the API-level and the data-level. We have exhaustively tested and verified that every data record returned by this ENSNode instance's ENS Subgraph API is byte-for-byte identical with The Graph's ENS Subgraph API. ENSv2 launches soon. Subgraph API soon unreliable. ENSv2 launches soon! As soon as ENSv2 launches on the `mainnet` ENS namespace, the legacy ENS Subgraph will no longer return reliable data. Transition your apps now to the new [ENS Omnigraph API](/docs/integrate/omnigraph) to be ENSv2 ready. | #### ENSNode ‘Sepolia’ [Section titled “ENSNode ‘Sepolia’”](#ensnode-sepolia) | | | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Hosted at | [ Connect with ENSAdmin](https://admin.ensnode.io/connection?connection=https%3A%2F%2Fapi.sepolia.ensnode.io) | | ENSNode Version | v1.15.2 | | ENS Namespace | sepolia | | ENS Versions | ENSv1 only (not also ENSv2 yet) | | ENSNode Plugins | [subgraph](/docs/integrate/integration-options/ensnode-plugins#existing-plugins) | | ENSApi Services | * ENS Omnigraph API ❌ *Not activated.* This ENSNode instance optimizes for maximum compatibility with the ENS Subgraph. Therefore it exclusively activates the *subgraph* plugin and does not activate the *unigraph* plugin that the ENS Omnigraph API requires. * ENS Protocol Acceleration ❌ *Unavailable.* Your ENS protocol resolution requests will be serviced in full compliance with all ENS protocol standards and best practices. However, this ENSNode instance did not activate the *protocol-acceleration* plugin and therefore ENS resolution requests will be serviced accurately but without acceleration. * ENS Subgraph API ✅ *Full Subgraph Compatibility.* This ENSNode instance has a fully backwards compatible ENS Subgraph GraphQL API at both the API-level and the data-level. We have exhaustively tested and verified that every data record returned by this ENSNode instance's ENS Subgraph API is byte-for-byte identical with The Graph's ENS Subgraph API. ENSv2 launches soon. Subgraph API soon unreliable. ENSv2 launches soon! As soon as ENSv2 launches on the `sepolia` ENS namespace, the legacy ENS Subgraph will no longer return reliable data. Transition your apps now to the new [ENS Omnigraph API](/docs/integrate/omnigraph) to be ENSv2 ready. | ## Start building [Section titled “Start building”](#start-building) Pick an instance above, then jump into the Quickstart for integration options to start making use of it. [ENSNode Quickstart ](/docs/integrate)Wire enskit, enssdk, or the ENS Omnigraph API up to a hosted instance in a few minutes. # ENSv2 Quickstart > Get started building full-stack ENSv2 apps. ## What is ENSv2? [Section titled “What is ENSv2?”](#what-is-ensv2) [ENSv2](https://ens.domains/ensv2) is the next generation of the [Ethereum Name Service](https://ens.domains) — a protocol upgrade that fundamentally changes how the ENS protocol works. Prepare for ENSv2 The ENSv2 upgrade to the ENS protocol is coming **Summer 2026**! Your app, regardless of how it interacts with names, needs to be updated to avoid being left behind.\ [Learn more about ENSv2 Readiness](/docs/integrate/why-ensnode/ensv2-readiness) ## What is the ENS Omnigraph? [Section titled “What is the ENS Omnigraph?”](#what-is-the-ens-omnigraph) ENSNode fully supports ENSv2 via the [ENS Omnigraph API](/docs/integrate/omnigraph), the world’s first and only *unified* API over the full state of **both ENSv1 and ENSv2**. When ENSv2 launches in **Summer 2026**, ENSv1 continues to exist, and apps *must* be updated to use the new protocol version. ENSNode takes the guesswork out of building on ENS, whether you need to resolve up-to-date records, search all Domains, or see which Domains a user owns (and much, much more). ![ENS Omnigraph diagram](/ens-omnigraph-diagram.png) ENS Omnigraph supports both ENSv1 and ENSv2 **concurrently** within the **same unified data model**. This means you can integrate today (before ENSv2 launches) and continue with full ENSv2 support when it goes live, with zero downtime! ## ENSNode’s Integration Options [Section titled “ENSNode’s Integration Options”](#ensnodes-integration-options) ENSNode supports a full range of different integration options across the stack, whether you’re using React, any JavaScript runtime, raw GraphQL, or looking to go deep and build a fully custom service using indexed ENS data. [Catalog of Integration Options ](/docs/integrate/integration-options) Here’s a summary of some popular integration strategies: ### 1. enssdk + Omnigraph [Section titled “1. enssdk + Omnigraph”](#1-enssdk--omnigraph) With `enssdk`, leverage ENSNode and the Omnigraph from any JavaScript runtime to power your frontend or backend apps. `enssdk` comes with built-in type-safety and editor autocomplete for Omnigraph queries. Start from a wallet address, reverse-resolve its Ethereum primary name, then forward-resolve the profile on that name: example.ts ```ts import { createEnsNodeClient } from "enssdk/core"; import { graphql, omnigraph } from "enssdk/omnigraph"; // create and extend an EnsNodeClient with Omnigraph API support const client = createEnsNodeClient({ url: process.env.ENSNODE_URL! }) .extend(omnigraph); // this is fully typechecked and supports editor autocomplete! const HelloWorldQuery = graphql(` query HelloWorld($address: Address!) { account(by: { address: $address }) { address resolve { primaryName(by: { chainName: ETHEREUM }) { name { beautified } resolve { profile { description addresses { ethereum bitcoin } } } } } } } `); // `result` is fully typed! const result = await client.omnigraph.query({ query: HelloWorldQuery, variables: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", }, }); ``` BeautifiedName `beautified` is the display-ready form of the Canonical Name — its normalized labels rendered per [ENSIP-15](https://docs.ens.domains/ensip/15) (e.g. `♾.eth` → `♾️.eth`) — so you can render it directly with no normalization or emoji logic of your own. It’s **display-only**: use `interpreted` (or the Domain `id`) as a lookup key or navigation target, never `beautified`. See [Beautified Name](/docs/reference/terminology#beautified-name). [Full enssdk Integration Documentation ](/docs/integrate/integration-options/enssdk) [enssdk-example app ](https://github.com/namehash/ensnode/tree/main/examples/enssdk-example)Check out our enssdk-example for a full example app. [Interactive enssdk example ⚡ ](/docs/integrate/integration-options/enssdk/example)Edit and run the enssdk-example script in your browser. ### 2. enskit + Omnigraph [Section titled “2. enskit + Omnigraph”](#2-enskit--omnigraph) With `enskit`, leverage ENSNode and the Omnigraph to power your React components using `useOmnigraphQuery`. `enskit` comes with built-in type-safety, Omnigraph-specific cache directives, easy infinite pagination, and much much more. The same `address -> primary name -> forward profile` pattern in a React component: example.tsx ```tsx import { graphql, useOmnigraphQuery } from "enskit/react/omnigraph"; import type { Address } from "enssdk"; // this query is fully typechecked and supports editor autocomplete! const AccountPrimaryProfileQuery = graphql(` query AccountPrimaryProfile($address: Address!) { account(by: { address: $address }) { address resolve { primaryName(by: { chainName: ETHEREUM }) { name { beautified } resolve { profile { description addresses { ethereum bitcoin } } } } } } } `); export function AccountProfileCard({ address }: { address: Address }) { // `result` is fully typed! const [result] = useOmnigraphQuery({ query: AccountPrimaryProfileQuery, variables: { address }, }); const { data, fetching, error } = result; if (fetching) return

Loading...

; if (error) return

Error: {error.message}

; if (!data?.account) return

No account found for '{address}'.

; const { account } = data; const primaryName = account.resolve?.primaryName; const addresses = primaryName?.resolve?.profile?.addresses; return (

Address: {account.address}

Primary name: {primaryName?.name?.beautified ?? "None set"}

Bitcoin address: {addresses?.bitcoin ?? "Not set"}

Description: {primaryName?.resolve?.profile?.description}

); } ``` [Full enskit Integration Documentation ](/docs/integrate/integration-options/enskit) [enskit-react-example app ](https://github.com/namehash/ensnode/tree/main/examples/enskit-react-example)Check out our enskit-react-example for a full example app. [Interactive enskit example ⚡ ](/docs/integrate/integration-options/enskit/example)Edit and run the enskit-react-example app in your browser with a live preview. ### 3. ENS Omnigraph GraphQL API [Section titled “3. ENS Omnigraph GraphQL API”](#3-ens-omnigraph-graphql-api) The ENS Omnigraph API is a GraphQL API following the Relay specification, so you get built-in support for efficient infinite pagination and idiomatic access to all of the ENS protocol within a *unified* ENSv1 + ENSv2 datamodel. Same query: `address -> primary name -> forward profile` — via raw GraphQL with example response below: omnigraphcurl [ Run in ENSAdmin ](https://admin.ensnode.io/api/omnigraph?query=query+HelloWorld%28%24address%3A+Address%21%29+%7B%0A++%23+Lookup+an+Account+by+address.%0A++account%28by%3A+%7B+address%3A+%24address+%7D%29+%7B%0A++++resolve+%7B%0A++++++%23+Reverse+resolve+the+ENS+primary+name+of+the+account%0A++++++%23+using+a+convenient+ETHEREUM+alias+for+mainnet.%0A++++++primaryName%28by%3A+%7B+chainName%3A+ETHEREUM+%7D%29+%7B%0A++++++++%23+Get+the+regular+interpreted+variant+of+the+primary+name%0A++++++++%23+and+also+the+special+beautified+variant+that+optimizes+names%0A++++++++%23+containing+special+characters+such+as+emojis+for+proper+display+in+interfaces.%0A++++++++name+%7B+interpreted+beautified+%7D%0A++++++++resolve+%7B%0A++++++++++%23+If+the+account+has+a+primary+name+on+Ethereum+%28mainnet%29%2C%0A++++++++++%23+forward+resolve+the+interpreted+ENS+profile+of+that+name+in+the+same+query%21%0A++++++++++profile+%7B%0A++++++++++++description%0A++++++++++++avatar+%7B+httpUrl+%7D%0A++++++++++++addresses+%7B+ethereum+bitcoin+%7D%0A++++++++++++socials+%7B%0A++++++++++++++twitter+%7B+handle+httpUrl+%7D%0A++++++++++++++github+%7B+handle+httpUrl+%7D%0A++++++++++++%7D%0A++++++++++%7D%0A++++++++%7D%0A++++++%7D%0A++++%7D%0A%0A++++%23+Also+load+the+count+of+ENSv1+and+ENSv2+domains+owned+by+the+account%0A++++%23+to+see+if+they+have+domains+they+should+upgrade+to+ENSv2.%0A++++%23+For+simplicity+this+example+query+doesn%27t+include+additional+logic%0A++++%23+to+filter+out+domains+that+have+expired.%0A++++v1DomainsCount%3A+domains%28where%3A+%7B+version%3A+ENSv1+%7D%29+%7B+totalCount+%7D%0A++++v2DomainsCount%3A+domains%28where%3A+%7B+version%3A+ENSv2+%7D%29+%7B+totalCount+%7D%0A++%7D%0A%7D\&connection=https%3A%2F%2Fapi.alpha.ensnode.io\&variables=%7B%0A++%22address%22%3A+%220xd8da6bf26964af9d7eed9e03e53415d37aa96045%22%0A%7D)Open an interactive playground to execute this example on our [alpha ENSNode instance.](/docs/hosted-instances#ensnode-alpha) GraphQL ```graphql query HelloWorld($address: Address!) { # Lookup an Account by address. account(by: { address: $address }) { resolve { # Reverse resolve the ENS primary name of the account # using a convenient ETHEREUM alias for mainnet. primaryName(by: { chainName: ETHEREUM }) { # Get the regular interpreted variant of the primary name # and also the special beautified variant that optimizes names # containing special characters such as emojis for proper display in interfaces. name { interpreted beautified } resolve { # If the account has a primary name on Ethereum (mainnet), # forward resolve the interpreted ENS profile of that name in the same query! profile { description avatar { httpUrl } addresses { ethereum bitcoin } socials { twitter { handle httpUrl } github { handle httpUrl } } } } } } # Also load the count of ENSv1 and ENSv2 domains owned by the account # to see if they have domains they should upgrade to ENSv2. # For simplicity this example query doesn't include additional logic # to filter out domains that have expired. v1DomainsCount: domains(where: { version: ENSv1 }) { totalCount } v2DomainsCount: domains(where: { version: ENSv2 }) { totalCount } } } ``` Variables ```json { "address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" } ``` Output ```json { "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", "bitcoin": null }, "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](/docs/hosted-instances#ensnode-alpha). Live output depends on the configuration of your ENSNode instance and ENS state updates. cURL ```bash # POST JSON to your ENSNode Omnigraph endpoint (same path enssdk uses). curl -sS -X POST "https://api.alpha.ensnode.io/api/omnigraph" \ -H "Content-Type: application/json" \ -d '{ "query": "query HelloWorld($address: Address!) { account(by: { address: $address }) { resolve { primaryName(by: { chainName: ETHEREUM }) { name { interpreted beautified } resolve { profile { description avatar { httpUrl } addresses { ethereum bitcoin } socials { twitter { handle httpUrl } github { handle httpUrl } } } } } } v1DomainsCount: domains(where: { version: ENSv1 }) { totalCount } v2DomainsCount: domains(where: { version: ENSv2 }) { totalCount } } }", "variables": {"address":"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"} }' ``` Response ```json { "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", "bitcoin": null }, "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](/docs/hosted-instances#ensnode-alpha). Live output depends on the configuration of your ENSNode instance and ENS state updates. [Full ENS Omnigraph GraphQL API Documentation ](/docs/integrate/integration-options/omnigraph-graphql-api) [omnigraph-graphql-example app ](https://github.com/namehash/ensnode/tree/main/examples/omnigraph-graphql-example)Check out our omnigraph-graphql-example for a full example app. ### 4. Further Integration Options [Section titled “4. Further Integration Options”](#4-further-integration-options) Beyond [`enssdk`](/docs/integrate/integration-options/enssdk), [`enskit`](/docs/integrate/integration-options/enskit), and the [Omnigraph GraphQL API](/docs/integrate/integration-options/omnigraph-graphql-api), ENSNode exposes a deeper set of integration surfaces for advanced use cases: * **[ENSDb (SQL)](/docs/integrate/integration-options/ensdb)** — query the indexed ENSv1 and ENSv2 datasets directly via SQL for custom analytics or your own service layer, from any language with a Postgres driver. * **[ENSDb Writers (Indexers)](/docs/integrate/integration-options/ensdb-writers)** — enable all other layers of the ENSNode stack to build on your custom indexing engine. * **[ENSDb Readers (Custom APIs)](/docs/integrate/integration-options/ensdb-readers)** — build your own custom APIs and services on top of ENSDb using any programming language or framework. * **[ENSNode Plugins (Indexed Data Models)](/docs/integrate/integration-options/ensnode-plugins)** — define how onchain data should be indexed into ENSDb. * **[enscli (CLI)](/docs/integrate/integration-options/enscli)** — resolve names, look up records, and run ad-hoc Omnigraph queries from the terminal — built for humans and AI agents alike. * **[ensskills (AI agents)](/docs/integrate/integration-options/ensskills)** — a curated set of skills that gives AI coding agents a well-defined contract for working with ENS. * **[ensdb-cli (ENSDb Snapshots)](/docs/integrate/integration-options/ensdb-cli)** — bootstrap a fresh ENSDb in minutes from portable, versioned snapshots instead of waiting days on a full historical backfill. * **[ENSEngine (Live push notifications)](/docs/integrate/integration-options/ensengine)** — subscribe to ENS-aware live notifications driven by changes in ENSDb, so your apps can stop polling and start reacting. [See all Integration Options ](/docs/integrate/integration-options)Includes more advanced integration options not introduced in this quickstart guide # AI / LLM Tooling > AI and LLM tooling for building on ENSv2. We’re building the infrastructure to make ENS a first-class citizen for AI agents. The foundation for how developers and their AI agents reach for ENS is [`ensskills`](/docs/integrate/integration-options/ensskills), that teach your AI assistant about ENS, ENSNode, the ENS Omnigraph, and how to drive [`enscli`](/docs/integrate/integration-options/enscli) — an agent- and human-friendly CLI — on your behalf. Version compatibility with hosted instances [Our hosted ENSNode instances](/docs/hosted-instances) currently run ENSNode `1.15.2`. `ensskills` is version-locked to the ENSNode suite—the Omnigraph schema and example queries the skills teach are bundled at a specific version—so pin `ensskills@1.15.2` and the matching `enscli@1.15.2` to keep your agent's ENS knowledge and queries matched to the deployed API. ## Quickstart (`npm`/`pnpm`/`yarn`/`bun`) [Section titled “Quickstart (npm/pnpm/yarn/bun)”](#quickstart-npmpnpmyarnbun) Add `ensskills` and [`skills-npm`](https://github.com/antfu/skills-npm) to your project and wire a `prepare` script so the pinned skills re-sync into your agent directories (`.claude/skills`, `.cursor/skills`, …) on every install: package.json ```jsonc { "devDependencies": { "ensskills": "1.15.2", "skills-npm": "^1" }, "scripts": { "prepare": "skills-npm" } } ``` ```bash npm install # symlinks the skills for your detected agents ``` ## Quickstart (`npx skills`) [Section titled “Quickstart (npx skills)”](#quickstart-npx-skills) Not in a Node project? [`skills`](https://github.com/vercel-labs/skills) installs every ENS skill straight from the repo, pinned to the matching `v…` release tag: ```bash npx skills add https://github.com/namehash/ensnode/tree/v1.15.2/packages/ensskills/skills --skill '*' ``` ## Next Steps [Section titled “Next Steps”](#next-steps) That’s it — your AI agent now has all of [`ensskills`](/docs/integrate/integration-options/ensskills) at its disposal. prompt.md ```md Which address currently owns vitalik.eth and how many other domains do they own? ``` [enscli ](/docs/integrate/integration-options/enscli)An agent- and human-friendly CLI for the ENS Omnigraph API. [ensskills ](/docs/integrate/integration-options/ensskills)Skill bundles that give AI agents an opinionated contract for ENS. ## Documentation as `llms.txt` [Section titled “Documentation as llms.txt”](#documentation-as-llmstxt) If you aren’t using `ensskills`, the entire documentation site is also published in the [`llms.txt`](https://llmstxt.org/) format so any agent or LLM can load it directly as context: * [`/llms.txt`](https://ensnode.io/llms.txt) — a structured index of the documentation with links to every page. * [`/llms-full.txt`](https://ensnode.io/llms-full.txt) — the entire documentation concatenated into a single file, ready to drop into a model’s context window. Paste this at the top of a prompt to point your agent at the full documentation before asking your question: prompt.md ```md Load the ENSNode documentation from https://ensnode.io/llms-full.txt to answer the following question: ``` # ENS Subgraph > The ENS Subgraph quietly became critical infrastructure for ENS and the broader web3 ecosystem — and it cannot carry that ecosystem into ENSv2. Here's who depends on it, and what comes next. 🚨 The ENS Subgraph is not ENSv2 compatible The ENS Subgraph **fundamentally fails as a source of ENS data as soon as ENSv2 launches.** [Keep ENS apps working 🚨 ](/docs/integrate/why-ensnode/keep-ens-working)See apps currently set to break when ENSv2 launches unless they upgrade to the new ENS Omnigraph API. [Key Limitations 🚨 ](/docs/integrate/ens-subgraph/key-limitations)See the full list of Key Subgraph Limitations and how the Omnigraph addresses them. Start here instead: the ENS Omnigraph API The [ENS Omnigraph API](/docs/integrate/omnigraph) is the ENSv2-ready replacement: one unified, typed GraphQL API over **both ENSv1 and ENSv2**, multichain by default, with protocol-correct [ENS Protocol Acceleration](/docs/integrate/omnigraph/protocol-acceleration) resolution built in. [ENS Omnigraph API ](/docs/integrate/omnigraph)ENSv2-ready unified GraphQL API over both ENSv1 and ENSv2 — start here for new integrations. [ENS Unigraph SQL ](/docs/integrate/unigraph)Direct SQL access to the unified, multichain ENS data model. ## ENSNode Subgraph compatibility [Section titled “ENSNode Subgraph compatibility”](#ensnode-subgraph-compatibility) ENSNode maintains a verified Subgraph-compatible API for migrating existing integrations from The Graph, but it is **not** the path forward for ENSv2. [ENSNode’s Backwards Compatibility with the ENS Subgraph ](/docs/integrate/ens-subgraph/backwards-compatibility#ensnodes-backwards-compatibility-with-the-ens-subgraph)A verified Subgraph-compatible GraphQL endpoint for migrating existing integrations to ENSNode. # Backwards Compatibility > How ENSNode provides a verified Subgraph-compatible API for migrating existing integrations, the ecosystem it grew out of, and how to query it correctly. This page is background on the ENS Subgraph and the ecosystem ENSNode grew out of. ENSNode maintains a verified Subgraph-compatible API for migrating existing integrations, but it is **not** the path forward for ENSv2 — see [Key Limitations](/docs/integrate/ens-subgraph/key-limitations) and the [ENS Omnigraph API](/docs/integrate/omnigraph) for what is. ## The Graph & Graph Node [Section titled “The Graph & Graph Node”](#the-graph--graph-node) [The Graph](https://thegraph.com/) leads development of [Graph Node](https://thegraph.com/docs/en/indexing/tooling/graph-node/), an [open source software application](https://github.com/graphprotocol/graph-node) for indexing blockchain data. ## Subgraphs [Section titled “Subgraphs”](#subgraphs) Each Graph Node server can run any number of “subgraphs”. Each subgraph is essentially a plugin describing: 1. A strategy for how the Graph Node should index blockchain data. 2. A schema for a GraphQL API providing access to the indexed data. ## ENS Subgraph [Section titled “ENS Subgraph”](#ens-subgraph) [ENS Labs](https://www.enslabs.org/) has led development of the [ENS Subgraph](https://github.com/ensdomains/ens-subgraph). In the past, this was the “official” strategy for indexing ENS data. Additional background info is available in [official ENS docs](https://docs.ens.domains/web/subgraph). ## Graph Network [Section titled “Graph Network”](#graph-network) Operating your own Graph Node server instance can be complex, expensive, and time consuming. An alternative is to use The Graph’s semi-decentralized network of indexers operating Graph Node instances. This network provides access to a [semi-decentralized ENS Subgraph](https://thegraph.com/explorer/subgraphs/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH?view=Query\&chain=arbitrum-one). Developers are welcome to use this rate limited API endpoint above for testing, but are highly encouraged to sign up for an account with The Graph to get their own (paid) API key. ## ENSNode’s Backwards Compatibility with the ENS Subgraph [Section titled “ENSNode’s Backwards Compatibility with the ENS Subgraph”](#ensnodes-backwards-compatibility-with-the-ens-subgraph) To support the ENS ecosystem’s transition away from legacy ENS indexing strategies to ENSNode, ENSNode provides a verified backwards compatible ENS Subgraph GraphQL endpoint. This therefore also provides backwards compatibility with `ensjs`. 1. For those that wish to host their own ENS indexer, it is faster and easier to deploy ENSNode than to run an ENS Subgraph instance. 2. For those building an app that simply want to query the legacy ENS Subgraph API in the easiest way possible, we make this freely available through [our hosted ENSNode instances](/docs/hosted-instances). ## Self-hosted ENSNode instance configuration for ENS Subgraph compatibility [Section titled “Self-hosted ENSNode instance configuration for ENS Subgraph compatibility”](#self-hosted-ensnode-instance-configuration-for-ens-subgraph-compatibility) To enable full ENS Subgraph compatibility on a self-hosted ENSNode instance, configure ENSIndexer with `SUBGRAPH_COMPAT=true`. This single flag: 1. **Applies Subgraph Indexing Behavior**: Uses Subgraph Interpreted Labels and Names, allowing unnormalized labels to be returned as they appear in the original ENS Subgraph 2. **Sets Default Plugins & Label Set**: Defaults to `PLUGINS=subgraph`, `LABEL_SET_ID=subgraph` and `LABEL_SET_VERSION=0` to match subgraph indexing logic and label healing behavior When `SUBGRAPH_COMPAT=false` (default), ENSIndexer operates in enhanced mode with: * **Enhanced Indexing Behavior**: Uses Interpreted Labels and Names with improved security by encoding unnormalized labels as labelhashes * **Expanded Plugin Support**: Defaults to `PLUGINS=subgraph,basenames,lineanames,threedns,protocol-acceleration,registrars,tokenscope` for multichain ENS indexing * **Reverse Address Healing**: Attempts to heal subnames of addr.reverse for enhanced reverse resolution support ## Compatibility Tooling [Section titled “Compatibility Tooling”](#compatibility-tooling) ENSNode has developed tooling to verify subgraph compatibility and ease migration from the ENS Subgraph. The tools in the [ens-subgraph-transition-tools](https://github.com/namehash/ens-subgraph-transition-tools) repository help users verify ENSNode’s subgraph-compatibility. * `snapshot-eq` — verify subgraph-equivalent data via snapshots at specific blockheights See the [ens-subgraph-transition-tools](https://github.com/namehash/ens-subgraph-transition-tools) README for additional context and usage instructions. [ens-subgraph-transition-tools ](https://github.com/namehash/ens-subgraph-transition-tools)Tools for verifying ENSNode's subgraph compatibility ## Querying the Subgraph-Compatible API correctly [Section titled “Querying the Subgraph-Compatible API correctly”](#querying-the-subgraph-compatible-api-correctly) The care required to query the ENS Subgraph correctly is itself one of its [Key Limitations](/docs/integrate/ens-subgraph/key-limitations) — the guidance below exists because the Subgraph data model exposes raw protocol internals that every client has to handle carefully. If you are migrating an existing integration onto ENSNode’s Subgraph-compatible API, the following patterns apply. Terminology It may be helpful to refer to the [Terminology](/docs/reference/terminology) guide when reading this section. ### Use the node as the stable identifier [Section titled “Use the node as the stable identifier”](#use-the-node-as-the-stable-identifier) When querying for specific names or sets of names, it’s crucial to understand that the representation of labels (both known and unknown) should not generally be assumed to be immutable identifiers. Here’s why: **Label Mutability** * ENSNode indexes all onchain events where a subname is created in the ENS Registry. When these events are indexed, the labelhash of the subname is always known, however sometimes the label of the subname is unknown (strictly from indexed onchain data). When this happens ENSNode attempts to look up the label for the labelhash through an attached ENSRainbow server. If this lookup succeeds, ENSNode will represent the subname using its true label. If this lookup fails, some label to represent the subname is still required. Therefore, ENSNode will represent the “unknown label” using its labelhash in the format `[labelhash]`. * Changes in the set of healable labels maintained by an ENSRainbow instance can modify the resulting indexed state in attached ENSNode instances. For example, if at “time 1” ENSRainbow does not have knowledge to heal label X, but at “time 2” it does (from the perspective of an ENSNode client) a label represented as “unknown” at “time 1” could transition to become known at “time 2”. Each ENSNode instance should ensure it is attached to an ENSRainbow instance that only grows its set of healable labels across time, such that from the perspective of an ENSNode client a “known label” should never transition back to its “unknown” representation. However, if an ENSNode instance is improperly operated, such a situation could occur. **ENS Normalization Standard Changes** The [ENSIP-15: ENS Name Normalization Standard](https://docs.ens.domains/ensip/15) may change across time such that the set of normalizable names grows (thankfully it should never shrink). For example, consider a new Unicode release that standardizes new emoji. The ENS Normalize standard may subsequently change to expand support for those new emoji. Therefore, always use the node of a name (calculated by the namehash of the name) as the stable identifier when querying. The node of a name is immutable across time and works for all names, even if they are unknown, unnormalized, or subgraph-unindexable. #### Pattern 1: Names from User Input / Offchain Data [Section titled “Pattern 1: Names from User Input / Offchain Data”](#pattern-1-names-from-user-input--offchain-data) When querying for names that originate from user input (e.g., search fields, user-entered addresses) or offchain data (e.g. traditional data sources), always apply the following procedure within your app: 1. Normalize the name according to ENSIP-15. 2. Calculate the `node` for the normalized name using the `namehash` function. 3. Query the `id` field of domains using the `node` calculated in the previous step, rather than the name itself (for backwards compatibility with the ENS Subgraph, the field for the `node` of the name is actually the `id` field). Example: First, let’s prepare the name for querying by normalizing it and calculating its node: prep-example.ts ```typescript import { namehashInterpretedName, normalizeName, asInterpretedName } from "enssdk"; // 1. Normalize the user input according to ENSIP-15 const userInput = "Vitalik.eth"; const normalizedName = normalizeName(userInput); // 2. Calculate the node from the normalized name const node = namehashInterpretedName(asInterpretedName(normalizedName)); ``` Now use this node to query the domain id: query.graphql ```graphql { domain(id: "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835") { id name labelName labelhash createdAt } } ``` The query will return the domain information: response.json ```json { "data": { "domain": { "createdAt": "1497775154", "id": "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835", "labelName": "vitalik", "labelhash": "0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc", "name": "vitalik.eth" } } } ``` #### Pattern 2: Names from Onchain Data [Section titled “Pattern 2: Names from Onchain Data”](#pattern-2-names-from-onchain-data) When querying for name values sourced directly from onchain data (e.g., ENS NFTs, contract events), you must: 1. Skip any normalization step — the name value passed to namehash must be exactly as it appears onchain, even if unnormalized. 2. Calculate the node by taking the namehash of the onchain name (without any normalization). Be warned however that unnormalized labels may contain ”.” characters within the label value which can confuse namehash if special precautions are not taken. 3. Query the domain id using the node of the name. This pattern is crucial when dealing with unnormalized names that exist onchain. For example, if while examining onchain data you see a registration for “EXAMPLE.eth” (note the uppercase unnormalized characters), attempting to normalize this name in the process of querying for additional information about it would result in looking up details for a different node in the ENS Registry (in this case the node for “example.eth” rather than “EXAMPLE.eth”). The query structure in Pattern 2 remains the same as Pattern 1, except the normalization step is skipped to ensure the node that you query data about is the intended node. ### Never normalize labels returned by ENSNode [Section titled “Never normalize labels returned by ENSNode”](#never-normalize-labels-returned-by-ensnode) Configuration Note ENSNode’s handling of unnormalized labels is controlled by the `SUBGRAPH_COMPAT` configuration option: * `SUBGRAPH_COMPAT=true` allows unnormalized labels to be returned as Subgraph Interpreted Labels (required for full ENS Subgraph compatibility) * `SUBGRAPH_COMPAT=false` (default) encodes unnormalized labels as Interpreted Labels, improving security When `SUBGRAPH_COMPAT=true`, ENSNode may return unnormalized labels as [Subgraph Interpreted Labels](/docs/reference/terminology#subgraph-interpreted-label) associated with indexed names. **ENSNode clients should never attempt to normalize labels returned by ENSNode.** This is because when ENSNode returns an unnormalized label, that label is associated with a specific node that has been indexed. Normalizing an unnormalized label in this context would represent a different node. An ENSNode client is permitted to validate that all labels returned by ENSNode are in normalized form, and to reject any names with unnormalized labels from further processing. However, the key principle is that an ENSNode client should never normalize returned labels, as normalization transforms the label and therefore also the node associated with the name the label is contained within. When `SUBGRAPH_COMPAT=false` (default), ENSNode uses [Interpreted Labels](/docs/reference/terminology#interpreted-label) instead of [Subgraph Interpreted Labels](/docs/reference/terminology#subgraph-interpreted-label), which helps avoid edge cases related to null bytes, full-stop characters (periods), or exotic unicode characters. When names are returned from any of the ENSNode APIs, including the Subgraph-compatible GraphQL API, names will be [Interpreted Names](/docs/reference/terminology#interpreted-name). ### Calculating the node for names that contain Encoded LabelHashes [Section titled “Calculating the node for names that contain Encoded LabelHashes”](#calculating-the-node-for-names-that-contain-encoded-labelhashes) According to [ENSIP-1](https://docs.ens.domains/ensip/1#namehash-algorithm), the namehash algorithm makes no special consideration for Encoded LabelHashes, and therefore interprets Encoded-LabelHash-looking strings as Literal Label values. Due to this behavior, we recommend using an “Encoded-LabelHash-aware” namehash algorithm implementation such as the [viem namehash implementation](https://github.com/wevm/viem/blob/fe558fdef7e2e9cd5f3f57d8bdeae0c7ff67a1b0/src/utils/ens/namehash.ts#L36-L51). SUBGRAPH\_COMPAT The following is relevant when `SUBGRAPH_COMPAT=false` (default) and ENSNode is using Interpreted Labels for handling unknown labels. When an **Unknown** or `subgraph-unindexable` label is encountered, ENSNode represents it as an **Encoded LabelHash** in the format `[{labelhash}]`, where `{labelhash}` is the labelhash of the label in question. This representation creates an interesting edge case that must be handled carefully: Consider an unnormalized label that literally looks like `[24695ee963d29f0f52edfdea1e830d2fcfc9052d5ba70b194bddd0afbbc89765]`. Because this label contains square brackets (`subgraph-unindexable` characters), it will be represented as the unknown label: `[80968d00b78a91f47b233eaa213576293d16dadcbbdceb257bca94b08451ba7f]` Therefore, this represents the `subgraph-unindexable` label as an **Encoded LabelHash**, encoding the labelhash of the original unnormalized label (including its square brackets) in square brackets. This demonstrates why square brackets are considered `subgraph-unindexable` — they create ambiguity between literal labels and the representation of **Encoded LabelHashes**. When ENSNode encounters a `subgraph-unindexable` label, it will represent it as an **Encoded LabelHash** even if the actual label data is available. For more detailed information about `subgraph-unindexable` labels and their handling, please refer to the [ENSNode SDK implementation](https://github.com/namehash/ensnode/blob/main/apps/ensindexer/src/lib/is-label-subgraph-indexable.ts). ## Unplanned Features [Section titled “Unplanned Features”](#unplanned-features) The following features of the subgraph GraphQL API are explicitly unsupported and are not planned. * [1-level-nested Entity `_orderBy` param](https://thegraph.com/docs/en/subgraphs/querying/graphql-api#nested-entity-sorting-example) * [time travel queries](https://thegraph.com/docs/en/subgraphs/querying/graphql-api#time-travel-queries-example) * [\_change\_block filtering](https://thegraph.com/docs/en/subgraphs/querying/graphql-api#block-based-filtering-example) * [fulltext search queries](https://thegraph.com/docs/en/subgraphs/querying/graphql-api#full-text-search-example) # ENS Subgraph Examples > Examples of integrating ENSNode's Subgraph-compatible API with popular ENS libraries. Examples of integrating ENSNode’s Subgraph-compatible GraphQL API with popular ENS libraries. [With ENSjs ](/docs/integrate/ens-subgraph/examples/with-ensjs)Point @ensdomains/ensjs at an ENSNode Subgraph-compatible endpoint. [With Viem ](/docs/integrate/ens-subgraph/examples/with-viem)Configure a viem Chain's subgraph URL to use ENSNode. # Using ENSNode with ENSjs To use ENSNode with `@ensdomains/ensjs`, follow the [ENSjs documentation for custom subgraph URIs](https://github.com/ensdomains/ensjs/blob/17ab314/docs/basics/custom-subgraph-uris.md), replacing the subgraph URI with your ENSNode’s subgraph-compatible api endpoint. No backend required You don't need to run your own ENSNode to follow this guide — the steps below default to a NameHash-hosted instance. Browse the available deployments below. Version compatibility with hosted instances [Our hosted ENSNode instances](/docs/hosted-instances) currently run ENSNode `1.15.2`. The Omnigraph GraphQL schema is bundled inside the SDK and consumed by the `gql.tada` TypeScript plugin to type your queries, so pin an **exact** version (no `^` or `~`) of `enssdk@1.15.2` (and `enskit@1.15.2` when using React) to keep your generated types matched to the deployed schema. Use these exact install commands: ``` npm install enssdk@1.15.2 # or, for React apps: npm install enskit@1.15.2 enssdk@1.15.2 ``` [Hosted ENSNode Instances ](/docs/hosted-instances) example.ts ```ts import { http, createClient } from "viem"; import { mainnet } from "viem/chains"; import { addEnsContracts } from "@ensdomains/ensjs"; import { getNamesForAddress } from "@ensdomains/ensjs/subgraph"; const mainnetWithEns = addEnsContracts(mainnet); const chain = { ...mainnetWithEns, subgraphs: { ens: { // use the NameHash-hosted 'alpha' instance subgraph-compatible responses with (mainnet, Base, and Linea) names url: "https://api.alpha.ensnode.io/subgraph", // or use your own local instance // url: 'http://localhost:42069/subgraph', }, }, }; const client = createClient({ chain, transport: http(), }); const names = await getNamesForAddress(client, { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", // vitalik.eth }); ``` ## Well-Known Subgraph Queries [Section titled “Well-Known Subgraph Queries”](#well-known-subgraph-queries) Once ENSjs is pointed at an ENSNode Subgraph-compatible endpoint, its Subgraph functions work unchanged. ENSNode’s Subgraph-compatible GraphQL API provides full compatibility with these use cases (and all other possible queries, with the only exception of the [unplanned features](/docs/integrate/ens-subgraph/backwards-compatibility#unplanned-features)). The functions below are the patterns we see most often in the wild. Contributions If you’d like to highlight additional query patterns of the ENS Subgraph GraphQL, please [contribute to this documentation](https://github.com/namehash/ensnode/issues). ### ENSjs Subgraph functions [Section titled “ENSjs Subgraph functions”](#ensjs-subgraph-functions) * [`getDecodedName`](https://github.com/ensdomains/ensjs/blob/17ab314/packages/ensjs/src/functions/subgraph/getDecodedName.ts) — gets the full name for a name with unknown labels from the subgraph (heals encoded labels, splits the name into labels, finds domains by id, and queries the domain by namehash). * [`getNameHistory`](https://github.com/ensdomains/ensjs/blob/17ab314/packages/ensjs/src/functions/subgraph/getNameHistory.ts) — retrieves all events associated with a name. * [`getNamesForAddress`](https://github.com/ensdomains/ensjs/blob/17ab314/packages/ensjs/src/functions/subgraph/getNamesForAddress.ts) — gets all names related to an address via registrant, owner, wrappedOwner, and resolvedAddress; supports `searchString`, filtering (by expiry, reverse records, empty domains), ordering (by expiry date, name, labelName, createdAt), and pagination. * [`getSubgraphRecords`](https://github.com/ensdomains/ensjs/blob/17ab314/packages/ensjs/src/functions/subgraph/getSubgraphRecords.ts) — gets the records for a name from the subgraph; allows querying by a specific resolver id. * [`getSubgraphRegistrant`](https://github.com/ensdomains/ensjs/blob/17ab314/packages/ensjs/src/functions/subgraph/getSubgraphRegistrant.ts) — gets the name registrant from the subgraph (`.eth` second-level domains only). * [`getSubnames`](https://github.com/ensdomains/ensjs/blob/17ab314/packages/ensjs/src/functions/subgraph/getSubnames.ts) — gets the subnames for a name; supports `searchString`, filtering (by expiry, empty domains), ordering, and pagination. ### ENSv1 Manager App queries [Section titled “ENSv1 Manager App queries”](#ensv1-manager-app-queries) These query patterns come from the ENSv1 Manager App (`ens-app-v3`). They may not go through ENSjs directly, but they’re useful references for the kinds of Subgraph queries real apps depend on: * [`useResolverExists`](https://github.com/ensdomains/ens-app-v3/blob/328692ae832618f8143916c143b7e4cb9e520811/src/hooks/useResolverExists.ts#L27) — checks if a resolver exists. * [`useRegistrationData`](https://github.com/ensdomains/ens-app-v3/blob/328692ae832618f8143916c143b7e4cb9e520811/src/hooks/useRegistrationData.ts#L31) — gets registration by id and `nameRegistered` events. ## ENSjs Documentation [Section titled “ENSjs Documentation”](#ensjs-documentation) Refer to the ENSjs documentation for further usage. [ENSjs Documentation ](https://github.com/ensdomains/ensjs/) # Using ENSNode with `viem/chain` Some libraries (for example, [`ENSjs`](/docs/integrate/subgraph/examples/with-ensjs)) use a `viem/chain` object to identify the ENS Subgraph url. If you’re integrating with a library that expects a url in the `subgraph` key for your chain, you can update the `Chain` spec to use ENSNode like so: example.ts ```ts import { mainnet } from "viem/chains"; const mainnetWithENSNode = { ...mainnet, subgraphs: { ens: { url: "https://api.alpha.ensnode.io/subgraph" } }, }; ``` # Key Limitations > The ENS Subgraph was never designed to be a complete view of ENS. These are the limitations that break apps today — and that get worse the moment ENSv2 launches. The ENS Subgraph was never designed to be a complete view of ENS. It indexes a single chain’s events and exposes them largely as-is — leaving every app that builds on it to work around a long list of gaps. Many apps don’t work around them correctly, and the result is shipping real bugs in some of the most-used software in the ecosystem. Each of the following limitations is a place where the burden of getting ENS right is pushed onto app developers. There is a path forward The [ENS Omnigraph API](/docs/integrate/omnigraph) is built to close every gap on this page: one unified, typed API over ENSv1 and ENSv2, multichain by default, with [ENS Protocol Acceleration](/docs/integrate/omnigraph/protocol-acceleration) for resolution. ## Two systems, neither complete [Section titled “Two systems, neither complete”](#two-systems-neither-complete) DIY ENS Integrations are Hard Historically, full access to ENS data required two separate data-fetching strategies working in parallel: 1. **ENS resolution** — RPC calls with CCIP-Read support for offchain data (e.g. via `viem` or `wagmi`) to perform forward or reverse resolution. 2. **Indexed ENS data** — the ENS Subgraph, for discovering names owned by an address and all other ENS state outside of resolution. Neither system alone is complete. Resolution gives you resolver records but no access to the rest of ENS state, and it is painfully “close to the metal.” The Subgraph gives you queryable indexed data but cannot resolve names and carries the limitations below. Apps have had to live with the split, its limitations, and its downstream complexity — and **with ENSv2, the complexity of ENS’s onchain state meaningfully increases.** One unified API The [Omnigraph API](/docs/integrate/omnigraph) bundles access to ENS onchain resources (like Domains and Registrations) with Protocol Accelerated Resolution; a single unified API for all of your ENS needs. ## No ENS resolution — and apps that fake it are broken [Section titled “No ENS resolution — and apps that fake it are broken”](#no-ens-resolution--and-apps-that-fake-it-are-broken) Faking resolution ships real bugs The Subgraph does not perform ENS resolution. It has no concept of the ENS Universal Resolver, CCIP-Read, or ENSIP-10 wildcard resolution. Despite this, developers routinely reach for the Subgraph to resolve names — because it’s the indexed data source already in front of them — which produces incorrect results because it **doesn’t follow the ENS Forward Resolution protocol**. This isn’t hypothetical. It happens in widely-used software: * **[Stamp](https://github.com/snapshot-labs/stamp) by [Snapshot Labs](https://snapshot.box/)** powers the avatars across [Snapshot](https://snapshot.box/), among the most-used DAO infrastructure in the ecosystem. It resolves addresses [directly against the Subgraph](https://github.com/snapshot-labs/stamp/blob/a6d341a65159a1e76d1dc889156c4676e54eea14/src/addressResolvers/ens.ts#L87-L94). * **[ethVM](https://www.ethvm.com/) by [MyEtherWallet](https://www.myetherwallet.com/)** resolves names [via a generated Subgraph query](https://github.com/EthVM/EthVM/blob/2ad42adc544074ed8cd6c2cba6a7fa0ff4ffc48b/v2/src/core/composables/ResolveName/ensResolveName.generated.ts#L21-L30). * **[Ethereum Comments Protocol](https://github.com/ecp-eth/comments-monorepo)** resolves names [against an indexer query](https://github.com/ecp-eth/comments-monorepo/blob/c301d76fa56b6b807f135c98273ac9eb5ddebe95/apps/indexer/src/services/resolvers/ens-by-query-resolver.ts) rather than the resolution protocol. Each of these approaches produces results that diverge from what the ENS protocol *actually* says. Protocol-correct resolution The [Omnigraph API](/docs/integrate/omnigraph) performs protocol-correct resolution for you — including the CCIP-Read offchain lookups — so the correct result is the default. ## It forces you to stitch together multiple APIs [Section titled “It forces you to stitch together multiple APIs”](#it-forces-you-to-stitch-together-multiple-apis) You become the integration glue Because the Subgraph can’t resolve names, any app that needs both indexed data *and* resolution has to run two integrations side by side: the Subgraph for indexed state, and a resolution library for records. You reconcile their differences, their failure modes, and their data models yourself. Developers shouldn’t have to care about these implementation details of the ENS protocol — getting “all the ENS data I need,” whether ENSv1, ENSv2, indexed, or resolved, should come from a single unified API. Write your query once The [Omnigraph API](/docs/integrate/omnigraph) provides a unified datamodel across ENSv1 and ENSv2: write your query once and your platform automatically understands both protocol versions without any extra work on your end. ## ENSv1 only — blind to ENSv2 [Section titled “ENSv1 only — blind to ENSv2”](#ensv1-only--blind-to-ensv2) Stale the moment ENSv2 launches The Subgraph’s data model has no concept of ENSv2. The moment ENSv2 launches (Summer 2026), apps still reading the Subgraph are looking at a stale, partial view of ENS — missing the new ENSv2 Namegraphs entirely. There is no upgrade path: the schema was never designed for it. The Omnigraph transparently upgrades to ENSv2 The [Omnigraph API](/docs/integrate/omnigraph) provides a unified datamodel across ENSv1 and ENSv2: your app works before, during, and after the ENSv2 release without any changes. ## Single-chain only — misses most names [Section titled “Single-chain only — misses most names”](#single-chain-only--misses-most-names) Most ENS names are invisible The Subgraph indexes a single chain, so it never sees Basenames (`.base.eth`), Lineanames (`.linea.eth`), or 3DNS names (`.box`). A large and growing majority of ENS names already live off of mainnet and are simply invisible to it. Every chain in one schema The [Omnigraph API](/docs/integrate/omnigraph) indexes the full suite of onchain ENS names, including Basenames (`.base.eth`), Lineanames (`.linea.eth`) and 3DNS names (`.box`). ## No multichain primary names (ENSIP-19) [Section titled “No multichain primary names (ENSIP-19)”](#no-multichain-primary-names-ensip-19) No cross-chain primary names Beyond being single-chain, the Subgraph has no concept of [ENSIP-19](https://docs.ens.domains/ensip/19) multichain primary names. Even an app willing to query several per-chain Subgraphs cannot reconstruct a name’s primary-name configuration across chains from Subgraph data. Full ENSIP-19 support The [Omnigraph API](/docs/integrate/omnigraph) fully implements [ENSIP-19](https://docs.ens.domains/ensip/19) and accurately returns an account’s multichain primary names in milliseconds. ## No concept of the effective resolver (ENSIP-10) [Section titled “No concept of the effective resolver (ENSIP-10)”](#no-concept-of-the-effective-resolver-ensip-10) Wrong resolver, wrong records The Subgraph records the resolver *assigned* to a domain but has no understanding of [ENSIP-10](https://docs.ens.domains/ensip/10) wildcard resolution, and therefore no concept of the *effective* resolver — the resolver that actually answers for a name via a parent’s wildcard resolver. Apps that read the assigned resolver from the Subgraph and assume it’s the effective one get the wrong answer for any name that relies on wildcard resolution. Assigned and effective resolvers The [Omnigraph API](/docs/integrate/omnigraph) supports both a Domain’s *assigned* resolver as well as its [ENSIP-10](https://docs.ens.domains/ensip/10) *effective* resolver, so you can write applications that understand the difference, whether you’re resolving up-to-date records or letting users edit records onchain. ## Unnormalized names (ENSIP-15 not applied) [Section titled “Unnormalized names (ENSIP-15 not applied)”](#unnormalized-names-ensip-15-not-applied) Normalization is left to you The Subgraph does not apply [ENSIP-15](https://docs.ens.domains/ensip/15) name normalization. It returns unnormalized labels and names, putting the burden on every consuming app to implement normalization correctly and consistently — and the ones that don’t display or match names incorrectly. ENSNode [replaces unnormalized labels](/docs/integrate/ens-subgraph/backwards-compatibility#never-normalize-labels-returned-by-ensnode) for you, so you automatically enjoy safer handling. Interpreted Names by default The [Omnigraph API](/docs/integrate/omnigraph) stores and operates over [Interpreted Names](/docs/reference/terminology#interpreted-name), a consistent name format that ensures that names are composed of labels that are either normalized or [Encoded LabelHashes](/docs/reference/terminology#encoded-labelhash). This means consistent handling and fewer application bugs. ## Unstable domain identification [Section titled “Unstable domain identification”](#unstable-domain-identification) Identifiers shift underneath you Labels in the Subgraph are not stable identifiers. A label that is “unknown” today can become “known” later (as label-healing coverage grows), and the set of normalizable names can change over time. Apps that key on label or name strings will see identifiers shift underneath them. The only stable identifier is the `node` (the namehash of the name) — but the Subgraph schema surfaces it as the `id` field, and getting this right requires careful, documented handling. See [Use the node as the stable identifier](/docs/integrate/ens-subgraph/backwards-compatibility#use-the-node-as-the-stable-identifier). Stable IDs that never move The [Omnigraph API](/docs/integrate/omnigraph) provides stable identification via a Domain’s `id`, a multichain-aware globally unique identifier that works for both ENSv1 and ENSv2 Domains. Domains are also addressable by [InterpretedName](/docs/reference/terminology#interpreted-name), and a Domain’s Canonical Name (`Domain.canonical.name`) is always maximally healed at request time, thanks to [ENSRainbow](/docs/services/ensrainbow). ## Effective ownership is hard to determine [Section titled “Effective ownership is hard to determine”](#effective-ownership-is-hard-to-determine) Effective ownership is ambiguous The Subgraph schema spreads ownership across multiple fields — `owner`, `registrant`, `wrappedOwner` — reflecting raw protocol state (the Registry, the `.eth` Registrar, and the Name Wrapper). Determining the *effective* owner of a domain requires understanding the interplay of all of them. This is exactly the kind of protocol-implementation detail app developers are forced to learn and re-implement, with plenty of room to get it wrong. One effective owner field In the [Omnigraph API](/docs/integrate/omnigraph) `Domain.owner` is *always* the effective owner’s address — no weird edge-cases! For ENSv2 Domains, `Domain.owner` is Smart-Account-aware and represents the true owner of the Domain at a given time. ## Missing all offchain ENS names [Section titled “Missing all offchain ENS names”](#missing-all-offchain-ens-names) Offchain names are missing entirely The Subgraph indexes onchain events only, so it has no knowledge of offchain ENS names. A meaningful and growing slice of ENS lives offchain and is entirely absent from Subgraph data. Automatic offchain name resolution While the [Omnigraph API](/docs/integrate/omnigraph) doesn’t (*yet!*) index offchain names, it does provide protocol-correct Accelerated Forward Resolution, including support for offchain CCIP-Read-based names. ## Raw “bare-metal” values push the decoding burden onto you [Section titled “Raw “bare-metal” values push the decoding burden onto you”](#raw-bare-metal-values-push-the-decoding-burden-onto-you) Decoding is your problem The Subgraph exposes raw values straight from the ENS protocol, with none of the interpretation that apps actually need: * **Address records** may be for non-EVM chains and need chain-specific decoding before they’re usable. * **Contenthash** values are encoded and need decoding to become a usable URL. * **Text records** are represented by users in many inconsistent ways. Consider the many variations in how someone might set a Twitter/X handle — both the record key and the value vary widely. Every bit of this interpretation, decoding, and normalization is left to the app developer. The result is more bugs in ENS integrations across the ecosystem, which damages the network effects and growth of ENS. Interpreted records The [Omnigraph API](/docs/integrate/omnigraph) supports two major record resolution use-cases: 1. Protocol-accurate ‘raw’ requests, without post processing (`resolve.records`), and 2. Consumer-friendly semantic interpretation of records for, e.g. profile display (`resolve.profile`). ## It can’t cleanly power NFT-reference → avatar use cases [Section titled “It can’t cleanly power NFT-reference → avatar use cases”](#it-cant-cleanly-power-nft-reference--avatar-use-cases) Avatar resolution is painful A common and important flow is taking an NFT reference as input and mapping it: **NFT Ref → Domain → Name → Avatar text record → Avatar image.** This powers services like the ENS Metadata Service, which provides NFT metadata for ENS names using standardized protocols adopted by platforms such as OpenSea, Rarible, Grails, and ENS Vision. The Subgraph’s raw, resolution-free data model makes this flow far harder than it should be. Automatic avatars The [Omnigraph API](/docs/integrate/omnigraph) supports automatic avatar URL derivation, including deriving images from NFT references per [ENSIP-12](https://docs.ens.domains/ensip/12); all your app needs to do is render an `` tag! ## Unhealed names degrade developer and user experience [Section titled “Unhealed names degrade developer and user experience”](#unhealed-names-degrade-developer-and-user-experience) Unhealed labelhashes everywhere The Subgraph (and any data-level-compatible indexer) contains a large volume of unhealed names — names whose labels are only known as labelhashes (e.g. `[abcd…].eth`). These complicate both the developer experience and the UX of every app built on top, which must decide how to display and handle them. **What the heck is a `[428…b0b]`?** These are encoded labelhashes used to represent an unknown label in an ENS name. Without name healing, millions of names in the ENS manager app (and other ENS apps) don’t appear properly. See the problem for yourself: [Example 1](https://app.ens.domains/0xfFD1Ac3e8818AdCbe5C597ea076E8D3210B45df5) and [Example 2](https://app.ens.domains/%5B4283f2583432677d3dac6d2c021cdd7ef6855349ea584813ad5811c0e497eb0b%5D.makoto.eth). ![An ENS profile listing names where an unknown label is shown as an encoded labelhash instead of a readable name](/_astro/ens-profile-unhealed.DGkFNDhx_2toyiE.svg) \~94% healed, and climbing ENSNode already heals **\~94%** of these labels with [ENSRainbow](/docs/services/ensrainbow), compared to **\~11%** with the label set bundled into the traditional ENS Subgraph. [ENSRainbow](ensrainbow.io) has data for healing **259,053,605** unknown labels as of May 2026, and coverage is climbing toward a **99%** target. ![Name Healing Coverage chart: ENS Subgraph heals 11% of labels, ENSRainbow + ENSNode (current) heals 94%, and ENSRainbowBeam + ENSNode (target) reaches 99%, as of 26 May, 2026](/_astro/healing-coverage.BxZp7CQZ_Z1e6etR.webp) Healing turns these encoded labelhashes back into the readable labels they represent, so a name like `[428…b0b].makoto.eth` is displayed as the actual name a user expects. ![A split view of an ENS name card: on the left, the healed, readable name; on the right, the same name still showing an encoded labelhash](/_astro/healed-name-split.zxcMAwxY_ZnH13U.webp) See [ENSRainbow](/docs/services/ensrainbow) for how ENSNode uses this service to heal labels at request time. ## Thick-client lock-in [Section titled “Thick-client lock-in”](#thick-client-lock-in) Locked into a thick TypeScript client Achieving common ENS query operations correctly against the Subgraph requires meaningful additional logic. In practice that logic lives in “thick client” libraries — most notably `ensjs`, which embeds special-case handling for working with the Subgraph (e.g. decoding names, reconstructing histories, assembling the queries for names owned by an address). A thin client that simply wraps the GraphQL API can’t reproduce these behaviors. And because such thick clients are written for a single language (`ensjs` is TypeScript only), developers building on ENS in any other language don’t get them at all. Any client, any language The [Omnigraph API](/docs/integrate/omnigraph) is a Relay-compatible GraphQL API; bring your own GraphQL client library, or simply make GraphQL requests over HTTP and receive exactly the data you need! ## No type-safe API client [Section titled “No type-safe API client”](#no-type-safe-api-client) No type safety, no autocomplete The Subgraph’s auto-generated GraphQL API ships without a first-class, type-safe client. Developers are left hand-writing queries and types, with no compile-time guarantees that a query matches the schema or that responses are shaped as expected. Typed enssdk and enskit The [Omnigraph API](/docs/integrate/omnigraph) comes with [`enssdk` (TypeScript)](/docs/integrate/integration-options/enssdk) and [`enskit` (React)](/docs/integrate/integration-options/enskit) fully typed client libraries with built-in editor intellisense and autocomplete. ## Operational gaps [Section titled “Operational gaps”](#operational-gaps) Operations left half-solved Beyond the data-model limitations, the Subgraph’s auto-generated GraphQL API leaves common operational needs underserved: * **Pagination** is awkward and easy to implement incorrectly at scale. * **Caching** has no first-class story for ENS-shaped data. * **Indexing status** is hard to reason about — there’s no clear, app-friendly signal for how far behind realtime the data is (e.g. worst-case distance from the chain head). * **Joins** in the auto-generated API perform certain multi-entity operations in ways that don’t match what apps actually need, forcing client-side stitching. Relay pagination and caching The [Omnigraph API](/docs/integrate/omnigraph) supports [Relay Connections](https://relay.dev/graphql/connections.htm) for paginated resources; your app gets lightning-quick infinite scroll with minimal work! If using [`enskit` (React)](/docs/integrate/integration-options/enskit), the `useOmnigraphQuery` hook comes with Omnigraph-specific local cache directives for instant resolution of cacheable values. The Omnigraph’s idiomatic GraphQL API also aims to match consumer query patterns as closely as possible to negate complex and bespoke client-side logic; if your use-case isn’t yet supported, [open an issue on GitHub](https://github.com/namehash/ensnode/issues/new). ENSNode’s Indexing Status API ENSNode supports the [Indexing Status API](/docs/services/ensapi/reference/api-reference#tag/meta/GET/api/indexing-status) for up-to-date knowledge of ENSNode’s indexing status, including realtime lag, if any. ## Next Steps [Section titled “Next Steps”](#next-steps) Indexed ENS data is vital for the upcoming launch of ENSv2. The legacy ENS Subgraph is fundamentally unsuitable for ENSv2, and a replacement is critically required for many of ENS’s most important apps — including the official ENS Manager App. Build on the Omnigraph API or the Unigraph datamodel to take the guesswork out of your ENS integration. [Integrate with ENSNode ](/docs/integrate/integration-options)Integrate the Omnigraph API or the Unigraph datamodel # Integration Options > Integration options for building with ENSNode. ENSNode takes the guesswork out of ENS integrations, whether you need to resolve up-to-date records, search all Domains, or see which Domains a user owns (and much, much more). There are a few different ways to integrate with ENSNode, depending on your app, runtime, and needs. ## 1. enssdk [Section titled “1. enssdk”](#1-enssdk) With `enssdk`, leverage ENSNode and the ENS Omnigraph from any JavaScript runtime to power your frontend or backend apps. `enssdk` comes with built-in type-safety and editor autocomplete for Omnigraph queries. [enssdk Integration Documentation ](/docs/integrate/integration-options/enssdk) ## 2. enskit [Section titled “2. enskit”](#2-enskit) With `enskit`, leverage ENSNode and the Omnigraph to power your React components using `useOmnigraphQuery`. `enskit` comes with built-in type-safety, Omnigraph-specific cache directives, easy infinite pagination, and much much more. [enskit Integration Documentation ](/docs/integrate/integration-options/enskit) ## 3. Omnigraph GraphQL API [Section titled “3. Omnigraph GraphQL API”](#3-omnigraph-graphql-api) The Omnigraph API is a GraphQL API following the Relay specification, so you get built-in support for efficient infinite pagination and idiomatic access to all of the ENS protocol within a *unified* ENSv1 + ENSv2 datamodel. [Omnigraph GraphQL API Documentation ](/docs/integrate/integration-options/omnigraph-graphql-api) ## 4. ENSDb [Section titled “4. ENSDb”](#4-ensdb) For special use cases that go beyond what the ENS Omnigraph exposes, query the live state of ENSv2 directly via SQL. `ENSDb` stores ENS state in a PostgreSQL database — usable from any language with a Postgres driver. [ENSDb Integration Documentation ](/docs/integrate/integration-options/ensdb) ## 5. ENSDb Writers [Section titled “5. ENSDb Writers”](#5-ensdb-writers) Build your own indexer for ENSDb by implementing the [ENSNode Plugin](/docs/integrate/integration-options/ensnode-plugins) specifications you’re interested in indexing. ENSDb Writers index onchain data and write it into an ENSDb instance according to the standards set by relevant ENSNode Plugins. [ENSDb Writer Documentation ](/docs/integrate/integration-options/ensdb-writers) ## 6. ENSDb Readers [Section titled “6. ENSDb Readers”](#6-ensdb-readers) Build custom APIs or other specialized services on top of ENSDb. ENSDb Readers read indexed ENS data from an ENSDb instance and serve it through any API surface (GraphQL, REST, gRPC, webhooks, etc.) or pipe it into specialized data processing pipelines through the PostgreSQL write-ahead-log. [ENSDb Reader Documentation ](/docs/integrate/integration-options/ensdb-readers) ## 7. ENSNode Plugins [Section titled “7. ENSNode Plugins”](#7-ensnode-plugins) ENSNode Plugins are abstract specifications that define indexed data models relevant to ENS. They are a key architectural piece that enables complete decoupling between ENSDb Writers and ENSDb Readers. [ENSNode Plugins Documentation ](/docs/integrate/integration-options/ensnode-plugins) ## 8. enscli [Section titled “8. enscli”](#8-enscli) `enscli` is a CLI that wraps `enssdk` to bring the ENS Omnigraph to the terminal. Designed for developers exploring or validating integrations, operators wiring ENS lookups into shell pipelines, and AI coding agents driving `ensskills`. [enscli Integration Documentation ](/docs/integrate/integration-options/enscli) ## 9. ensskills [Section titled “9. ensskills”](#9-ensskills) `ensskills` is a collection of curated skill bundles that give AI coding agents a well-defined contract for working with ENS — powering conversational ENS lookups and streamlining integration code written with `enskit`, `enssdk`, or the raw Omnigraph API. [ensskills Integration Documentation ](/docs/integrate/integration-options/ensskills) ## 10. ensdb-cli & ENSDb snapshots [Section titled “10. ensdb-cli & ENSDb snapshots”](#10-ensdb-cli--ensdb-snapshots) `ensdb-cli` is the operator-facing tool for ENSDb snapshots — portable, versioned packages of an ENSDb instance. Pull one down, restore it into Postgres, and start querying ENS in minutes instead of waiting days to complete a full historical indexing backfill from scratch. [ensdb-cli & ENSDb snapshots Documentation ](/docs/integrate/integration-options/ensdb-cli) ## 11. ENSEngine [Section titled “11. ENSEngine”](#11-ensengine) ENSEngine watches your ENSDb for changes in real time and delivers ENS-aware events — including webhooks — to any sink you configure. Stop polling and start reacting to ENS state changes. [ENSEngine Integration Documentation ](/docs/integrate/integration-options/ensengine) # enscli (CLI) > An agent- and human-friendly CLI for ENS — query the ENS Omnigraph, explore the schema, resolve hashes, heal labels, and check indexing status from the terminal. `enscli` is the CLI entry point to ENS. It wraps [`enssdk`](/docs/integrate/integration-options/enssdk) and the [ENS Omnigraph](/docs/integrate/omnigraph) so you can resolve names, look up records, search domains, and run ad-hoc GraphQL queries against any ENSNode instance — without writing a script first. It is designed to feel natural whether you drive it yourself or let an AI agent drive it: predictable arguments, machine-readable output, runtime schema introspection, and loud, structured errors. Version compatibility with hosted instances [Our hosted ENSNode instances](/docs/hosted-instances) currently run ENSNode `1.15.2`. `ensskills` is version-locked to the ENSNode suite—the Omnigraph schema and example queries the skills teach are bundled at a specific version—so pin `ensskills@1.15.2` and the matching `enscli@1.15.2` to keep your agent's ENS knowledge and queries matched to the deployed API. ## Quick start [Section titled “Quick start”](#quick-start) No install step beyond `npx`: ```bash # Namehash a Name npx enscli namehash vitalik.eth # Run a GraphQL query against the Omnigraph (default: mainnet) npx enscli ensnode omnigraph '{ domain(by: { name: "vitalik.eth" }) { owner { address } } }' ``` ## Output contract [Section titled “Output contract”](#output-contract) `enscli` is built for predictable parsing: * **JSON when piped, pretty in a TTY.** When stdout is not a terminal (i.e. for agents), every command prints JSON; interactively you get a friendlier rendering. Force either with `--output json` or `--output pretty`. * **Structured errors.** Failures print `{ "error": { "message": "…" } }` to stderr and exit non-zero. * **Input hardening.** Names, labels, and hashes containing control characters or `?`/`#`/`%` are rejected before any network call. ## Selecting an ENSNode instance [Section titled “Selecting an ENSNode instance”](#selecting-an-ensnode-instance) Most `ensnode` commands talk to an ENSNode instance. The target URL is resolved with this precedence: **`--ensnode-url` flag → `ENSNODE_URL` env → `.env` → namespace default.** `--namespace` (alias `-n`, or the `NAMESPACE` env var) selects a NameHash-hosted instance: | Namespace | Hosted default | | ------------ | -------------------------------------- | | `mainnet` | `https://api.alpha.ensnode.io` | | `sepolia` | `https://api.alpha-sepolia.ensnode.io` | | `sepolia-v2` | `https://api.v2-sepolia.ensnode.io` | ```bash npx enscli ensnode indexing-status --namespace sepolia npx enscli ensnode indexing-status --ensnode-url http://localhost:4334 ``` ENSRainbow commands resolve their URL similarly via `--ensrainbow-url` / `ENSRAINBOW_URL`. ## Commands [Section titled “Commands”](#commands) ### `ensnode omnigraph ` [Section titled “ensnode omnigraph \”](#ensnode-omnigraph-query) Send a raw GraphQL query — the string is the exact payload, so the [schema](#ensnode-omnigraph-schema-typefield) doubles as your documentation. ```bash npx enscli ensnode omnigraph 'query D($name: InterpretedName!) { domain(by: { name: $name }) { canonical { name { interpreted } } resolve { records { addresses(coinTypes: [60]) { address } } } } }' --variables '{"name":"vitalik.eth"}' ``` Tip GraphQL is naturally field-masked — select only the fields you need to keep responses small and avoid context bloat. Resolution lives in the graph: select `Domain.resolve` (records) and `Account.resolve` (primary names) inline rather than as separate calls. [ENS Omnigraph API ](/docs/integrate/omnigraph)The full data model, resolution, and query patterns. ### `ensnode omnigraph schema [Type[.field]]` [Section titled “ensnode omnigraph schema \[Type\[.field\]\]”](#ensnode-omnigraph-schema-typefield) Explore the Omnigraph schema offline (it ships with the CLI — no network): ```bash npx enscli ensnode omnigraph schema # root query fields + major types npx enscli ensnode omnigraph schema Domain # a type's fields, with descriptions npx enscli ensnode omnigraph schema Domain.canonical # a single field npx enscli ensnode omnigraph schema --search primary # find types/fields by keyword ``` ### `ensnode indexing-status` [Section titled “ensnode indexing-status”](#ensnode-indexing-status) ```bash npx enscli ensnode indexing-status ``` ### `ensrainbow heal ` / `ensrainbow count` [Section titled “ensrainbow heal \ / ensrainbow count”](#ensrainbow-heal-labelhash--ensrainbow-count) ```bash npx enscli ensrainbow heal 0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc npx enscli ensrainbow count ``` ### `datasources identify
` [Section titled “datasources identify \
”](#datasources-identify-address) Identify a well-known ENS contract by address — given `0xabc…`, report which datasource contract it is across the namespace’s chains. Fully offline (the datasource catalog ships with the CLI). Accepts a bare address, a chain-scoped `chainId:address`, or full CAIP-10 `eip155:chainId:address`; `--namespace` (default `mainnet`) selects which namespace to search. ```bash npx enscli datasources identify 0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e # bare address (mainnet) npx enscli datasources identify 1:0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85 # scope to a chain npx enscli datasources identify 0x94f523b8261b815b87effcf4d18e6abef18d6e4b -n sepolia # another namespace ``` The result is `{ query, matches }`. A miss is not an error: `matches` is `[]` with exit code `0`, so branch on `matches.length` rather than the exit code. Contracts indexed only by event (no fixed address) can’t be identified and are never returned. ### `namehash ` / `labelhash