Methodology

How AlpineRank measures AI visibility

How the score is calculated, what each signal measures, and where the method has limits. Every formula on this page is the one in the code. If something here is vague, that is a bug — tell us.

What we measure — and what we don't

Every score on this page is calculated from one page: the exact URL you submit. We do not crawl your site, follow links, or aggregate across pages.

That is deliberate rather than a shortcut. AI engines cite individual pages, not sites — an answer that lives on your FAQ page does not help the visitor who lands on your homepage. But it does mean a homepage audit will mark questions as missing that your site answers elsewhere. If FAQ or service content matters to you, audit those pages too.

Two of these checks read the whole domain rather than the page, because that is where they live: AI Crawler Access reads /robots.txt, and the llms.txt bonus reads /llms.txt.

How the composite score is calculated

Seven weighted signals. One is question coverage; six are technical checks on the page.

SignalWeightWhat it reads
AI Question Coverage30%25 generated questions scored against the page
AI Crawler Access20%/robots.txt
Structured Data15%every JSON-LD block on the page
Answer Structure15%question headings and the text below them
Citations10%figures and outbound source links
Freshness5%dates in markup
E-E-A-T5%author and organisation markup

The composite is the weighted mean of the signals we could measure. Crawler access is dropped from both the numerator and the denominator when your robots.txt cannot be read — it is not counted as zero, and it is not counted as a pass. It is the only signal that can come back unverified, because it is the only one we fetch separately: the other five read the page HTML we already have, so for those an absent signal is a real finding and scores zero. A page we cannot read at all fails the audit outright rather than being scored around.

That is the behaviour most of this category gets wrong. A tool that scores an unreachablerobots.txtas “no blocks found” reports a green tick that means “we failed to look”, and the inflation is invisible unless someone tells you.

The gate. If GPTBot, ClaudeBot or PerplexityBot are blocked inrobots.txt, the composite is capped at 40. A page those engines cannot fetch cannot be cited, and averaging a blocked crawler against good structured data produces a number that describes nothing.

llms.txt carries no weight. It is reported under Agent Readiness, below.

30% of overall

AI Question Coverage (the heaviest signal)

The largest single component of the score, and the one that needs the most explaining — so it gets the most detail here.

When someone searches with an AI engine, they don't type a keyword — they ask a question. AlpineRank detects your page's niche, then uses Claude to generate 25 real questions that people in your niche actually ask AI engines. It then checks whether your page answers each one.

The scoring is three-tiered: covered (full answer present), partial (topic mentioned but not directly answered), or missing (no coverage). The score is (covered × 1.0 + partial × 0.5) / total × 100. A verdict that comes back unusable is recorded as missing — we round against the page, not in its favour.

Princeton's 2024 GEO study found that pages with statistics, citations, and direct answers to common questions received up to 40% more citations from LLMs than comparable pages without them. AI Question Coverage is the operationalisation of that finding.

Where the questions come from

Site identity and page topic are detected as two separate model calls and then composed. A single combined call fails on topic pages inside larger sites: the Wikipedia heat-pump article resolves to “online encyclopedia”, and the questions come back about editing Wikipedia.

From that topic we generate 25 questions, spread across six intents — definition and mechanism, cost, comparison, how-to, troubleshooting, trust and safety. The inputs are the topic, the hostname and the detected language. Page content is not an input. Questions derived from the page would score the page against itself.

Why the set is frozen

The set is stored per normalised URL and reused for every later audit of that URL. Both inputs are non-deterministic model calls, so before freezing, two audits of an unchanged page three hours apart scored 54 and 28 on coverage with every technical signal byte-identical — 30% of the composite moving on its own. Question sets are dated on the report, so you can see which set you are being measured against.

A set is only redrawn when you ask for it. If your page's subject has genuinely changed you can discard the set from the report, and the next audit draws a fresh one. Score history either side of a redraw is not directly comparable — which is why it is a deliberate action rather than something that happens on its own.

Known limits. Question quality depends on topic detection; a page whose subject is genuinely ambiguous gets a vaguer set.

Six signals are deterministic. Question Coverage is not.

Worth being explicit about, because it is the one place a re-audit can move without your page moving. The six technical checks are pure functions over the HTML we fetched: the same page produces the same six scores every time, and we test that. Question Coverage is a model judgement, and the same page can score slightly differently on two consecutive runs — it reads a hedged non-answer as partial, which is right, but the covered/partial boundary is a judgement and judgements are not bit-identical.

