Back to Overfront

How the Overfront AI Visibility Score works

This document is the public definition of the score (REQ-030). It lives in the same repository as the implementation (api/src/core/score.ts) and any change to the formula updates this file in the same commit.

What we measure

For a domain d and an AI engine e, we run a versioned set of discovery prompts — questions a user who does not know the brand would ask — and check whether the engine’s grounded answer cites or mentions the domain.

Prompt weights

Each discovery prompt carries a weight reflecting how likely real users are to ask it. Prompts derived from real autocomplete suggestions are weighted by their autocomplete rank (a popularity proxy): the top suggestion gets the maximum weight (currently 2.0), decaying linearly toward the base weight. Prompts generated without a matching suggestion keep the base weight 1.0.

Formulas

With w_p the weight of prompt p :

CitationRate_e(d)          = sum(w_p over cited prompts) / sum(w_p over all prompts)
EffectiveCitationRate_e(d) = sum(w_p x (linked x 1.0 + unlinked mention x 0.3)) / sum(w_p)
RunScore(d)                = 100 x sum_e( w_e x EffectiveCitationRate_e(d) )   (integer, 0-100)
AI Visibility Score(d)     = mean of RunScore over all measurements in the
                             last 35 days (integer, 0-100)

The displayed score averages successive measurement runs. AI answers vary between runs even for identical prompts, so a single snapshot is noisy; the rolling mean smooths answer-side variance while the reused prompt plan keeps runs directly comparable. The number of runs behind a score is exposed as runs in the API response. Note that the per-engine breakdown in the API response reflects the LATEST run only, so it does not arithmetically reconstruct the averaged score once more than one run is in the window.

Small samples

At the sample size one run affords, the plain rate cannot tell “never cited” from “cited rarely”: a site with a true appearance rate of 11% returns zero citations from 10 prompts about 31% of the time, and the plain rate then reports exactly 0 for a site that is not absent at all.

Where a prior has been fitted, the displayed score is therefore the posterior mean of a Beta prior updated with the run’s effective sample size, rather than the raw ratio:

Displayed(d) = (rate x n_eff + alpha) / (n_eff + alpha + beta)

alpha and beta describe the distribution of appearance rates across all domains we have measured, and are estimated from those measurements — never chosen by hand. Until enough domains have been measured for that estimate to mean anything, both are empty and the displayed score is exactly the observed rate. The reported interval always describes the observed rate, so the score is a point estimate inside a range that is stated honestly either way. Brand scores are not shrunk: branded prompts are a different population from the one the prior is fitted on.

Uncertainty

Scores come with an approximate 95% interval (scoreLow / scoreHigh in the API response): a Wilson score interval computed on the effective sample size of the weighted prompt set, scaled by the number of runs in the window. At the default 10 prompts a single run’s interval is wide by design — treat a first score as an estimate, not a verdict; it narrows as weekly runs accumulate.

Sampling rules

What the score is conditional on

Every measurement call forces the engine to run a web search. That removes a large source of run-to-run variance and keeps the cost of a run predictable, but it also means the score answers a conditional question:

Given that the engine searched the web, how often does it cite this domain?

It is not the unconditional chance that a user asking this question sees the domain. Published measurements find that a large share of ChatGPT repetitions never activate web search at all, so the unconditional figure is lower than the score reported here. We force search rather than sampling the activation rate because an unforced sample would mix two different sources of variance — whether the engine searched, and what it cited once it did — into one number that moves for reasons a site owner cannot act on.

Mention detection

Text mentions are matched after Unicode NFKC normalization with word-boundary protection for ASCII names and substring matching for scripts without word boundaries (e.g. Japanese). The detector is versioned; every measurement records the detector version so that score shifts caused by detector changes are distinguishable from real visibility changes. Citation position (where in the answer’s citation list the domain first appears) is recorded but not part of the score.

Current engine weights w_e : ChatGPT (OpenAI) = 1.0. Weights will be based on public AI traffic share data as more engines are added.

Brand prompts are scored separately

Prompts that contain the brand (“Is X trustworthy?”, “X reviews”) measure awareness and sentiment, not discoverability. They are shown as a separate Brand Score and are never included in the AI Visibility Score.

The same rule applies to user-registered prompts: site owners can register a small number of questions they care about, and these are measured alongside each run and reported per prompt — but they never enter the AI Visibility Score, because self-chosen questions would let a site score against a test it wrote itself.

Method notes