Open-source documentation for structured data, identity verification, and search indexing of ENS-based pages.
Reference implementation:
ookyet.eth— measured outcomes in Results.
Privacy: see the Privacy Notice.
ENS domains like vitalik.eth or ookyet.eth often lack structured entity markup on an associated website. Without machine-readable Person/Organization data and cross-source consistency, they may not appear as named entities in web search results or Knowledge Panels.
A documented five-layer approach for entity markup and indexing submission:
- Google Indexing API - 24-48 hour indexing vs 7+ days traditional crawl
- IndexNow - Bing/Yandex instant indexing
- Direct submission bypasses crawl queue
- Schema.org @graph - Structured entity data
- Person/Organization types - Standard Schema.org entity types
- hasCredential properties - Dentity/ENS verification signals
- Dentity Unique Human verification - Anti-Sybil KYC
- Government ID + Biometric - Third-party liveness and document checks
- Verification checklist - Provider-specific credential status
@graphwith shared@idreferences - Person, ProfilePage, WebSite, and Article entities are explicitly linked through stable@idURIs, so Google parses one cohesive entity rather than several disconnected ones- ProfilePage with
mainEntity→ Person - signals the page's primary subject is a Person entity (per Schema.org ProfilePage). Google requiresmainEntityto be aPersonorOrganization; emit exactly one ProfilePage on the canonical "about" page. FAQ Schema (— RETIRED - Google limited FAQ rich results to authoritative government/health sites in Aug 2023, then fully removed the feature from Search on May 7, 2026 (FAQ structured-data docs removed June 15, 2026). Do not emitFAQPage)FAQPagefor entity SEO — keep FAQ as visible page content. (HowTolikewise retired Sep 2023;QAPageis still supported but only for a single user-submitted Q&A page, not authored FAQ copy.)
- Unified cross-platform identity - Consistent name/avatar/links across Web2/Web3 (audited count in Results)
- NFT avatar - Visual identity proof
- sameAs linkage - Cross-source consistency
- Off-site co-occurrence - real name and handle together on every authority profile (LinkedIn, ORCID) so Google reconciles the alias itself; display name where it reads natively, otherwise leading the bio — see Step 4.3 of the guide
See ookyet.eth for a production example:
- ✅ ENS Domain: ookyet.eth (owned since 2023)
- ✅ Dentity Verified: Unique Human KYC (10/10 checks)
- ✅ NFT Avatar: Lil Ghost #761 on-chain proof
- ✅ Indexed entity: Person + Organization + ProfilePage detected, 0 errors (Rich Results Test)
- ✅ SERP features: Position 1, Sitelinks, Image pack, AI Overview entity mention
Technical Deep-Dive: Identity Through ENS Complete Proof Hub: ookyet.com/proof
Person-first naming. Make the Person your single primary entity. Its name
should read like a person/handle (e.g. Your Name or yourhandle), not the ENS
domain. Put the ENS name in alternateName and as an identifier — it is a
verifiable anchor, not the entity's primary key. This keeps Google's person entity
keyed to a human/handle while ENS corroborates it.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Person",
"@id": "https://yoursite.com/#Author",
"name": "Your Name",
"alternateName": ["yourname.eth", "@yourhandle"],
"hasCredential": [{
"@type": "EducationalOccupationalCredential",
"name": "Dentity Verified Human",
"credentialCategory": "Identity Verification"
}],
"identifier": [
{
"@type": "PropertyValue",
"propertyID": "ens",
"value": "yourname.eth",
"url": "https://app.ens.domains/name/yourname.eth"
}
]
}
</script>Per Google's ProfilePage documentation, the page's primary focus must be a single person/organization affiliated with the site (an "About" / author page qualifies). mainEntity must be a Person or Organization, and name is required. Google also recognizes sameAs, identifier, description, and dateCreated/dateModified on the entity. This markup feeds Google's Discussions and Forums understanding of who a creator is.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfilePage",
"@id": "https://yoursite.com/#ProfilePage",
"dateCreated": "2023-01-01T00:00:00+00:00",
"dateModified": "2026-06-29T00:00:00+00:00",
"mainEntity": {
"@type": "Person",
"@id": "https://yoursite.com/#Author"
}
}
</script>Google limited FAQ rich results to authoritative government/health sites in Aug 2023, then fully removed the feature from Search on May 7, 2026 (FAQ structured-data docs removed June 15, 2026). Emitting
FAQPageno longer produces a rich result and can surface as an invalid item / "Q&A" issue in Search Console. Keep FAQ content as visible page copy instead.HowTois likewise retired (Sep 2023).QAPageremains supported but only for a single user-submitted Q&A page — not authored FAQ/marketing content.The former
FAQPageexample is kept below for historical context only — do not deploy it:
<!-- RETIRED: do NOT deploy. FAQPage no longer yields rich results and may trigger GSC errors. -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [{
"@type": "Question",
"name": "Who is yourname.eth?",
"acceptedAnswer": { "@type": "Answer", "text": "..." }
}]
}
</script>
⚠️ The Google Indexing API is NOT for identity/profile pages. Per Google's policy, the Indexing API may only be used for pages withJobPostingorBroadcastEvent(in aVideoObject). In May 2025 Google reiterated it "may stop supporting unsupported content formats without notice," and misuse can get API access revoked. For an identity/ProfilePagelike/proof/, do not call the Indexing API — submit a sitemap and, for a one-off, use Search Console → URL Inspection → "Request indexing." IndexNow (below) covers Bing/Yandex.
The API call itself, shown only for the content types Google actually allows (e.g. a JobPosting page):
const { google } = require('googleapis');
async function submitToIndexingAPI(url) {
const auth = new google.auth.GoogleAuth({
keyFile: 'service-account.json',
scopes: ['https://www.googleapis.com/auth/indexing']
});
const indexing = google.indexing({ version: 'v3', auth });
await indexing.urlNotifications.publish({
requestBody: { url, type: 'URL_UPDATED' }
});
}
// Allowed: a JobPosting / BroadcastEvent page only.
await submitToIndexingAPI('https://yoursite.com/jobs/some-job-posting/');Based on the ookyet.eth implementation:
| Metric | Before | After | How measured |
|---|---|---|---|
| Google indexing time (per page) | 7-30 days | 24-48 hours | Google Search Console "Last crawl" timestamps |
SERP features for ookyet / ookyet.eth |
None | Position 1, Sitelinks, Image thumbnail, Image pack | Reproducible — search ookyet / ookyet.eth |
| Entity recognition in AI Overview | None | Google's AI Overview answers that ookyet "is indeed an entity," resolving the person (real name), the ookyet.eth ENS name, and the NFT avatar from 6-7 cross-linked sources |
Reproducible — search ookyet or ookyet is entity |
| Search performance (cumulative since first indexed, Aug 2025) | — | Avg position 1.4, CTR 11.1% (11.8K impressions / 1.31K clicks) | Search Console → Performance (Web); ookyet.com was first indexed Aug 2025, so these are ~10 months of cumulative data |
| Rich Results Test status | N/A | 0 errors, Person + ProfilePage detected | Google Rich Results Test |
Cross-platform sameAs links |
0 | 15+ verified profiles | Manual audit of profile links in sameAs array |
| Google Knowledge Graph entity node | None (KG API returned no entity) | Machine-generated Person node confirmed 2026-07-02 — query ookyet resolves uniquely to MID /g/11z806my44 |
KG Search API, reproducible (see milestone) |
| Knowledge Panel (formal KP box) | Not triggered | Still not triggered — a KG entity node is the mechanical prerequisite for a KP, not the KP itself | Google KG API + direct SERP |
AI Overview entity recognition ≠ a Knowledge Panel. Being narrated as an entity in an AI Overview (achieved above) means Google has resolved and understood the entity; a formal Knowledge Panel is a separate, black-box decision Google has not made here. (AI Overviews are generated and can vary between queries/sessions; the entity recognition above has been observed stable over an extended period.) The Knowledge Graph API exposes no "candidate"/pre-trigger state, so any "% probability of KP trigger" is an internal model estimate, not a Google metric. This project optimizes for verifiable entity understanding, not for forcing a KP.
About 11 months after first indexing (Aug 2025), the Google Knowledge Graph Search API returns a machine-generated Person node for this implementation:
curl "https://kgsearch.googleapis.com/v1/entities:search?query=ookyet&limit=10&indent=true&key=YOUR_API_KEY"
# → exactly one result: kg:/g/11z806my44 (@type: Person)Why this is the outcome the architecture targets:
/g/MID = a machine-minted node (post-Freebase), created by Google's own cross-source reconciliation. It cannot be registered or bought — only corroborated into existence. This is entity resolution, not document retrieval.- Zero-ambiguity resolution. The KG holds 8 distinct Person nodes sharing the author's real name; the query
ookyetresolves uniquely to this one. A coined handle works as a cross-namespace disambiguation key (handle → person), which is exactly what a Person-first entity model is for. - Third-party corroboration outweighs self-declaration. The node's canonical name is the author's real name (Qifeng Huang — see CITATION.cff), taken from high-authority anchors (LinkedIn, ORCID) rather than the site's self-declared
name: ookyet. Expected and healthy: the handle stays the unique entry point; the legal name carries source authority. - Honest status. The node is still sparse (no
detailedDescription,image, orurlexposed; near-zeroresultScore), and a formal Knowledge Panel remains untriggered. Growth from here is driven by independent third-party coverage plus time — not by further markup changes.
Post-milestone monitoring: the growth staircase. Once a node exists, check it weekly, not daily — KG ingestion runs on a weeks-to-months cycle, and repeat queries within a day return byte-identical results (verified). A sparse Person node typically grows in a predictable order, so read the fields by priority:
url— usually first. It means Google has bound your entity home to the node; it is driven by the corroboration you already shipped (Person-first graph + ProfilePage + consistentsameAs), not by new signals.image— next; drawn from the node's reconciled visual identity (a consistent avatar across sources keeps the candidate pool unambiguous).resultScorerising by an order of magnitude — a precursor of display-worthiness.detailedDescription— usually last, and often never for niche entities: it is largely sourced from encyclopedic references (Wikipedia/Wikidata), which are notability-gated. An empty description does not block the other fields.
First weekly check (2026-07-07, five days after discovery): all fields unchanged — expected, not a negative signal. Practical notes: KG Search API keys expire (renew before concluding anything from an error response), and "the node has grown url" is the point at which "Knowledge Panel plausible soon" becomes a defensible statement.
Recovery-playbook validation (same window). The reference site's structured-data fix (retiring QAPage, fixing ProfilePage.mainEntity; deployed Jun 28) was confirmed digested by Google on Jul 7: the GSC Profile page report turned valid (1 item, 0 invalid), indexed pages rose 4 → 6, and 404s stayed at 0 — about 9 days from deploy to report-level validation, with zero further schema edits in between. This is the "fix once, freeze, wait" discipline working as designed; re-tweaking mid-window would have reset Google's evaluation clock. (Related GSC note: Test Live URL is read-only — it never queues a crawl or resets anything; only Request Indexing sends an active signal.)
Timeline: Aug 2025 first indexed → Oct 2025 Dentity verification + entity markup → Jun 2026 Person-first convergence (single Person entity; FAQ/HowTo retired) → Jul 2, 2026 KG entity node confirmed via API → Jul 7, 2026 GSC structured-data recovery confirmed (ProfilePage valid; indexed pages 4→6) → Jul 8–12, 2026 corpus-supply window: the stale 2025 self-published article superseded by a current retrospective (published Jul 8, indexed within days), first ORCID works entry mounted on the anchor (blog-post type, public-API-verified) → Jul 16–18, 2026 second corpus pillar: the CSS migration pattern behind the reference site released as a standalone library on GitHub and npm (the package page's author field is the identity's first open-web real-name+handle co-occurrence surface outside login-walled platforms); both repositories mounted as ORCID software works; the combined-query confidence ladder measured — real-name+handle queries score 800× the bare handle on the same node, unique at every rung.
The same API that confirmed this project's entity node returns nothing — or worse — for identities with far larger audiences (measured 2026-07-19/20; cases deliberately anonymized: the point is the pattern, not the people).
- The famous developer. An open-source author with an order of magnitude more stars and followers than this project's reference identity: the KG returns empty for their handle. Scattered prestige — stars, follows, walled-garden activity — is not a form the graph ingests. The Knowledge Graph doesn't count stars; it reads structure.
- The generic brand word. A brand named after a common English phrase: its query returns unrelated songs and legacy entities. A name that collides with natural language never routes uniquely. The coined-word advantage is structural and permanent.
- The pseudonymous celebrity. A globally known Web3-era creator — mainstream press coverage, seven-figure sales history — returns empty for both the real-name and handle queries, while the alias is crushed by an entrenched legacy entity of the same name; what may remain of an earlier node is a stripped, near-scoreless shell. This is the deepest failure mode: fame without Person reconciliation does not persist. A pseudonymous identity with no real-name binding gives Google no way to confirm which human this is. A panel granted during a hype cycle can ride shallow query-level mapping without a reconciled entity underneath — and shallow panels are the first casualties of a recalibration. Reconciled entities survive years of dormancy; unreconciled fame does not survive one re-evaluation. Note also the conversion trap: this creator still posts weekly, but activity inside login-walled platforms is high-volume, zero-conversion supply — the graph never sees it. Postscript, measured a day later: the entrenched same-alias entity turns out to be a modestly known film director whose full panel is fed by the movies vertical (IMDb) — API-sparse fields, complete panel. Feed membership beat world fame, and a displayed panel re-wins the alias with every impression, making the collision permanent.
The sequence this playbook encodes is the inverse: reconciliation before display. Confirm the entity first (Person-first graph, real-name binding on authority anchors, unique routing), and a panel — if it comes — sits on owned foundations rather than a news cycle. And once node fields appear, supply does not stop; it shifts from launch fuel to life support.
┌─────────────────────────────────────────────────┐
│ Google Knowledge Graph │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ Entity: ookyet (alt: ookyet.eth) │ │
│ │ Type: Person │ │
│ │ Verification: Dentity ✓ │ │
│ │ KG node: /g/11z806my44 (2026-07-02) │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
▲
│
│ 5-Layer Signals
│
┌─────────────────────────────────────────────────┐
│ ookyet.eth Website │
│ │
│ Layer 1: Indexing API ──────────────────────┐ │
│ Layer 2: Schema.org @graph ─────────────────┤ │
│ Layer 3: Dentity Unique Human ──────────────┤ │
│ Layer 4: Entity Graph Linkage ──────────────┤ │
│ Layer 5: Cross-Platform sameAs linkage ─────┘ │
│ │
│ Result: KG Person node minted on 2026-07-02 │
│ (KP triggering is Google's black-box decision) │
└─────────────────────────────────────────────────┘
- ENS (Ethereum Name Service) - Blockchain naming system
- Dentity - Unique Human KYC verification
- Schema.org - Structured data standard
- Google Indexing API - Direct indexing submission
- IndexNow - Multi-search-engine indexing protocol
- Issues: actionable, verifiable suggestions only (observability/privacy/minimization). For ideas, use Discussions.
- Labels:
proposal:observability,privacy-reviewed,wontfix:ranking.
- Publish structured Person/Organization markup tied to an ENS name
- Express on-chain ownership and optional third-party verification in
identifier/hasCredential - Link a canonical website and social profiles via
sameAs
- Document a repeatable pattern for aligning on-chain names with a public site
- Provide cross-source consistency signals search engines can parse
- Machine-readable entity graphs (
@graph, ProfilePage, Person) - Optional proof-of-personhood credentials where applicable
- Explicit cross-platform linkage for entity disambiguation
The complete implementation demonstrates:
-
ENS Ownership Proof
- Domain: ookyet.eth
- Wallet: 0xC5F1c8b15A658B1b36A0CF2c64b45101568B17fF
- On-chain since 2023
-
Dentity Verification
- Unique Human KYC: ✅ 10/10 checks
- Government ID: ✅ Verified
- Biometric Liveness: ✅ Verified
- Anti-Sybil Database: ✅ Unique
-
NFT Avatar Integration
- Lil Ghost #761 (verifiable on-chain)
- Consistent visual identity
- OpenSea ownership proof
-
Search indexing and markup
- Schema.org complete @graph (Person-first; FAQ/HowTo/QAPage not emitted)
- ProfilePage with
mainEntity→ Person on the about page - Consistent cross-platform
sameAs+ verifiableidentifier/hasCredential
Full Technical Breakdown: https://ookyet.com/blog/identity-through-ens/ Proof hub: https://ookyet.com/proof/
- ENS domain (register at app.ens.domains)
- Dentity verification (dentity.com)
- Website/Hugo site
- Google Cloud service account
The fastest path is to fork this repository and adapt the reference schema to your own identity:
- Fork this repo — you'll be editing the schema examples and scripts to match your identity, so start from your own copy.
- Replace the placeholder values in
examples/schema-person.json: your domain (yoursite.com), your ENS name (yourname.eth), and your handle (@yourhandle). - Serve the JSON-LD server-side as a single
@graph— one source of truth, no client-side injection (implementation guide). - Verify, then submit: pass the Rich Results Test with zero errors, then accelerate indexing with the Indexing API and IndexNow scripts in
scripts/. - Bind your off-site profiles — LinkedIn, ORCID, GitHub — to the same name/handle pair (guide, Step 4.3).
- ProfilePage (
mainEntity→ Person) on the about page - Person-first entity model (name = person/handle; ENS in
alternateName+identifier) - Cross-platform unification and off-site co-occurrence (guide, Step 4.3)
- Image structured data for the Google Images surface (guide, Advanced Optimization)
- Monitoring with kg-audit.sh
- Reference example: ookyet.eth
- Technical Blog: Identity Through ENS
- ENS Domains: app.ens.domains
- Dentity KYC: dentity.com
- Google Indexing API: Google Documentation
Improvements welcome. See CONTRIBUTING.md for scope, process, and issue policy.
Git commit guard setup:
git config core.hooksPath .githooks
chmod +x .githooks/commit-msg scripts/commit-message-guard.sh- Code —
scripts/,.github/, and the copy-paste JSON-LD templates inexamples/: MIT. Drop them into your own site freely; no attribution required. - Documentation — README, CHANGELOG, and everything under
docs/: CC BY 4.0. Share and adapt freely, with credit to Qifeng Huang (ookyet) and a link back to this repository.
This project is independent documentation. It is not affiliated with, endorsed by, or sponsored by Google, the Ethereum Name Service (ENS), Dentity, Microsoft, or Yandex; all trademarks and product names are the property of their respective owners. Search result appearance — including Knowledge Panels — is determined solely by the search engines and is not guaranteed by anything in this repository. Nothing here is financial, legal, or investment advice.
Reference implementation: ookyet.eth.