GEO Scanner Reference

This page details the scoring logic behind the GEO Scanner in the Universal Visual Editor. It is intended for developers and content strategists who want to understand precisely why a page received a particular score and what changes will move specific signals.

For a conceptual overview of the scanner and how to run it, see the UVE documentation.

Score Calculation#


The composite GEO score (0–100) is a weighted sum of four category scores:

GEO Score = Citability × 0.30 + Structured Knowledge × 0.25 + Content Authority × 0.25 + Discoverability × 0.20

Each category score is the simple average of its five signal scores (each 0–100). The composite is rounded to the nearest integer.

Issue severity is assigned per signal: a score of 0 is high; below 40 is medium; below 70 is low. Issues are surfaced sorted high → medium → low.

8 of 20 signals are binary pass/fail with no partial credit: author attribution, publish date, HTTPS, indexability, language declaration, and the zero-count floor of citations, statistics, and quotations. A page that is "almost there" on one of these still scores 0 on that signal.

Citability (30%)#


Signals in this category are scanned over the detected mainContent region only. Navigation, header, footer, sidebar, and ARIA landmark regions are stripped before analysis.

SignalWhat it checksScore bands
Source citations<a href> elements in main content whose hostname differs from the page's own0 → 0;
1 → 20;
2 → 40;
3 → 55;
4 → 70;
5 → 80;
6 → 90;
7+ → 100
Statistics / dataRegex over main-content text matching: percentages, currency values, year ranges ("since 2024"), numbers with thousands separators, "X million/billion", "5x" multipliers — deduplicated across matches0 → 0;
1 → 20;
2 → 40;
3 → 55;
4 → 70;
5 → 76;
6 → 82;
7 → 88;
8 → 94;
9+ → 100
Expert quotations<blockquote> count, plus curly-quote spans of ≥20 characters followed by an em/en-dash and a word, or followed by: said, says, according to, wrote, noted, explained, stated0 → 0;
1 → 40;
2 → 65;
3–4 → 85;
5+ → 100
Content depthWord count of main content (whitespace-split)<100: linear 0–20;
<300: 20–40;
<600: 40–65;
<1000: 65–80;
<2000: 80–95;
2000+: 100
Answer structureTwo sub-checks: (a) whether the first <p> is ≥40 characters ("has intro"); (b) H1–H6 walked in document order, any level jump greater than 1 flagged as "partial"hasIntro: +50;
hierarchy valid: +50 / partial: +25 / missing: +0

Structured Knowledge (25%)#


SignalWhat it checksScore bands
Schema presentCount of <script type="application/ld+json"> blocks in <head> or <body>0 → 0;
1 → 60;
2–3 → 80;
4+ → 100
Schema validityEach block must parse as valid JSON and contain a string @type field(valid blocks / total blocks) × 100
Schema completenessThe first block whose @type matches a type with a recommended-property checklist (see below)(present properties / total recommended) × 100;
matched type with no checklist = 50
Heading hierarchyH1 count and level-skip detection across the full <body>Exactly one H1: +40 / more than one: +20;
two or more headings present: +30 / one heading: +15; no skipped levels (with ≥2 headings): +30 / any skip: +10
Internal linking<a href> in main content whose hostname matches the page's own (or non-http hrefs); excludes # anchors and javascript: links0 → 0;
1–2 → 30;
3–5 → 60;
6–10 → 80;
11+ → 100

Recognised Schemas#

The scanner accepts the following 26 @type values for validity and type-matching:

Article, NewsArticle, BlogPosting, TechArticle, ScholarlyArticle, Report, WebPage, AboutPage, FAQPage, QAPage, CollectionPage, ProfilePage, ItemPage, Product, SoftwareApplication, Organization, Person, Event, Course, Recipe, HowTo, Review, LocalBusiness, BreadcrumbList, VideoObject, ImageObject.

Recommended-Property Checklists#

The Schema completeness signal works by finding the first JSON-LD block on the page whose @type is one of the 26 recognised types, then checking how many of that type's "recommended" properties are present and scoring (present / recommended) × 100.

This checklist only exists for 13 of those 26 types — the content-heavy ones like Article, WebPage, Product, FAQPage, etc. The other 13 (e.g., ScholarlyArticle, SoftwareApplication, Recipe, Review, etc.) are accepted as valid schema, but no one has defined what "complete" looks like for them. Instead of measuring their completeness, the scanner awards a flat 50 rather than penalizing the page for having schema that happens to be a less common type.

TypeRecommended properties
Article, NewsArticle, BlogPostingheadline, author, datePublished, dateModified, image, publisher, description
TechArticleheadline, author, datePublished, dateModified, image, description
WebPagename, description, url, datePublished, dateModified
Productname, description, image, offers, brand, sku, review
Organizationname, url, logo, description, sameAs
Personname, url, image, jobTitle
FAQPagemainEntity
HowToname, step, description, image
Eventname, startDate, endDate, location, description, image
BreadcrumbListitemListElement
VideoObjectname, description, thumbnailUrl, uploadDate, duration

Content Authority (25%)#


SignalWhat it checksScore bands
Author attributionAny of: a author field in JSON-LD; <a rel="author">; an element matching .author, .byline, [class*="author"], [class*="byline"], or [itemprop="author"] with non-empty text; <meta name="author"> with contentFound → 100;
not found → 0 (binary)
Publish dateFirst match of: JSON-LD datePublished or dateModified<time datetime><meta property="article:published_time"> or article:modified_time → a recognisable date pattern in visible body textAny match → 100;
no match → 0 (binary)
Image alt textAll <img> elements in <body>, checking for a non-empty alt attribute(images with alt / total images) × 100;
zero images on the page = 100 (not penalised)
Content uniqueness (title)<title> checked against a generic blocklist (home, homepage, welcome, index, untitled, blog, news, page, default); length target 30–60 charactersNon-generic: +40;
length 30–60 chars: +40 / 15–29 or 61–80 chars: +20;
any non-empty title: +20
HTTPSWhether the page is served over HTTPSTrue → 100;
false → 0 (binary)

Discoverability (20%)#


SignalWhat it checksScore bands
Meta description<meta name="description"> content length120–160 chars → 100;
80–119 or 161–200 → 70;
50–79 or >200 → 40;
other non-empty → 20;
missing → 0
Canonical tag<link rel="canonical"> resolved URL compared to the page's final (post-redirect) URLMatches → 100;
present but mismatched → 60;
missing → 0
Indexability<meta name="robots"> content checked for a noindex tokenIndexable → 100;
noindex present → 0 (binary)
Open Graph tagsRequired set: og:title, og:description, og:image — each must carry non-empty content(tags present / 3) × 100
Language declarationlang="..." attribute on the <html> element (matched against raw HTML)Present → 100;
absent → 0 (binary)