XEO — the ontology for the xEO family

xeo: · https://xeoontology.org/xeo# · v0.5.0 · open draft · CC BY 4.0

inboundfound/xeo-ontology

A small, standards-grounded vocabulary for how engines — search engines, generative overviews, answer engines, conversational agents — see, cite, and serve web content. One graph model for the whole xEO family: SEO, GEO, AEO, and whatever letter comes next.

A small, standards-grounded vocabulary for how engines — search engines, generative overviews, answer engines, conversational agents — see, cite, and serve web content. One graph model for the whole xEO family: SEO, GEO, AEO, and whatever letter comes next.

The x is the variable. That is the whole point of the name: the letter in front keeps changing, and the discipline behind it doesn't.

Prefix: xeo: · Namespace: https://xeoontology.org/xeo# · Status: v0.5 — open draft, built to be riffed on. Issues and PRs welcome.

Why "XEO"

Marketers already think in -EO: SEO, then GEO, then AEO. The engines keep changing; the discipline — make your content legible and creditable to the machine between you and your audience — doesn't. XEO names that discipline once, and the ontology's Engine taxonomy absorbs new surfaces as subclasses instead of new acronyms.

What makes this one different

  1. Observations are grounded in primary standards. Every observational term cites the spec or API contract that defines it — HTTP (RFC 9110), WHATWG HTML/URL, RFC 6596, the GSC Search Analytics API, per-provider response annotations. No dependency on any third-party SEO vocabulary.
  2. Epistemic layering. Every term is typed by the kind of claim it makes: entity (durable identity) · episode (happened at a time, immutable) · observation (measured fact) · derivation (model output — carries method, model, confidence) · interpretation (a strategist's claim, labeled as one) · norm (a standing rule about a class of cases, not a call about one). An agent assembling context can filter to observations only.
  3. Storage-agnostic. The ontology defines meaning and identity keys; every term declares a canonical store. The graph holds what you traverse; the column store holds high-cardinality time-series facts; the vector store holds geometry; the CRM holds the pipeline. Identity keys join across stores.
  4. Tenancy is data, not schema. Scope lives in properties (websiteId), never in dynamic labels.
  5. Integrate with data sources, not vocabularies. Mapping modules for your CRM/analytics stack are operational pointers (identity keys), never baked-in vendor vocabularies.

Modules

FileLayerContents
xeo-core.ttlthe SEO substrateWebsite, URL, Term, Crawl, SerpSnapshot, Topic, SearchPerformanceFact; FETCHED, LINKS_TO, REDIRECTS_TO, HAS_CANONICAL, RANKS_FOR (windowed rollups with datasetUri provenance), HAS_RESULT, IN_TOPIC
xeo-visibility.ttlthe xEO layerEngine (+ SearchEngine / GenerativeEngine / AnswerEngine / ConversationalAgent), Brand, Prompt, LLMResponse; CITES, MENTIONS {mentionRank}, FANS_OUT_TO (fan-out queries are Terms — the join back to rank data), VISIBILITY_FOR rollups (mentionRate, citationRate)
xeo-engagement.ttldraft v0SearchIntent individuals (Broder 2002, extended), ConversionPoint (+ CallToAction / LeadCaptureForm / GatedAsset), ConversionEvent, crmRecordRef (the CRM join key), attributedResponse (pre-click attribution — a labeled interpretation)
xeo-decision.ttlthe interpretation tierDiagnostic, Gap, Tactic, Capability, Experiment, Outcome, Recommendation; the chain reveals→addressableBy→requiresCapability (scope gate)→tests/inContext→recommends/supportedBy. Classes, never values — gapType/inIntervention/onDimension/atPriority are skos:Concept slots you fill.
xeo-strategy.ttlthe norms tierPractice (a standing rule: guardrail vetoes a candidate, preference reorders it, guidance caveats it), Playbook (a reusable discipline bundle); constrains, appliesToConcept, appliedPractice (the audit edge — why a candidate was blocked), supersedes (revisable, never deleted), hasRole (page roles as a derivation, not regexes), appliesAtScope (the tenancy specificity ladder). Governs how a Recommendation is allowed to be made.
xeo-delivery.ttlthe delivery layerProject (the contract — engagementType, interventionQuota, cadence/durationDays, what's inScope), Campaign (a body of work aboutTopic, covering URLs and Terms), Objective → MetricTarget (the intent, as targets a later Outcome is read against). Recommendation issuedFor a campaign; Experiment measures a target. The layer the decision and norms tiers left open.
xeo-schemes.ttl · schemes.jsonreference valuesThe slots, filled. SKOS concept schemes for every skos:Concept slot and controlled string in the ontology — 20 schemes, ~100 concepts: gap types, verdicts, priority, the intervention catalogue, lifecycles, metrics, epistemic layers. Every value lifted from a production implementation and sourced. schemes.json is the generated projection for anything that builds an enum at boot.
xeo-align.ttlinteroperabilityOptional bridges — schema.org (WebSite, WebPage, Brand, Observation), PROV-O (Crawl→Activity, Engine→SoftwareAgent, LLMResponse→Entity), SKOS (Topic→Concept, childOf→broader). Alignments, not dependencies.
context.jsonldinteroperabilityA JSON-LD @context mapping graph labels/relationships/properties to IRIs — turns a Neo4j export into valid RDF/JSON-LD in one pass.
schema.cypherproperty graphNeo4j 5.x constraints + indexes for every module

The core module is the stable substrate. Visibility is field-tested against a working tracker/response-capture/Neo4j implementation. Decision and strategy are implemented in production (see xeo-graph-kit for a runnable slice). Engagement is an early draft published for discussion — the "pre-click funnel" seam that engine-side data has been missing.

The mental model

              entities (durable)              episodes (immutable)

  core        Website · URL · Term · Topic    Crawl · SerpSnapshot
  visibility  Engine · Brand · Prompt         LLMResponse
  engagement  ConversionPoint · SearchIntent  ConversionEvent
  decision    Gap · Tactic · Capability       Experiment (→ Outcome)
  strategy    Practice · Playbook             (norms — rules, not events)
  delivery    Project · Campaign              (Objective → MetricTarget:
                                              the intent)

The strata get more interpretive upward: core is bedrock (falsifiable, standards-grounded); decision is the surface (diagnosed, recommended); strategy governs it (what SHOULD hold, not what is). Load only the strata you need — filter to observation and the interpretation and norm tiers drop away.

Two rollup patterns rhyme on purpose:

The first summarizes the SEO world (facts in your column store); the second summarizes the xEO world (facts in your response archive). Same discipline, new engine.

Example queries the model is shaped for

// Cited but not named: pages that ground answers naming someone else
MATCH (r:LLMResponse)-[:CITES]->(u:URL {websiteId: $tenant})
WHERE NOT EXISTS { MATCH (r)-[:MENTIONS]->(:Brand {websiteId: $tenant}) }
RETURN u.address, count(r) AS ghost_citations ORDER BY ghost_citations DESC;

// List filler: mentioned often, ranked late
MATCH (r:LLMResponse)-[m:MENTIONS]->(b:Brand)
RETURN b.name, count(r) AS mentions, avg(m.mentionRank) AS avg_rank
ORDER BY mentions DESC;

// The fan-out join: engine retrieval queries you already rank for
MATCH (p:Prompt)-[:FANS_OUT_TO]->(t:Term)<-[rf:RANKS_FOR]-(u:URL)
WHERE rf.avgPosition <= 10
RETURN p.text, t.name, u.address, rf.avgPosition;

// Pre-click to pipeline (engagement draft): visibility windows around a conversion
MATCH (e:ConversionEvent)-[:CAPTURED_BY]->(cp:ConversionPoint)<-[:HAS_CONVERSION_POINT]-(u:URL)
MATCH (r:LLMResponse)-[:CITES]->(u)
WHERE r.capturedAt < e.occurredAt <= r.capturedAt + duration('P7D')
RETURN e.id, cp.crmRecordRef, collect(r.id) AS candidate_responses;

The decision layer — from an observation to a labeled recommendation

xeo-decision.ttl is where facts become a plan, honestly labeled as interpretation. It is the one chain the whole model builds toward —

observation  →  Diagnostic reveals Gap  →  Gap addressableBy Tactic
             →  Tactic requiresCapability          (the scope gate)
             →  Experiment tests Tactic, inContext Gap, producedOutcome
             →  Recommendation recommends Tactic, closesGap, supportedBy Experiment

The payoff query — the metric that triggered a diagnosis, the gap it revealed, the in-reach tactic to close it, and the precedent that earns the pick — is one traversal:

// In-reach tactics for an open gap, ranked by precedent strength
MATCH (g:Gap {websiteId: $tenant})-[:ADDRESSABLE_BY]->(t:Tactic)
WHERE all(c IN [(t)-[:REQUIRES_CAPABILITY]->(cap) | cap]
          WHERE (cap)-[:APPROVED]->() OR cap.approved = true)   // scope gate
OPTIONAL MATCH (e:Experiment)-[:TESTS]->(t),
              (e)-[:IN_CONTEXT]->(:Gap)-[:GAP_TYPE]->(gt)<-[:GAP_TYPE]-(g),
              (e)-[:PRODUCED_OUTCOME]->(o:Outcome)
RETURN t.label, count(e) AS precedents, avg(o.lift) AS avg_lift
ORDER BY precedents DESC, avg_lift DESC;

Classes, never values. Gap and Tactic are terms; a Citation-Waterfall stage and "publish a comparison page" are not — they are skos:Concepts and instances you slot into gapType, inIntervention, onDimension, atPriority. That split is the point: open scaffolding, your proprietary blend. The frame grows adoption; the fill is yours. (This is the one module that leans on SKOS as a load-bearing primitive rather than an optional bridge — the taxonomy standard is the right base for the "bring your own scheme" layer.)

Interoperability — stands alone, bridges out

XEO has no hard dependency: core, visibility, and engagement load and reason with zero external vocabularies present. It grounds its own terms in primary standards (HTTP, WHATWG, the GSC API) rather than borrowing another SEO ontology.

For anyone who already speaks the foundational web vocabularies, xeo-align.ttl is an optional crosswalk — alignments, not imports:

Alignment uses skos:closeMatch where the correspondence is approximate (no forced logical entailment) and rdfs:subClassOf/subPropertyOf only where an XEO term is a genuine specialization. The bridges assert nothing false and can be ignored entirely.

context.jsonld is the operational half: point it at a Neo4j export and the graph's labels, relationship types, and properties become valid RDF/JSON-LD — object properties resolve to node references, datatype properties carry their xsd types. Legible names in the graph, real IRIs on export.

What is deliberately NOT here

The slots, filled — reference schemes

An ontology that ships classes and never values leaves slots: xeo:gapType, xeo:atPriority, xeo:inIntervention, xeo:status. A slot nobody fills gets filled locally, once per consumer, in prose — and the same status ends up described five different ways across five systems.

xeo-schemes.ttl fills the slots with the vocabulary one agency actually runs in production, lifted verbatim from the repos named in each scheme's dct:source. It is published under its own namespace (xeos:) so it stays separable from the ontology proper: adopt a scheme as-is, extend it, or replace it — the slot is what XEO defines; a scheme is one answer.

SchemeFillsConcepts
gapTypexeo:gapType14 — what kind of deficit a Diagnostic found
gapVerdictxeo:verdict5 — attack · fix first · defend · hold · ignore
interventionxeo:inIntervention8 — the service catalogue: what an agency can deploy, who controls it, lead time
priorityxeo:atPriority3 — now · next · later
recommendationStatus · experimentStatus · practiceStatusxeo:statusthe three lifecycles
practiceKind · practiceSource · practiceOutcomethe norms tierhow a rule acts, where it came from, what it did
outcomeResult · outcomeResultReasonxeo:result · xeo:resultReasondid it move, and why it couldn't be judged
objectiveMetric · targetKind · engagementType · cadence · effort · executionthe delivery layer
magnitudeUnitxeo:magnitudeUnit8 — a size is never rendered bare
epistemicLayerxeo:epistemicLayerthe six kinds of claim, one IRI each

Two conventions make them consumable by software: skos:notation on every concept is the code — the exact string a system stores or sends — and schemes.json is a generated projection of the whole file, so a catalog can build a JSON Schema enum at boot without parsing Turtle:

import json, urllib.request
schemes = json.load(urllib.request.urlopen(
    "https://raw.githubusercontent.com/inboundfound/xeo-ontology/main/schemes.json"))["schemes"]
GAP_TYPES = [c["code"] for c in schemes["gapType"]["concepts"]]   # 14 codes, in stated order

Using it

# property graph
cat schema.cypher | cypher-shell -u neo4j -p <password>

The TTL files are plain OWL — load xeo-core, xeo-visibility, xeo-engagement, xeo-decision, xeo-strategy, xeo-delivery, and (if you want the crosswalk) xeo-align into any triple store or ontology editor. Decision builds on core; strategy and delivery build on decision; the rest stand alone. xeo-schemes is SKOS data, not ontology — load it where you want the reference values. To publish graph data as linked data, serve your Neo4j export under context.jsonld and it validates as RDF/JSON-LD.

Maintained by

Inbound Found. Built by working backwards from a production marketing knowledge graph, then generalized. Contributions, counter-proposals, and rude questions about our modeling choices are all welcome.

License

CC BY 4.0 — use it, extend it, ship it; just attribute.

REFERENCES.md

References — prior art

Ontologies and vocabularies XEO relates to. Distilled so the source repos don't need to be checked out locally.


SEOntology (seovoc) — WordLift et al.

https://github.com/seontology/seontology · namespace https://w3id.org/seovoc/ · 96 commits, none ours

The closest prior art to XEO: an open-source SEO domain ontology, initially developed by WordLift and enriched by SEO practitioners and knowledge engineers. Described by its authors as "a semantic operating system for modern SEO" — a shared vocabulary letting agents, apps and researchers reason about, audit and optimise content. Self-described as an early draft.

Accepted at SEMANTiCS 2026 (Research & Innovation Track).

Ships seovoc.ttl / seovoc.owl (~134 KB). Imports/relates to schema.org, skos, voaf, dc/dcterms, and WordLift's earlier SEO_Ontology.

@software{gjorgjevska2026seontology,
  title        = {SEOntology: A Domain Ontology for Semantic Modeling of Search Engine Optimization Workflows},
  author       = {Gjorgjevska, Emilija and Riccitelli, David and Jovanovik, Milos and Volpini, Andrea},
  year         = {2026},
  url          = {https://github.com/seontology/seontology},
  note         = {Accepted at SEMANTiCS 2026 Research & Innovation Track}
}

Relationship to XEO

We reference SEOntology as prior art and expect to align to it where the vocabularies genuinely meet. They are not the same ontology, and the difference is one of subject rather than quality:

SEOntology models traditional SEO. Its subject is the SEO workflow — content, crawling, keywords, on-page structure — expressed as linked data so agents and apps can reason over it. That is real and useful ground, and where XEO touches it we should relate terms rather than restate them.

XEO is AI-native and xEO-scoped. The subject is web engine optimization across the whole xEO family — SEO, GEO and AEO together — where the consuming system is as often an answer engine or an assistant as a search engine. That changes what has to be modelled.

Two areas extend past SEOntology's scope, and they are the reason XEO exists rather than being a profile of seovoc:

  1. Decision intelligence. XEO carries the reasoning, not only the artefacts — diagnostics and their stages (xeo-decision), norms that fire or veto (xeo-strategy: Practices, guardrails, provenance, an experiment ledger that promotes a claimed practice to learned), and provenance all the way down. Modelling why a recommendation was made, and how much to trust it, is a first-class requirement here.
  2. Chat assistant / agent surface. Engagement with assistants — citations, mentions, sentiment and the visibility layer they feed (xeo-visibility, xeo-engagement) — is native to XEO's subject and largely outside a workflow-centred SEO vocabulary.

Practical stance: cite SEOntology, align the overlapping terms in xeo-align.ttl when we do the alignment pass, and do not force the decision-intelligence or assistant layers into it. The overlap is worth an explicit mapping; the extension is the point of the ontology.

Status: xeo-align.ttl currently relates XEO to schema.org, prov and skos (dcterms is used for module metadata, not aligned to), and does not yet mention seovoc. The alignment pass is open work.


Also related

The runnable consumer of this ontology is xeo-graph-kit, which carries its own REFERENCES.md for the implementation-side prior art (Neo4j context graphs, GEO tactics planning).