<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SementicSEO]]></title><description><![CDATA[Learn Semantic SEO with practical guides, AI-powered strategies, topical authority, structured data, and modern search optimization techniques to improve rankings.
]]></description><link>https://sementicseo.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a719ec223e561da56d328fe/8f91de22-e3c9-4dcc-a814-55ce05664f1f.png</url><title>SementicSEO</title><link>https://sementicseo.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 07 Nov 2026 10:35:13 GMT</lastBuildDate><atom:link href="https://sementicseo.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Entity SEO for AI Search: 
A 3- Layer JSON-LD Blueprint]]></title><description><![CDATA[A connected entity graph in JSON-LD takes 3 layers: a canonical Entity Home, sameAs identity links, and typed service and area attributes. The examples use…]]></description><link>https://sementicseo.hashnode.dev/entity-seo-for-ai-search-a-3-layer-json-ld-blueprint</link><guid isPermaLink="true">https://sementicseo.hashnode.dev/entity-seo-for-ai-search-a-3-layer-json-ld-blueprint</guid><dc:creator><![CDATA[Farrukh Abdullah]]></dc:creator><pubDate>Wed, 28 Oct 2026 16:13:42 GMT</pubDate><content:encoded><![CDATA[<p>A connected entity graph in JSON-LD takes <strong>3 layers: a canonical Entity Home,</strong> <code>sameAs</code> <strong>identity links, and typed service and area attributes</strong>. The examples use the entity graph of my own site, farrukh.top, and the post ends with a script that checks that every <code>@id</code> reference resolves.</p>
<h2>What does an entity graph add over page-level markup?</h2>
<p>An entity graph adds identity that persists across pages: <strong>every page points to the same Organization and Person nodes instead of declaring its own copies</strong>. Google's Organization guidance describes markup that helps it disambiguate an organization in search results, and a shared graph gives that markup one consistent source. This post covers markup correctness and makes no claim about ranking or AI-answer citation outcomes.</p>
<p>Layer 1 gives each entity the address that every other node references.</p>
<h2>Layer 1: What is an Entity Home?</h2>
<p>An Entity Home is <strong>the single page on your domain that holds the canonical record of one entity</strong>, identified in JSON-LD by a persistent <code>@id</code>. The term comes from Jason Barnard of Kalicube. Assign each entity one <code>@id</code> as a URI fragment, such as <code>https://yourdomain.com/#organization</code> and <code>https://yourdomain.com/#person</code>, and reference that <code>@id</code> from every service page and article instead of redeclaring the entity.</p>
<p>Markup without an <code>@id</code> creates a blank node, so 2 pages that each declare an Organization produce 2 unconnected Organizations instead of 1 shared one. A service page that references the Entity Home's <code>@id</code> joins the existing node:</p>
<pre><code class="language-json">{
  "@context": "https://schema.org",
  "@type": "Service",
  "name": "Local SEO for HVAC Companies",
  "provider": { "@id": "https://farrukh.top/#organization" }
}
</code></pre>
<p>Once each entity has an <code>@id</code>, layer 2 connects that node to Wikidata, ORCID, GitHub, and Crunchbase.</p>
<h2>Layer 2: What belongs in a <code>sameAs</code> array?</h2>
<p>4 types of identity nodes belong in a <code>sameAs</code> array: <strong>structured knowledge bases, researcher registries, developer hubs, and B2B verification directories</strong>. <a href="http://schema.org">schema.org</a> defines <code>sameAs</code> as an identity assertion, so every URL in the array must be a page about the entity itself.</p>
<ul>
<li>Structured knowledge bases, such as Wikidata item Q141886354</li>
<li>Researcher registries, such as ORCID profile 0009-0001-9570-3897</li>
<li>Developer hubs, such as the GitHub profile yes155</li>
<li>B2B verification directories, such as GoodFirms and Crunchbase</li>
</ul>
<p>Each node belongs on the entity it describes: a Crunchbase person profile belongs on the Person, and a GoodFirms company profile belongs on the Organization. Open every target before adding it, and confirm that it describes the same entity.</p>
<p>2 further node types attach through other properties. Published research, such as the Zenodo whitepaper (DOI 10.5281/zenodo.23701870), belongs on a <code>CreativeWork</code> node whose <code>author</code> is your Person <code>@id</code>. Industry credentials belong under <code>hasCredential</code>. Those pages describe your work and qualifications rather than your identity, so <code>sameAs</code> is the wrong property for them.</p>
<p>The full graph looks like this:</p>
<pre><code class="language-json">{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://farrukh.top/#organization",
      "name": "Farrukh Abdullah Advisory",
      "url": "https://farrukh.top/",
      "sameAs": [
        "https://www.goodfirms.co/company/farrukh-abdullah-geo-semantic-seo-consultant"
      ]
    },
    {
      "@type": "Person",
      "@id": "https://farrukh.top/#person",
      "name": "Farrukh Abdullah",
      "jobTitle": "Semantic SEO &amp; GEO Consultant",
      "worksFor": { "@id": "https://farrukh.top/#organization" },
      "sameAs": [
        "https://orcid.org/0009-0001-9570-3897",
        "https://www.wikidata.org/wiki/Q141886354",
        "https://github.com/yes155",
        "https://www.crunchbase.com/person/farrukh-abdullah"
      ]
    },
    {
      "@type": "CreativeWork",
      "url": "https://zenodo.org/records/23701870",
      "identifier": "https://doi.org/10.5281/zenodo.23701870",
      "author": { "@id": "https://farrukh.top/#person" }
    }
  ]
}
</code></pre>
<h3>Which attributes must match across every node?</h3>
<p>3 attributes must match character for character on every node: <strong>the entity name, the job title, and the third-person description</strong>. Entity reconciliation compares strings first, so "SEO Consultant" on one profile and "SEO Specialist" on another introduces an ambiguity that a single canonical string prevents. Copy each value from the Entity Home into every external profile, and re-check them whenever one changes.</p>
<p>With identity established, layer 3 attaches typed location attributes.</p>
<h2>Layer 3: How do you map service and local entities?</h2>
<p>To map service and local entities, <strong>declare</strong> <code>areaServed</code> <strong>with a typed City or GeoCircle on each service or business node</strong>. The following example declares 1 named city and a 50 km radius for a hypothetical HVAC business:</p>
<pre><code class="language-json">{
  "@context": "https://schema.org",
  "@type": "HVACBusiness",
  "@id": "https://example-hvac.com/#organization",
  "name": "Example HVAC Co.",
  "areaServed": [
    { "@type": "City", "name": "Austin" },
    {
      "@type": "GeoCircle",
      "geoMidpoint": { "@type": "GeoCoordinates", "latitude": 30.2672, "longitude": -97.7431 },
      "geoRadius": 50000
    }
  ]
}
</code></pre>
<p><code>areaServed</code> accepts City, GeoShape, and plain text; a typed City or GeoCircle states the service area exactly, while plain text leaves it open to interpretation. <code>geoRadius</code> takes meters, so <code>50000</code> is 50 km.</p>
<p>Layer 3 completes the graph, and the next step is checking that it holds together.</p>
<h2>How do you validate the graph?</h2>
<p>To validate the graph, <strong>run the combined JSON-LD through the Schema Markup Validator, then check that every</strong> <code>@id</code> <strong>reference resolves to a declared node</strong>. The validator covers syntax and <a href="http://schema.org">schema.org</a> types, and the script below covers the reference check on its own.</p>
<pre><code class="language-python">import json
import sys