Measured, not estimated. Two back-to-back audits of an unchanged page: on one site every signal matched exactly, coverage included. On another, all six technical signals were identical while coverage moved by two points, with three of the twenty-five verdicts flipping across the covered/partial/missing boundaries. The composite happened to land on the same number both times because coverage carries 30% and the movement rounded away — but a different combination of flips would show as a point or two on the overall score.

So: treat a one or two point move between audits of an unchanged page as noise, not a result. Freezing the question set removed the large source of this — before it, the same page scored 54 and 28 three hours apart. What remains is the residual judgement variance, and the honest thing is to name its size rather than imply a precision the signal does not have.

20% of overall

AI Crawler Access

We fetch your robots.txt and parse it for 9 AI crawlers: GPTBot, ChatGPT-User, OAI-SearchBot, ClaudeBot, Claude-SearchBot, anthropic-ai, PerplexityBot, Perplexity-User, and Google-Extended.

Each bot is scored individually. The final score is the proportion of bots that are allowed. Additionally, if any of the three primary gating bots (GPTBot, ClaudeBot, PerplexityBot) are blocked, the overall scorecard is capped at 40— because even a perfect content score is meaningless if the crawler can't reach the page.

Unable to verify.If the request returns 403, times out, or answers with a non-200 status, the signal is recorded as unverified with the reason attached (“robots.txt returned 403”, “the request timed out”) and excluded from the composite. A missing robots.txt is a different case: that means nothing is blocked, which is a genuine pass and is scored as one.

Known limit. robots.txt is site-wide and advisory. It tells you what a well-behaved crawler is asked to do, not what any crawler did. Server-level blocking — a WAF rule, a Cloudflare bot setting — is invisible to this check, and a page can be unreachable while robots.txt looks perfect.

15% of overall

Structured Data

We parse every application/ld+json block on the page and collect every@type, however nested — bare objects, top-level arrays, @graph arrays (what Yoast and RankMath emit), and @type given as an array of strings. Recursion covers nested entities under @graph, mainEntity,itemListElement, about, publisher and author.

Scored against five target types — FAQPage, Article, Organization, Product, HowTo — with subtypes credited to their parent, so BlogPosting counts as Article and LocalBusiness as Organization.

Score: found / 5 × 80, plus 20 if the page carries any valid JSON-LD at all. Types we recognise but do not score are reported separately rather than silently discarded, and malformed JSON is skipped rather than guessed at. Each missing schema type generates a specific JSON-LD snippet you can copy into your <head>.

Known limit.Presence, not correctness. We do not validate every required property against the schema.org spec — use Google's Rich Results Test for that.

15% of overall

Answer Structure

AI engines prefer pages that structure content as question → answer pairs, because it maps directly onto how queries are formed. We look at headings from H2 to H4, plus accordion titles — a lot of real FAQs live in accordions, and a headings-only pass finds nothing on those pages.

A heading counts as a question if it ends with a ?or opens with an interrogative (how, why, what, when, where, who, which, can, is, are…). That list is matched on whole words. An earlier version matched prefixes, so “Bionic” matched biand “Canton” matched can, and pages scored 100 on a single heading that was not a question.

For each question heading, we check whether a substantive paragraph (more than 20 characters) follows before the next heading. Score: answered / question-headings × 100. No question headings at all scores 0 — the structure is not there.

Known limit.“Substantive” is a length-and-content heuristic. A short but genuinely complete answer can read as thin.

10% of overall

Citations

Pages that cite data and link to external sources are cited more often by AI. We count two signals in the main content (excluding nav, footer, and sidebars):

  • Statistics: percentages, prices, quantities and durations (e.g. 45%, 1,200 EUR). Phone numbers, VAT identifiers and postcodes are excluded — they are contact details, and counting them inflated this signal on exactly the pages carrying no evidence at all.
  • External links: outbound links to domains other than your own. Links to your own pages do not count; the signal is whether a claim is backed by somewhere else.

5 or more figures contribute 50 points; 3 or more external links contribute 50 points. Scores are scaled linearly below those thresholds.

Why this is weighted at all. The Princeton GEO study measured nine optimisation levers against generative engines. Citing sources and adding statistics were among the three strongest, at roughly +30–40% relative visibility. Keyword density, which much SEO advice still leads with, measured flat to negative — we do not score it.

5% of overall

Freshness

AI models prefer recent, maintained content. We extract the most recent date from your page — first from JSON-LD (dateModified / datePublished), then from Open Graph meta tags (article:modified_time, article:published_time).

