Checking it worked
Geoffy does not take your word for it. After you publish, we fetch your live product page and look for our markup in the server-rendered HTML. A product stays pending until we find it, and your dashboard count only ever shows products confirmed on your real site.
If a product stays pending
| Reason | What it means | What to fix |
|---|---|---|
code_not_added | We fetched the page and our markup was not in it | The component is not on the page, or it is rendering on the client |
stale_version | Our markup is there, but it is an older copy | Nothing. Your cache clears itself within the revalidate window (one hour by default) |
canonical_broken | The page does not name itself as canonical | See "Before you start": most often a missing per-page metadata export |
You can check the same thing yourself:
curl -s https://yourdomain.com/en/products/your-handle | grep -c 'data-geoffy'A number greater than zero means it is in the server-rendered HTML, which is what matters. The same command works against your dev server while you are building; swap the host.
And the namespace
Geoffy checks the /apps/geoffy mount the same way: by fetching it, not by
trusting the setting. Check it yourself with:
curl -si https://yourdomain.com/apps/geoffy/sitemap.xml | head -20 A 200 is not the check. That is the one thing worth knowing
here, because it is what makes a broken mount look fine: a catch-all route in your app
answers every path (including this one) with your home page and a perfectly
healthy 200.
So Geoffy checks three things instead, and you can check the same three by eye:
| Check | Why |
|---|---|
| The response is genuinely proxied from Geoffy | Not your home page, not a CDN interstitial. If what comes back looks like your own site, a catch-all route is winning and the namespace route is not being reached |
| It is your site's content |
A GEOFFY_SITE_KEY copied from another project would otherwise confirm
a mount that is serving someone else's catalogue under your domain
|
content-type is application/xml or text/xml | A sitemap served as HTML is one a crawler will not parse |
If the mount is not confirmed, the dashboard says which of these it is:
| Reason | What it means |
|---|---|
not_mounted | The path answered, but not with our bytes. Usually a catch-all route serving your home page, or the route file is not deployed yet |
wrong_site |
Our marker came back carrying a different site key. Your
GEOFFY_SITE_KEY belongs to another Geoffy site
|
unreachable | We could not fetch it at all. This is not the same as "not mounted" and is not recorded as a failure. We try again |
While the mount is unconfirmed, your llms.txt simply says less: it omits
the product twins and the Geoffy sitemap rather than pointing a crawler at URLs that
answer with your home page.
What a local run cannot do
Geoffy confirms your integration by fetching your live product page at
its canonical URL (the public one, not your machine). So until the integration is
deployed, products stay pending with code_not_added no matter how correct
everything looks locally.
That is the check working as intended: it reports what your visitors and the crawlers
actually get. Prove it locally with the curl above, ship, and let the
confirmation follow.
Next.js specifics
Section titled “Next.js specifics”code_not_added on a page you are sure is correct is almost always one of two things:
- The component is inside a client component.
<GeoffyProduct>is an async server component. Rendering it below a"use client"boundary means it never runs on the server, and the markup exists only after hydration, which is exactly what a crawler does not see. canonicalUrldoes not match. The component renders nothing on a page that is not the one Geoffy published against, leaving an inertdata-geoffy-skippedmarker instead. If yourcurlfinds zerodata-geoffymatches, look for that marker in view-source: it means the component ran and deliberately declined.