Why doesn’t AI mention your brand? Find out which half is brokenGet a free report
LLMention
Try it on example.comScan API

Scan API: fetch the GEO score programmatically

One public endpoint returns the same analysis the report page renders. No key, no account, no sign-up. This page documents the parameters, the response, the rate limit, and the limits the API itself does not fix.

Documented 23 October 2026. The endpoint is unversioned; see the limits below.

What does the endpoint do?

It fetches a domain the way a crawler would, reads robots.txt, llms.txt and sitemap.xml when they exist, and scores the page against the same published rule set the site describes on /methodology/. The caller gets the score, the twelve dimension results and the issue list, not a screenshot of them.

GET https://llmention-geo.com/api/scan?domain=example.com

The scan runs during the request, so a first call on a cold domain takes as long as fetching that domain takes. The same analyser powers the report page and the published study, which is why a score from here and a score from the interface are the same number.

What parameters does it accept?

ParameterRequiredWhat it does
domainYesHostname only. A pasted https:// prefix, a path or a query string is stripped; a www. prefix is removed.
brief=1NoReturns headline numbers only - roughly 300 bytes instead of about 8 KB - without dimensions or the issue list. It is how a caller collecting many domains avoids pulling a full report per domain.
scope=siteNoAdds a site block: the homepage plus pages named by the sitemap, each scored by the same analyser, with a site average and the issues that recur across pages.
pages=NNoThe site-scope budget: pages beyond the homepage, default 5, maximum 10. Supplying it implies scope=site.

brief=1 wins over scope=site when both are sent. That is deliberate: the brief form exists to make bulk collection cheap, and a site block is the opposite trade.

What does the response contain?

A full scan returns reachable, status, scheme, browserStatus, scoreBasis, truncated, score, grade, gradeLabel, dimensions, checksRun, checksPassed, pageType, checksNotApplicable, issues and metrics.

  • scoreBasis says what the score describes. It is "homepage" when the page answered 200, and "403 error response" and so on when it did not - an error response is not a page, and the field exists so a caller cannot mistake one for the other.
  • dimensions carries all twelve weighted results, each with its earned and possible points and the published rationale.
  • issues lists the failed and partial checks with the evidence that produced them and the fix the rule page publishes.
  • truncated is true when the fetch stopped at the size cap, so the score describes what was read rather than the whole document.
  • checksNotApplicable is the count of rules excluded for this page type or premise. A score of 39/39 with one excluded is not a score of 39/40; see the method.

What does a brief response look like?

This is a real response for example.com, captured on 23 October 2026. It is not an illustration: run the same request and you should get the same shape.

{
  "domain": "example.com",
  "status": 200,
  "browserStatus": null,
  "scoreBasis": "homepage",
  "truncated": false,
  "score": 16,
  "grade": "F",
  "checksRun": 40,
  "checksPassed": 5,
  "aiCrawlersBlocked": false,
  "hasJsonLdEntity": false,
  "hasSameAs": false,
  "hasRobotsTxt": false,
  "topIssue": "robots-present",
  "pageType": "homepage",
  "checksNotApplicable": 1
}

What are the rate limits?

A best-effort in-isolate token bucket: 20 requests per client address per minute. When it is exhausted the endpoint answers 429 with a Retry-After header. It is not a global limit - Cloudflare runs many isolates, each with its own counter - so a caller planning bulk work should pace itself rather than rely on the number. This is stated because an accurate warning is more useful than a promise the architecture cannot keep.

What status codes does it return?

StatusMeaning
200A result. A site that refused the crawler still returns 200 with reachable: true and status: 403 - the refusal is the finding.
400The domain is not a valid hostname, or refuses to resolve to a public address. The body carries an error string.
429Rate limited. Retry after the Retry-After value.

If neither scheme answers at all, the response is 200 with reachable: false, score: 0 and an empty issue list. An unreachable domain is a result about reachability, not a server error caused by the caller.

What does the endpoint not do?

  • It does not see a firewall. A request from this scanner comes from its own address, so a CDN rule aimed at bots can refuse it while serving a browser. That is reported as a partial result for the access checks, not as a pass.
  • It does not execute JavaScript. A client-rendered page is scored as a crawler receives it.
  • It does not ask an AI engine anything. The score describes whether a page can be cited, not whether it currently is; the comparison page explains the distinction.
  • It does not store what it scans. There is no history and no key to lose.
  • It is not a versioned contract. Fields may be added, and the route may change with the site; the published method is the stable part, not the JSON envelope. If you build on it, pin to the fields you read and re-check after a release.

How do I call it from a script?

# Headline result for one domain
curl -s "https://llmention-geo.com/api/scan?brief=1&domain=example.com"

# Full report, including every dimension and issue
curl -s "https://llmention-geo.com/api/scan?domain=example.com" | jq '{score, grade, issues: [.issues[].id]}'

# Homepage plus up to five sitemap pages
curl -s "https://llmention-geo.com/api/scan?domain=example.com&scope=site" | jq '.site.siteScore'

The parameters and response are implemented in app/api/scan/route.ts, and the site-scope budget in lib/geo/scan.ts. Both are readable, because a documented API that cannot be checked is a claim.

Can I use it commercially?

The endpoint is free and unauthenticated, and the source is MIT licensed. There is no service-level agreement: this is a small independent project, not a platform, and calling it in a loop is what the rate limit and the absence of a key exist to discourage. For bulk or agency work, the paid measurement report is the supported path - and email if the shape of your work is not listed there.

Why is this endpoint not on the homepage?

Because the site is for people who want to know whether their pages can be cited, and most of them do not want a JSON envelope. The API is the same measurement for the readers who do - developers, agencies and anyone collecting data at a scale the interface does not serve. It is linked from the tools index, the navigation and /llms.txt so it is not a secret.

Questions about the scan API

Do I need an API key?

No. The endpoint is public and unauthenticated, and the scanner stores no scan history. The rate limit is the only gate, and it is a best-effort one.

Why is the rate limit not exact?

Because it is enforced inside a Worker isolate, and Cloudflare runs many isolates. The counter stops one caller hammering one isolate; it is not a global quota. The honest limit is the published one rather than a number the architecture cannot deliver.

Can I get every page of a site?

Not every page. scope=site reads the homepage plus up to ten pages named by the sitemap, chosen section by section; five is the default. That is a budget rather than a sample, and the response states how many pages were considered and capped.

Is the score the same as the report page shows?

Yes. Both call the same analyser against the same support files, which is why the published study was collected through this endpoint. What differs is the presentation, not the measurement.