Scoring tiers: ≤1 month → 100, ≤3 months → 85, ≤6 months → 70, ≤12 months → 50, ≤24 months → 25, older → 10. No date found → 0.

5% of overall

E-E-A-T Signals

Experience, Expertise, Authoritativeness, and Trust — Google's framework, increasingly adopted by AI engines for source evaluation. We check three signals:

  • Author byline: itemprop="author", rel="author", or a class containing author on any element (detection only — fixes recommend Person JSON-LD or an author field in an existing Article schema)
  • Author or About link: a link to an author, about, team, staff or writers page. Matched on link text as well as the slug, and in several languages — the English-only pattern this replaces is the confirmed reason a site with a real /o-nas page was told it had no About page
  • Organization schema: Organization or LocalBusiness JSON-LD

Score: signals_found / 3 × 100. Fixes use JSON-LD structured data; CSS-only markup is not reliably parsed by AI engines.

not scored

Agent Readiness (bonus, tracked separately)

Some emerging signals are tracked by AlpineRank but kept outside the GEO score — because no major AI provider has confirmed they affect search citation ranking. Folding unconfirmed signals into the score would make it less meaningful.

These appear in a separate “Agent Readiness” section on your audit report, clearly labeled as optional preparation rather than critical fixes.

LLMs.txt

The llmstxt.org standard proposes placing a /llms.txtfile at your domain root to guide AI agents about your site's content and structure. We check for its presence with a HEAD request (binary: 0 or 100). If absent, we generate a starter template.

We track it because it is low-cost to add and may become relevant as agentic AI use grows — but Google has explicitly stated it does not use llms.txtfor ranking or citation, and no other major AI provider has committed to it either. Until confirmed adoption exists, it belongs in “Agent Readiness” rather than the core score.

reported, not scored

Live citation checks

Five of your 25 questions, put to each engine your plan includes — Perplexity on all plans, OpenAI's web-search API on paid plans — once each. Both engines are asked the same five, so the two verdicts on a row can be read against each other.

Which five.Covered questions first, then Partial, then an even spread across Missing. A question your page answers that an engine still did not cite is the one result that changes what you should do — every other gap says “write the answer”, and that one says the answer is already there and something else is in the way. In practice most pages have very few Covered questions, so the sample usually falls through to Partial and Missing; the spread across the Missing tail is what stops it probing only the “what is it” end of an intent-ordered set.

A question counts as cited when your domain appears in the answer's source list. Your domain being named in the prose without being used as a source is recorded separately and never counted as a citation. Being mentioned is not being the source the engine relied on, and merging the two would flatter everyone.

This is a snapshot, not a rate.Engines are non-deterministic. Five questions asked once each cannot produce a stable percentage, and reporting one would be false precision. “0 of 5” means “not visible in this sample”.

We say “OpenAI” rather than naming a consumer chat product, because the API we query is OpenAI's search infrastructure rather than the product a person types into. The answers are close but not identical, and claiming otherwise would be exactly the kind of small overstatement this page exists to avoid.

Who got cited instead

When an engine answers a sampled question without using your domain, we list the domains it did use — up to three per question. That data was already in the response and used to be discarded. Platform, reference and government hosts (YouTube, Wikipedia, Reddit, .gov) are filtered out: a page cannot compete with them, and listing them as rivals would bury the finding that matters.

Where our verdict and the engine disagree

Two combinations get a badge, because only two say something the Covered / Partial / Missing label does not. Answered, not cited means we judged your page answers the question and the engine still chose another source. That points at trust, freshness or format rather than missing content — so writing more content, which is what every other gap implies, is the wrong fix for it. Cited despite the gap is the reverse: the engine used you on a question we scored as thin, meaning it accepted a shallower answer than our scorer did.

Only sampled questions can carry a badge. The rest get nothing rather than a guess — “we did not ask” is a different state from “we asked and you were not cited”, and collapsing the two would invent a result.

Who is being cited instead

The same source lists, counted across every question you have checked and both engines, reduced to the single most-cited domain and the fraction of checked questions it appeared on. A domain counts once per question, not once per URL it supplied, so a site that contributed four pages to one answer does not outrank a site cited on three separate questions.

It is a pointer, not a ranking of your market. This used to be a ranked list of five domains, which reads as a league table however carefully the caption hedges — five probes cannot support one. One name and the count it rests on says the same true thing and cannot be misread. It disappears entirely when there is nothing honest to say: nothing checked yet, every check cited you, or nothing but platforms and reference sites no page competes with. Reported, never scored.

