GEO Readiness
GEO Readiness answers a question nothing else in the back office can: when GPTBot, ClaudeBot or
PerplexityBot ask for one of your pages, what do they actually get? It adds a GEO readiness action
to jContent for a single page, and a site-wide dashboard under Additional > SEO.
It is deliberately not a browser audit. The editor's browser is authenticated, runs JavaScript and
is never challenged by the firewall, and a crawler is none of those three. So every question is
answered server-side - one fetch per crawler user agent, no cookies, no session, redirects not
followed - and it reads the initial HTML rather than a rendered DOM, because a page whose content
only appears after JavaScript runs looks perfect to an editor and empty to a crawler.
The page drawer fetches the published page sixteen times: once as a normal browser for a control,
then once as each of fifteen AI crawlers - GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot,
Claude-SearchBot, PerplexityBot, Perplexity-User, Google-Extended, GoogleOther, Bingbot, CCBot,
Bytespider, Amazonbot, Applebot-Extended and meta-externalagent. For each it reports the status, the
time, the word count and what the initial HTML contains. Then the disagreements, which are the part
worth reading: blocked but allowed, where robots.txt permits the crawler and the server refuses it
anyway - usually a firewall rule nobody remembers adding; reachable but disallowed, the same
contradiction the other way round; thin, where a crawler receives far less text than the browser
did, which points at rendering that depends on JavaScript; and invisible, where no anonymous
visitor can read the page at all, so no crawler ever will. A page that has never been published
says so rather than showing an error.
The site dashboard is ten panels in four groups. Overview holds the site score and, when a provider
is configured, the written report. Can a crawler reach it holds invisible content, internal links
and addresses. Is what arrives usable holds structured data, languages and freshness. Site-level
files holds sitemap vs reality, robots.txt and llms.txt. Everything except the site scan is a
repository query, so most panels answer immediately rather than waiting for a walk of the site.
Findings roll up to the template that produced them. A check is blamed on the template only when it
fails on nearly every page that template renders: three failures out of four hundred is three
authors, four hundred out of four hundred is the template. Nothing outside Jahia knows which
template rendered a page, which is what makes this a platform feature rather than a page tool.
The score is a count of checks, not a rating out of 100. Eighteen checks in three groups, each
reading one observed fact and showing that fact beside the verdict, so an editor can disagree with a
specific line rather than with a number they cannot see inside. Being disallowed in robots.txt is
deliberately not counted as a failure - refusing a crawler is a legitimate decision. A disagreement
between the policy and the server is, because one of the two is then wrong and somebody owns the
fix.
The robots.txt panel lists each of the fifteen crawlers, what it does, and what blocking it would
cost: seven answer questions, so refusing one takes the site out of that assistant's replies, and
seven only train models, so refusing those costs no visibility at all. The llms.txt panel generates
the file from the published page tree - deterministically, with no model call and no external
service, so the same site produces the same file every time, and pages a visitor cannot read or
that are marked noindex are left out.
Sitemap vs reality resolves every sitemap.xml entry back to a node instead of fetching it, so a site
of any size costs no requests to check: pages the map never mentions, entries resolving to nothing,
dates that contradict the content, pages advertised while their own markup says noindex. Internal
links reads the link graph from the rendered HTML of every page the scan already fetched, so a menu
built from the page tree, a listing, a rich text link and a configured button all count alike, with
navigation and content links counted apart - being in a menu that lists everything is not the same
as somebody choosing to link to you. Addresses reports every address a page answers on. Structured
data derives schema.org from the content type rather than inferring it from the words on a page.
Languages shows coverage and score per language side by side, so a strong language cannot average
out a weak one. Freshness shows when the site was last touched, by content type and section, and
every published page oldest first.
An optional written report asks a model to read those measurements and say what they add up to:
where the site stands, a compliance status per area, what to fix first with who can fix it and how
much effort, quick wins, and a now/next/later roadmap, exportable as Markdown or JSON. Anthropic,
OpenAI and DeepSeek are supported. The provider receives a digest of the measurements - scores,
failing check ids, page paths and titles, counts - never page bodies and never the key, which is
configured server-side and never reaches the browser. With no provider configured the tab does not
exist and nothing leaves the platform.
Generating llms.txt and setting crawler rules are the only two things this module writes. Both show
a highlighted line diff against what is stored and need a second confirming click, and what gets
written is exactly the text on screen, so hand edits made before applying survive. Structured data
is shown as a snippet for someone to place; it is never injected into a page.
The dashboard and the drawer meet WCAG 2.2 AAA on contrast, carry real headings and announce a
running scan to a screen reader. The charts are plain HTML and CSS in Moonstone's own colours - no
chart library - and carry their numbers as text inside the list and table structures around them.
The interface ships in English and French.
The dashboard requires the publish permission on the site, and the endpoints behind it require the
same one rather than trusting the screen to hide itself. The page drawer asks less: it opens for
anyone who can read that page in the editing workspace. A scheduled scan runs as the account that
saved it and re-checks that account's permission on every run, so revoking the permission stops the
schedule rather than merely hiding the screen.
Requires Jahia 8.2+, with the jcontent, robots and llms modules present. Enable the module on each
site where it should appear.
Captures d'écran
Comment installer
1. Install the prerequisites - GEO Readiness declares jcontent, robots and llms as module
dependencies. jcontent hosts the interface; robots and llms own the node types the site-files
editors write to. Jahia holds the module in "installed" rather than starting it until all three
are there, so install robots and llms from the Store first if your platform does not have them.
2. Install the module - from the Jahia Store directly, or download geo-readiness-x.y.z.jar from the
GitHub releases and upload it in Administration > Server > Modules and Extensions > Modules.
3. Enable it on your site(s) - in Administration > Server > Modules, select GEO Readiness and enable
it on each site to check (or from the site's own module management panel). Neither entry point
appears on sites where the module is not enabled.
4. Use it - open any page in jContent and use the GEO readiness action for the per-page drawer. For
the whole site, go to Additional > SEO > GEO readiness, then either run a scan from the Site
score panel or set a schedule there.
Requirements: Jahia 8.2 or later, plus the jcontent, robots and llms modules. No configuration is
needed to start. The dashboard requires the publish permission on the site; the page drawer needs
only read access to the page in the editing workspace. No external service is called unless you
explicitly configure an AI provider for the optional written report.
FAQ
The module is installed but never starts.
It waits for its dependencies. jcontent, robots and llms must all be started first - Jahia holds
the module back rather than starting it and failing at the first write. Install robots and llms
from the Store, then GEO Readiness starts on its own.
I installed the module but I don't see the GEO readiness action or the dashboard.
Both entry points only appear on sites where the module is enabled (Administration > Modules >
enable on site). The dashboard additionally requires the publish permission on that site, and the
endpoints behind it check the same permission rather than trusting the screen to hide itself - an
editor without it gets no dashboard and no robots.txt or llms.txt editor.
The report says a page is blocked, but my robots.txt allows it. Is that a bug?
No, that is the finding. Something between the crawler and Jahia is refusing the request, most
often a firewall or CDN rule that nobody remembers adding. The module also deliberately fetches a
page even when robots.txt disallows it, because knowing that a disallowed page is nonetheless
reachable is equally a finding.
It is reporting pages and a robots.txt that are not mine.
Set PUBLIC_BASE_URL. The address a check fetches comes from that setting, or from the site's own
server name when it is blank. A site that declares no server name, or names localhost, falls back
to http://localhost:8080 - on a box serving one site that is usually right, but on a box serving
several it is the default site, so the check reports another site's pages as if they were yours,
quietly, because the fetch succeeds. On a multi-site server, and on most Docker installs where the
server name is not resolvable from inside the container, this setting is required rather than
optional. It lives in digital-factory-data/karaf/etc/org.jahia.se.modules.georeadiness.cfg and
applies immediately, with no redeploy.
Does any data leave my platform?
Only the module's own fetches of your site. There is no telemetry and no external vendor. The one
exception is the optional written report: if an administrator configures a provider, a digest of
the measurements - scores, failing check ids, page paths and titles, counts - is sent to it. Page
bodies are never sent, and the API key never reaches the browser. Leave AI_PROVIDER blank and the
tab does not exist.
Why not just look at the page in the editor?
Because the editor's browser is authenticated, runs JavaScript and is never challenged by the
firewall, and a crawler is none of those. A page whose content only appears after JavaScript runs
looks perfect in the editor and arrives empty at a crawler. Every check here is answered
server-side, on the initial HTML, with no cookies and no session.
Why is "disallowed in robots.txt" not counted as a failure?
Because refusing a crawler is a legitimate decision, and a tool that scores it as a defect is
telling you to reverse a choice you made on purpose. What is counted is a disagreement between the
policy and the server, because then one of the two is wrong and somebody owns the fix.
Will it change my robots.txt or llms.txt?
Only when you ask, and never unseen. Both editors show a highlighted line diff against what is
stored and need a second confirming click, and what gets written is exactly the text on screen, so
hand edits made before applying survive. The robots.txt merge is line-based rather than a full
rewrite: it does not reorder, deduplicate or tidy, so a hand-written file comes back recognisable.
Everything else the module does is read-only - structured data is shown as a snippet for someone to
place, never injected into a page.
How do I check the whole site regularly?
The Site score panel holds the schedule: a cron expression built from dropdowns, an optional scope
and an enable toggle. A running scan appears in the administration job list. A scan is capped at
2000 pages per run and is synchronous when started from the button, so a large site should use the
schedule rather than the button.
My site is multilingual.
A scan covers one language per run, so set one schedule per language. Coverage and score are then
shown per language side by side, and a language nobody has scanned reports as not measured, never
as zero. The link graph and the freshness picture also judge only the language that was scanned.
Do I need an AI provider?
No. Everything except the Report tab is measured, and works with no provider and no key. The report
is the one place a model is asked for judgement instead of measurement, and it is off until an
administrator sets AI_PROVIDER, AI_MODEL and AI_API_KEY.
Does the score certify that my site is AI-ready?
No. It is a count of eighteen observed checks, each showing the fact behind its verdict, so you can
disagree with a specific line. It measures what a crawler receives from your server - not whether
any assistant chooses to cite you.
I am upgrading from 1.2.0 or earlier. Will I lose my settings?
No. The groupId moved to org.jahia.community in 1.3.1, but the Java package, the OSGi configuration
PID and the bundle name are unchanged, so an existing install upgrades in place and keeps its
configuration file.
Why is there no llms-full.txt?
The community llms module declares one property and one route, so the full variant cannot exist on
this stack. The report calls the file absent, which is the closest it can say.
MIT License
Copyright (c) 2026 Jahia Solutions Group SA
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Dépendances
Modules dépendants
Aucun module n'en dépend.