def walk(node, declared, refs):
    if isinstance(node, dict):
        if "@id" in node:
            # A node holding only an @id is a reference; any other node declares it.
            (refs if len(node) == 1 else declared).add(node["@id"])
        for value in node.values():
            walk(value, declared, refs)
    elif isinstance(node, list):
        for item in node:
            walk(item, declared, refs)


declared, refs = set(), set()
for path in sys.argv[1:]:
    with open(path, encoding="utf-8") as f:
        walk(json.load(f), declared, refs)

print("Declared:", sorted(declared))
print("Unresolved @id references:", sorted(refs - declared) or "none")
</code></pre>
<p>Run it as <code>python check_ids.py graph.json service.json</code>. A service page that references <code>#organization</code> resolves only when the file declaring that Organization is in the same run: the graph file plus the service file prints <code>none</code>, and the service file alone lists <code>https://farrukh.top/#organization</code> as unresolved.</p>
<h2>What are the limits of this approach?</h2>
<p>This approach delivers <strong>consistent, machine-readable identity, not ranking or citation outcomes</strong>. No markup change in this post is tied to a measured traffic or citation result, so test every claim about AI-answer visibility on your own site before relying on it.</p>
<h2>Where can you read more?</h2>
<p>The 4 primary references are the <a href="http://schema.org">schema.org</a> pages for <a href="https://schema.org/sameAs">sameAs</a>, <a href="https://schema.org/hasCredential">hasCredential</a>, and <a href="https://schema.org/GeoCircle">GeoCircle</a>, and Google's <a href="https://developers.google.com/search/docs/appearance/structured-data/organization">Organization structured data guidance</a>. The <a href="https://validator.schema.org/">Schema Markup Validator</a> checks syntax and types, and the <a href="https://www.w3.org/TR/json-ld11/">JSON-LD 1.1 specification</a> defines <code>@id</code> and blank nodes.</p>
<p>My related work: <a href="https://farrukh.top/insights/local-entity-seo-ai-search">Local Entity SEO: Accurate Business Information and Useful Service Content</a> extends layer 3 to location-based businesses, and <a href="https://github.com/yes155/awesome-geo-seo">awesome-geo-seo</a> is the open-source curated list for generative engine optimization.</p>
<p>I'm Farrukh Abdullah, a Semantic SEO &amp; GEO Consultant, and the identifiers in the examples are my own.</p>
]]></content:encoded></item></channel></rss>