Reused results

A citation result is good for a domain for seven days. Whether an engine cites you is a property of your domain's standing in its index, not of the heading you edited an hour ago, and the normal loop here is audit → fix → re-audit, sometimes several times a day. Within that window we copy the previous result forward and label it on the report rather than charging for the same answer twice.

Per-question verdicts are carried forward with it, matched on the question text. Since your question set is frozen per URL, re-auditing the same page reuses the same questions and every verdict transfers; a different page of the same site matches only the questions it genuinely shares, and anything the earlier run never asked stays blank.

Checking a question yourself

The other twenty questions are not checked automatically, because asking an engine costs money on every question of every audit. On a paid plan you can check any of them on demand, against both engines, from the row itself — out of a monthly allowance shown next to the button.

That gives you another snapshot, not a rate. We do not offer a repeated-sampling mode: it cost about $0.11 a question, and the answer it returned was usually either 0/20 or 20/20 — an interval around a number you could already read off a single check.

reported, not scored

Benchmarks

Two forms, both labelled with the sample behind them.

Category benchmark.Median and 75th percentile for your page's category, shown with the number of sites and accounts behind it. These are sites audited with AlpineRank. That is not a survey of the industry, and the population is self-selecting: people who run GEO audits are people trying to improve.

Your own history. Once you have run 5 audits we show your average and your best fifth, labelled with the count. We do not compare your scores against other accounts.

Below 5 audits you get a published reference point labelled “Typical range” and “High performers” — explicitly a reference, not your data and not an industry figure. We would rather show a labelled placeholder than compute an average from three data points and print it like a fact.

reported, not scored

Generated content

Paid plans get paste-ready fixes: an answer paragraph per gap, an FAQ HTML block, and JSON-LD schema.

Every one is checked against your page before you see it. Dates, prices and percentages your page does not state are replaced with placeholders — [INSERT PRICE], [INSERT DATE]— with a line explaining why. Matching is on the number, so “1.200 EUR” on your page supports “1200 EUR” in the fix; that is formatting, not invention.

This exists because it failed once. A generated fix for a question a page did not answer came back with an invented price and a date in the past, ready to paste onto a live site. The prompt now forbids it, and the check no longer depends on the model complying.

Its limit, stated plainly.The check covers dates, prices and percentages. A claim with no figure in it — “an exceptionally good price”, “the most trusted supplier in the region” — cannot be caught by any pattern, and is addressed only by the prompt. Read generated text before publishing it — the placeholders tell you where a figure is missing, and nothing else about the text has been verified for you.

Projected scores after fixes are 40% of the theoretical maximum gain, weighted by each signal's contribution. Deliberately conservative: real gains depend on implementation.

What we don't measure — and why

We can't guarantee that any AI engine will actually cite your page. No tool can. AI citation behaviour is non-deterministic: the same query returns different results across sessions, models, and time.

What AlpineRank measures are the structural signalsthat correlate with higher citation rates in published research. Improving these signals increases the probability of citation — it doesn't guarantee it.

We also don't currently measure: page load speed, mobile usability, internal linking structure, or domain authority. These matter for SEO and may correlate with GEO — they're on the roadmap.

Check your page now

Free audit — no sign-up required for the first result.

Run a free audit →

Known limitations

Every number on a report is a measurement, and every measurement has edges. These are ours.

Technical checks are validated against a hand-labelled test set.Schema detection, crawler access, freshness and answer structure are tested against real pages whose correct answer we established by hand, and the tests run on every change. That is how we catch a parser that stops recognising a valid markup format — a class of bug that otherwise surfaces as a confident, wrong finding on a customer's site.

Citation checks are a snapshot, not a rate.Ask an AI engine the same question twice and it may cite different sources. A regular audit asks each sampled question once, so "0 of 5" means we did not see your site in those five answers — not that it is never cited. Distinguishing "never" from "sometimes, and we got an unlucky draw" would need asking the same question many times over, which we do not do. Read a citation result as one observation, and re-check a question yourself if it matters.

E-E-A-T measures machine-readable proxies, not expertise. We can see an author byline, a link to an about page, and Organization markup. We cannot see whether the named author knows the subject, whether the team on your about page is real, or whether your company is trusted in its field. A genuine expert with no schema markup will score poorly here, and that is a statement about the markup rather than about the expert.

One page, not the site.Scores describe the exact URL submitted. See "What we measure — and what we don't" above.