Knowledge Graph Entity Linking: sameAs and @id for AI Citation
Entity linking with sameAs and @id: how AI assistants reconcile a local business across GBP, Wikidata, and directory sources.
Here is a problem that looks trivial and is not. Your business appears on the open web as at least three strings: “Blue Bottle Coffee Aoyama” on your own site, “Blue Bottle Coffee — Aoyama Cafe” in a directory, and “ブルーボトルコーヒー 青山店” on a Japanese review aggregator. A human reads all three and knows they are one place. An AI assistant, asked “where should I get coffee near Aoyama?”, has to decide the same thing before it can decide whether to cite you, and it has no human intuition to fall back on. It has either evidence that the three strings denote the same entity, or it has a guess.
Most local-business optimization tries to win this by making the three strings identical. That is the NAP-consistency layer: name, address, and phone matched character-for-character so the model’s string comparison has an easy time. It works, up to a point. The point where it stops working is exactly where this piece begins, because string matching is inference (the model concludes the entities are probably the same), and there is a layer above it where you stop letting the model infer and start telling it outright. That layer is entity linking, and its two instruments are @id and sameAs.
Inference versus declaration
The distinction is worth making sharp, because it is the whole argument.
When two schema fragments both say "name": "Blue Bottle Coffee Aoyama" and "telephone": "+81-3-...", a model resolving entities does string and attribute comparison and assigns a probability that they co-refer. Clean NAP raises that probability. But the model is still reasoning “these look like the same business.” Change the name string on one surface — a new branch suffix, a romaji-versus-kana switch, a rebrand — and the probability drops, because the evidence you gave it was the strings agreeing.
@id and sameAs change the kind of evidence. Instead of “these strings look alike,” you publish “this fragment and that fragment carry the same identifier.” The model is no longer estimating co-reference from surface features; it is reading a declaration. Names can drift and the identity holds, because identity was never riding on the name in the first place.
This matters more every quarter, because the frameworks that describe AI citation are converging on it. LLMO, currently the most precise of them, treats entity identity not as something the model should probabilistically reconstruct from your NAP fields but as something you declare with resolvable URIs: the Knowledge Clarity component is, in effect, the requirement that your entity be unambiguously addressable rather than merely consistently spelled. That is a different optimization target from “make the strings match,” and it is the one that survives a rebrand.
What knowledge graph entity linking actually is
“Knowledge graph entity linking” is the technical name for the operation an AI assistant performs before it decides whether to cite you. It reads whatever surface it landed on — your JSON-LD, a directory scrape, a review site, a social profile — and tries to reconcile each mention to a single node in a graph of entities it already knows. If it succeeds, the mentions collapse into one node and every fact attached to any of them is available to answer a query about you. If it fails, the mentions stay as separate nodes and the facts are split across them; the model may have all the evidence it needs to answer a question and still not know which node the evidence belongs to.
In the local-business setting, the graph the model reconciles against is a mix of two things: an internal graph built from your own JSON-LD (nodes joined by shared @id), and an external graph the model brought with it from pre-training and retrieval (Wikidata, Google’s Knowledge Graph projection, verified profiles). Entity linking is the operation that bridges the two — the internal node you declare on your surfaces has to line up with the external node the model already holds. @id builds the internal graph; sameAs bridges it to the external one.
This is not a separate optimization on top of citation; it is a precondition for AI citation itself. A model that cannot identify you cannot cite you, regardless of how good your content is. And it sits on the Structure axis of the three axes of AI-native MEO — the axis concerned with how your business is addressable to a machine reader, distinct from the Provenance axis (where your facts come from) and the Confidence axis (how sure the model has to be to use them). This is also why structured data outweighs prose for AI trust at exactly this layer: a paragraph stating that your business is on Wikidata is not the same as a resolvable URI the model can dereference; identity claims in prose are inference, identity claims in JSON-LD are declaration.
@id: giving your business a primary key
@id is the stable URI you assign to your business entity. It is the primary key. Once you have one, every schema fragment that is about that business, across every page, in every @type, can point at it, and the model can collapse them into a single node.
{
"@context": "https://schema.org",
"@type": "Cafe",
"@id": "https://bluebottle.example/#aoyama",
"name": "Blue Bottle Coffee Aoyama",
"address": {
"@type": "PostalAddress",
"streetAddress": "3-13-14 Minamiaoyama",
"addressLocality": "Minato",
"addressRegion": "Tokyo",
"postalCode": "107-0062",
"addressCountry": "JP"
},
"telephone": "+81-3-xxxx-xxxx"
}
The @id here is a URI you control: a fragment identifier (#aoyama) anchored to a canonical page on your own domain. It does not have to resolve to a live document — though it is better if it does — but it does have to be stable. The cardinal sin is letting the @id change when the page URL changes, because the moment it changes you have told the model that the old entity ceased to exist and a new one appeared.
The payoff comes when you reuse it. Your menu page emits an Offer whose offeredBy points at {"@id": "https://bluebottle.example/#aoyama"}. Your reviews page emits an aggregateRating attached to the same @id. Your contact page emits the full LocalBusiness. Three pages, three @type contexts, one identity — and a model crawling your site reconciles them without guessing.
{
"@context": "https://schema.org",
"@type": "Menu",
"@id": "https://bluebottle.example/menu#menu",
"name": "Blue Bottle Aoyama Menu",
"hasMenuSection": {
"@type": "MenuSection",
"name": "Coffee",
"offers": {
"@type": "Offer",
"offeredBy": { "@id": "https://bluebottle.example/#aoyama" }
}
}
}
That offeredBy reference is the wire. It is the difference between a menu floating in space and a menu the model knows belongs to this cafe.
sameAs: connecting to the authority graph
@id resolves identity within your own surfaces. sameAs resolves it against the rest of the world: it declares that your entity is the same as a node in an authoritative graph the model already trusts.
{
"@context": "https://schema.org",
"@type": "Cafe",
"@id": "https://bluebottle.example/#aoyama",
"name": "Blue Bottle Coffee Aoyama",
"sameAs": [
"https://www.wikidata.org/wiki/Q4928902",
"https://www.instagram.com/bluebottlejapan/",
"https://www.google.com/maps/place/?q=place_id:ChIJ...",
"https://bluebottlecoffee.jp/"
]
}
Each URI in that array is a different kind of corroboration. The Wikidata QID anchors you to the structured public knowledge graph that sits underneath a great deal of model pre-training. The Google Place ID URL links you to the entity Google’s own surfaces project. The official site and verified social profiles are the open-web nodes a retrieval pass is most likely to reach. Together they say: the entity at this @id is the same entity you already know under all these other names.
How heavily any given engine weights a given sameAs target is documented architecture-based inference, not measured citation behavior: I can read the published descriptions of how these systems do entity resolution and reason about which anchors are load-bearing, but I cannot watch a model assign weights. With that caveat stated plainly, here is the map I work from:
sameAs target | What it anchors to | Why it carries weight |
|---|---|---|
| Wikidata QID | The public structured knowledge graph | Frequently present in pre-training; a canonical disambiguator across languages |
| Google Place ID URL | Google’s Knowledge Graph projection | Aligns your entity with the surface Google-integrated engines read first |
Official website (@id host) | Your first-party canonical | Closes the loop: the authority graph points back at the identity you declared |
| Verified social profiles | Open-web corroboration | Reachable on a live retrieval pass; reinforces freshness |
| Local citation directories | Third-party entity records | Corroboration density, but lower trust than Wikidata or a verified profile |
The ordering is the actionable part. A single Wikidata link does more disambiguating work than ten directory links, because it resolves you against a graph the model already holds rather than against more strings it has to trust on faith. If your business is notable enough to have, or to earn, a Wikidata item, that one URI is the highest-leverage entry in the array.
Where the layers stack
It helps to see the whole stack at once, because each layer does a job the one below it cannot.
| Layer | Instrument | What it tells the model | Failure mode it removes |
|---|---|---|---|
| String consistency (NAP) | matching name / address / telephone | ”these probably co-refer” | random spelling drift between surfaces |
| Internal identity | @id reused across pages | ”all of these fragments are one entity” | menu / reviews / hours read as separate businesses |
| External identity | sameAs to authority URIs | ”that one entity is this known node” | the model failing to connect you to what it already knows |
NAP consistency is the floor, not the ceiling. It is necessary — contradictory phone numbers will sink you regardless of how good your sameAs array is — but it is doing the weakest kind of work, and it is the layer most exposed to the ordinary entropy of a business that changes over time. @id and sameAs are the layers that hold when the strings move. (There is an honest irony here: the cleaner your NAP, the less your sameAs array has to rescue, and the messier your reality of branches and rebrands and bilingual names, the more it does. The businesses that need entity linking most are exactly the ones too tangled to keep their strings tidy.)
If you want the layer directly below this one in detail, the companion piece on reading GBP as JSON-LD covers how Google’s own projection of your business already carries an @id, and why your job is to agree with it rather than contradict it.
A note on what this is and is not
This is structural optimization, and structural optimization is not the same as the content-and-phrasing tactics that GEO and AEO concentrate on. Those frameworks largely optimize the text that lands in an answer: how a passage is worded so a model will lift it. Entity linking optimizes something earlier and lower: whether the model can resolve who you are before it gets to what to say about you. The two are complementary, but they are not interchangeable, and conflating them is how businesses end up with beautifully worded pages the model cannot attribute to anyone. If the terminology around all this is still fuzzy, the LLMO-versus-SEO-AEO-GEO guide draws the boundaries more carefully than I can in a paragraph.
A decision flow for the sameAs array
There is no universally correct sameAs array — the right entries are the ones that actually resolve you to something the model can dereference. Work through it in this order, top-down, and stop at each question that returns no rather than fabricating an entry:
- Does your business have (or plausibly qualify for) a Wikidata item? If yes, put the QID URI first:
https://www.wikidata.org/wiki/Q.... If it does not exist but the business is notable (independently sourced coverage, a distinctive brand, multiple locations), it may be worth creating one; the QID is the single highest-leverage entry you can add. If not, skip this row rather than inventing a placeholder. - Do you have a verified Google Business Profile? If yes, add the Place ID URL:
https://www.google.com/maps/place/?q=place_id:.... If no, this is the item to fix before worrying about the rest of the array — until the GBP exists, Google-integrated engines have nowhere to project you from. - Is your
@idhost the same domain as your official website? If yes, that is already the loop-closing anchor; you do not need a separate site URI insameAs, but adding it is harmless and makes crawler behavior more predictable. If your@idlives on a different host (a corporate umbrella, a franchisor domain) than the customer-facing site, include the customer-facing site here so retrieval reaches both. - Do you have verified social profiles the business itself controls? Add the primary one (usually Instagram for cafes and restaurants, LinkedIn for B2B, X for news-adjacent operations). Verified beats large, and controlled beats fan pages.
- Do you have entries in high-authority local directories? These are the last row, not the first. A Yelp or Foursquare URI can add corroboration density, but each one is more strings the model has to trust on faith; a handful of good directory URIs is fine, a wall of them is noise.
Two more choices sit alongside the array itself and are easy to get wrong. First, the @type of the node the @id and sameAs attach to should be the most specific class that fits — the tradeoffs between LocalBusiness, Place, and Restaurant for AI matter here, because the type is part of what routes your entity in the graph. Second, resist the temptation to point sameAs at pages you also link to elsewhere for SEO purposes but that do not actually identify the same entity (a generic corporate site, a category page, a franchisor homepage): a sameAs array is not a link farm, and each incorrect entry weakens the correct ones.
The one thing to do today
Pick your most important location and give it a real @id (a stable URI on your own domain), then add a sameAs array with, at minimum, your verified Google Place ID URL, your official site, and your primary verified social profile. If you can find or create a Wikidata item, put its QID first.
Then verify the entity actually resolves:
curl -sL https://your-domain.example/ \
| grep -oE '<script type="application/ld\+json">[^<]+</script>' \
| sed -E 's|</?script[^>]*>||g' \
| python3 -c 'import sys,json; d=json.load(sys.stdin); print("@id:", d.get("@id")); print("sameAs:", d.get("sameAs"))'
If @id comes back None, your business has no primary key and every fragment about it is floating independently. If sameAs comes back None, you are asking the model to connect you to the authority graph by inference alone. Both are fixable in an afternoon, and both are cheaper than they look, because you are not adding new facts about your business — you are only telling the model that the facts it already has all belong to one entity.
The closing caveat is the same one that applies to everything in this layer: the way engines weight authority URIs today is a snapshot, and the snapshot moves. But the underlying instruction — here is my identifier, and here is what it is the same as — is about as durable a thing as you can say in structured data. Strings drift. A well-chosen URI does not.
Further reading
Related canonicals in this cluster:
- NAP consistency as entity reconciliation: the string-matching floor this piece builds on — the inference layer that
@idandsameAssit above. - Reading Google Business Profile as JSON-LD: Google’s own projection of your business already assigns an
@idyou should agree with rather than contradict. - Preconditions for AI citation: why entity linking is a citation precondition — a model that cannot identify you cannot cite you at all.
- Three axes of AI-native MEO: where entity linking sits on the Structure axis, distinct from Provenance and Confidence.
- Structured data vs prose for AI trust: why identity claims in JSON-LD are declaration, while identity claims in prose stay inference.
- LocalBusiness vs Place vs Restaurant for AI: choosing the
@typethat@idandsameAsattach to, and the tradeoffs across specificity. - Three provenance paths for AI assistants: where entity linking sits inside the broader map of how an assistant sources what it cites.
- Knowledge Clarity — LLMO Framework: why an unambiguously addressable entity is treated as a first-class citation input.
- NAP consistency as entity reconciliation (日本語版): the Japanese-language companion to the string-matching floor.
Frequently asked questions
- What is the difference between sameAs and @id in JSON-LD?
- `@id` resolves identity within your own surfaces — it is the stable URI you assign to your business entity, functioning as a primary key that every schema fragment about that business across every page can point at. `sameAs` resolves identity against the rest of the world: it declares that your entity is the same as a node in an authoritative graph (Wikidata, Google's Knowledge Graph, verified profiles) that the model already trusts. `@id` collapses your internal fragments into one node; `sameAs` connects that node to nodes the model already knows.
- How do I connect my local business to the Google Knowledge Graph?
- Add a `sameAs` array to your business schema that includes your Google Place ID URL, which links you to the entity Google's own surfaces project. In the same array, put your Wikidata QID (if one exists), your official website, and verified social profiles. Each URI is a different kind of corroboration, and the Google Place ID specifically aligns your entity with the surface Google-integrated engines read first.
- Which sameAs URI carries the most weight for AI citation?
- Based on architecture-based inference — not measured citation behavior — a single Wikidata QID does more disambiguating work than ten directory links, because it resolves you against a public structured knowledge graph the model already holds from pre-training rather than against more strings it has to trust on faith. If your business is notable enough to have or to earn a Wikidata item, that one URI is the highest-leverage entry in the array; a Google Place ID URL is the next most impactful anchor.
- How do I check whether my business already declares @id and sameAs?
- Fetch your homepage and inspect the JSON-LD directly: `curl -sL https://your-domain.example/ | grep -oE '<script type="application/ld+json">[^<]+</script>' | sed -E 's|</?script[^>]*>||g' | python3 -c 'import sys,json; d=json.load(sys.stdin); print("@id:", d.get("@id")); print("sameAs:", d.get("sameAs"))'`. If `@id` comes back `None`, your business has no primary key and every fragment about it is floating independently. If `sameAs` comes back `None`, you are asking the model to connect you to the authority graph by inference alone.
- What is sameAs in Schema.org for local businesses?
- `sameAs` is a Schema.org property that declares your business is the same entity as a node in an external authoritative graph. Each URI in the `sameAs` array points to a place the model may already know your business: a Wikidata QID, a Google Place ID URL, your official website, or a verified social profile. Together they tell the model *the entity at this `@id` is the same entity you already know under all these other names*, replacing string-matching inference with an explicit declaration.
- How does AI use @id for entity linking?
- An AI assistant reading your site uses `@id` to reconcile schema fragments emitted from different pages into a single entity. If your menu page emits an `Offer` whose `offeredBy` points at your `@id`, your reviews page attaches an `aggregateRating` to the same `@id`, and your contact page emits the full `LocalBusiness` under it, the model collapses three fragments across three `@type` contexts into one node — without having to guess from string similarity that they refer to the same business.
- Which sameAs URLs should a local business include for AI citation?
- At minimum, include your verified Google Place ID URL, your official website, and your primary verified social profile. If your business is notable enough to have or to earn a Wikidata item, put its QID first in the array — a single Wikidata link does more disambiguating work than ten directory links, because it resolves you against a structured public knowledge graph the model already holds from pre-training. The Google Place ID is the next most impactful anchor, aligning your entity with the surface Google-integrated engines read first. Local citation directories can be added as corroboration density, but they carry lower trust than Wikidata or a verified profile.
- How is sameAs different from NAP consistency?
- NAP consistency and `sameAs` operate at different layers. Matching `name`, `address`, and `telephone` character-for-character across surfaces is *inference*: the model concludes from string similarity that the fragments probably co-refer. Change a name string — a new branch suffix, a romaji-versus-kana switch, a rebrand — and that probability drops, because the evidence you gave the model was the strings agreeing. `sameAs` is *declaration*: it publishes resolvable URIs that name the same entity in an authoritative graph, so identity holds even when the strings drift. NAP is the floor; `sameAs` is the layer that survives a rebrand.