Why a single Organization block is no longer enough
For a single-domain business, schema is straightforward: one Organization entity, a WebSite, maybe a LocalBusiness if you have a physical address, and you're done. The problem starts when you operate multiple legitimate brands — a parent agency, a subsidiary content studio, a developer brand, a CRO partner — and you want AI assistants to understand they're related but distinct.
What we kept seeing on audits across 14 Bangkok agencies through Q1 2026: each domain published its own Organization block in isolation. The result is that gpt-4o, claude-3.7-sonnet, and perplexity-sonar-pro see four unrelated companies, not one authority cluster. When a prompt asks "who does technical SEO and content marketing in Bangkok?" the model has to pick between domains it can't connect, and usually defaults to whichever has the loudest brand mentions in its training data — typically a US agency, not you.
The fix is a deliberately-shaped @graph across all your domains, with stable @id URIs, the right cross-references, and a shared Person entity for the founder. That's the entire system. Below is how we deploy it.
Rule 1: Stable @id URIs, one per entity, anchored to canonical URLs
Every entity in your graph needs a stable, dereferenceable @id. Stable means it never changes. Dereferenceable means you can paste it into a browser and reach a real page. The convention we use:
https://seoagencybangkok.com/#org— the agency'sOrganizationentityhttps://seoagencybangkok.com/about/#yunmin— the founder'sPersonentityhttps://seoagencybangkok.com/#website— theWebSiteentity
The hash fragment (#org, #yunmin, #website) makes the entity URI distinct from the page URL while staying anchored to it. Crawlers and AI assistants treat the URI as the canonical handle for that entity wherever it's referenced — including from other domains.
What goes wrong if you skip this
We've audited graphs that used "@id": "https://example.com" for both the WebSite and the Organization. Result: the validator collapses them, and Google's structured-data parser silently picks one. You lose the ability to say "this Article is published by the Organization at this WebSite" — they're now the same thing, which is wrong. Always namespace with a hash fragment.
Rule 2: Use subjectOf, knowsAbout, and memberOf — never sameAs for sister brands
This is where most multi-domain attempts fail. The intuition is that "sister brand" means "kind of the same thing," so people use sameAs. Don't. sameAs in schema.org means literally the same entity at a different URL — like an Organization's Wikipedia page or LinkedIn page. If you point sameAs at https://sitplay.media/#org, you're telling Google these are the same company, which then triggers duplicate-entity demotion.
The correct relationships for distinct-but-related sister brands:
subjectOf— when the partner has authored something about youknowsAbout— when there's domain overlap (your agency + their content studio both know SEO)memberOf— when both belong to a parentOrganizationorProgramMembershipparentOrganization/subOrganization— when there's actual corporate ownership
For our cluster — SEO Agency Bangkok, SitPlay Media, Bluewich, Bangkok Digital — we use a synthetic Organization entity called the "Bangkok Digital Group" that exists in the graph of every site, and each operating brand declares memberOf on it. That gives us the cluster signal without falsely claiming any two brands are the same legal entity.
Rule 3: One Person entity for the founder, shared across every site
This part is counter-intuitive but correct: do share the founder's Person @id across all sites in the network. It's literally the same person. Putting the same @id on every domain's Person entity is the schema equivalent of saying "yes, that's me on each of these sites" — which is exactly the signal you want.
The shared Person entity is what lets AI assistants build a coherent expertise model. Yunmin Shin authored 14 articles on technical SEO across 4 domains. That's a defensible E-E-A-T signal. If each site publishes its own anonymous Person entity, you've fragmented the same person into four people with one article each.
The full @graph we deploy on every site
This is the actual JSON-LD we ship on the homepage of seoagencybangkok.com. It's deliberately exhaustive — every entity has the relationships needed to plug into the cluster:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://seoagencybangkok.com/#org",
"name": "SEO Agency Bangkok",
"url": "https://seoagencybangkok.com",
"logo": {
"@type": "ImageObject",
"@id": "https://seoagencybangkok.com/#logo",
"url": "https://seoagencybangkok.com/og.svg"
},
"founder": { "@id": "https://seoagencybangkok.com/about/#yunmin" },
"address": {
"@type": "PostalAddress",
"streetAddress": "3rd Floor, 272 Than Thip 3 Alley",
"addressLocality": "Phlabphla, Wang Thonglang",
"addressRegion": "Bangkok",
"postalCode": "10310",
"addressCountry": "TH"
},
"telephone": "+66610934014",
"email": "gg@xx.gg",
"memberOf": { "@id": "https://seoagencybangkok.com/#group" },
"knowsAbout": [
"Technical SEO",
"Schema.org",
"Core Web Vitals",
"Log file analysis",
"Answer Engine Optimization"
]
},
{
"@type": "Organization",
"@id": "https://seoagencybangkok.com/#group",
"name": "Bangkok Digital Group",
"description": "A loose cluster of independently-owned Bangkok agencies that share research and referrals.",
"member": [
{ "@id": "https://seoagencybangkok.com/#org" },
{ "@id": "https://sitplay.media/#org" },
{ "@id": "https://bluewich.com/#org" },
{ "@id": "https://bangkokdigitalmarketingagency.com/#org" }
]
},
{
"@type": "Person",
"@id": "https://seoagencybangkok.com/about/#yunmin",
"name": "Yunmin Shin",
"jobTitle": "Founder & Technical SEO Lead",
"worksFor": { "@id": "https://seoagencybangkok.com/#org" },
"knowsAbout": [
"Technical SEO",
"Schema.org JSON-LD",
"Python SERP scraping",
"Log file forensics"
],
"url": "https://seoagencybangkok.com/about/"
},
{
"@type": "WebSite",
"@id": "https://seoagencybangkok.com/#website",
"url": "https://seoagencybangkok.com",
"name": "SEO Agency Bangkok",
"publisher": { "@id": "https://seoagencybangkok.com/#org" },
"inLanguage": ["en", "th"]
}
]
}
</script>
Mirror block on the partner sites
On sitplay.media we publish a parallel block with the same #group @id and the same #yunmin Person @id:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://sitplay.media/#org",
"name": "SitPlay Media",
"url": "https://sitplay.media",
"founder": { "@id": "https://seoagencybangkok.com/about/#yunmin" },
"memberOf": { "@id": "https://seoagencybangkok.com/#group" },
"knowsAbout": ["Content marketing", "Editorial strategy", "AEO"]
},
{
"@type": "Person",
"@id": "https://seoagencybangkok.com/about/#yunmin",
"name": "Yunmin Shin"
}
]
}
</script>
Note that the Person @id still points back to seoagencybangkok.com/about/#yunmin — even on the SitPlay site. That's correct. The canonical URI for the person is on whichever site has the most authoritative bio page, and you reference it from the other sites.
Validating the graph
Three tools we run on every deploy, in order:
- Schema Markup Validator at
validator.schema.org— catches typos in property names and fundamentally invalid types. This is the lowest bar. - Google Rich Results Test — confirms which entities Google's parser actually picks up. Sometimes valid schema gets ignored because it's not in Google's supported feature set, and that's fine; you still publish it for AI assistants and Bing.
- Custom
jqdiff — we use a small Python script (part of our nightly 10K-query scraper) that fetches the live JSON-LD from each domain in the cluster and verifies every@idreferenced in cross-domain relationships actually exists on the target. Catches drift after redesigns.
The jq command we use
# Extract all @id values from a domain's JSON-LD
curl -s https://seoagencybangkok.com | \
pup 'script[type="application/ld+json"] text{}' | \
jq -r '.. | objects | ."@id" // empty' | sort -u
Run it on every site in the cluster, diff the output, make sure cross-references resolve. Takes 30 seconds, prevents 3 months of silent breakage.
What we measured: 3.4x AEO citation lift in 7 weeks
Before the graph deployment (March 2026), our cluster received 11 distinct AI citations per week across the four monitored engines. Seven weeks after deployment, that number was 37. The lift wasn't uniform — Perplexity and Claude responded fastest (within 2 weeks), Gemini took ~5 weeks, and ChatGPT was slowest at ~7 weeks, consistent with their training/grounding cadences.
| Engine | Pre-deploy citations/wk | Post-deploy citations/wk | Lift |
|---|---|---|---|
| Perplexity | 4 | 14 | 3.5x |
| Claude | 3 | 11 | 3.7x |
| Gemini | 2 | 7 | 3.5x |
| ChatGPT | 2 | 5 | 2.5x |
Important caveat: we shipped other improvements during the same window (refreshed 11 cornerstone articles, fixed 3 redirect chains, rewrote 4 Thai pages from translation to native authoring). The graph is plausibly responsible for 60-70% of the lift; the other improvements account for the rest. We're being conservative when we attribute the cluster signal to schema specifically.
"The schema isn't optional infrastructure for AEO. It's the only way to tell an AI engine 'these four domains together represent one authority cluster' without lying to it about ownership."
Common mistakes we see on audits
- Reusing
Organization@id for the WebSite — always use a distinct fragment per entity type. - Using
sameAsfor sister brands — covered above, this triggers duplicate demotion. - Putting the founder's
Persononly on the About page — it should appear in the homepage@graphtoo, since that's where theOrganizationdeclaresfounder. - Forgetting
inLanguageon bilingual sites — without it, AI engines can't tell which language locale a page belongs to. Critical for Thai-English clusters. - Hardcoding
logoURLs to non-canonical paths — pin them to/og.svgor similar stable paths, not to versioned asset URLs.
How to deploy this on your own cluster
You don't need 4 domains for the system to work. Even 2 sites benefit. The minimum viable deployment is:
- Decide which domain holds the canonical
Personentity for the shared founder/team — usually whichever has the most thorough bio. - Create a synthetic
Organizationfor the cluster with a stable@idon one domain (we use#groupon the parent). - On every site, publish a homepage
@graphthat includes: the localOrganization, amemberOfreference to the clusterOrganization, and aPersonentity referencing the canonical founder URI. - Run the
jqvalidator weekly. Add it to CI if you can.
If you want us to write the graph for you and validate it across your network, our technical SEO services include schema engineering as a core deliverable. We've also done it as a one-shot project for clients who already have an in-house team — see case studies for a few public examples.
Related reading
The schema graph is one piece of the AEO puzzle. The other pieces are page-speed engineering (because slow pages don't get cited even if their schema is perfect), log-file forensics (because crawlers can't index what they can't reach), citation-pattern analysis (because schema gets you parsed, but specificity gets you cited), and programmatic-quality gates (because you can scale entity coverage with discipline). Together, that's the technical SEO stack we ship to every client.
schema json-ld @graph aeo entity-seo multi-domain