Skip to content

Troubleshooting

Indexed by symptom, because you know the symptom and not the cause. Several of these fail in ways that look like success, which is why they are worth reading before you need them.

CauseFix
GEOFFY_SITE_KEY is not set where the page runsNothing is requested, and the server log shows @geoffy/headless: GEOFFY_SITE_KEY is not set once. Set it for that environment and restart
A Shopify store’s own site is not verified yetEvery artifact endpoint 404s until it passes. A site with no commerce platform is served before the check. Prove you own your domain
Nothing is published for that handleThe endpoints serve published bundles only. Publish in the dashboard first
Wrong handleWith no commerce platform it is the segment your URL pattern captured, not your slug. The product page
canonicalUrl does not matchThe component renders nothing and leaves a data-geoffy-skipped marker. Look for it in view-source
Another page has the same handle, such as the same slug in two languagesBefore 0.3.5 only the page published last renders, and the other shows a data-geoffy-skipped marker with canonical-mismatch. Upgrade to 0.3.5 and pass this page’s own canonicalUrl. Several languages on one site
The component is under a "use client" boundaryIt is an async server component. Below that boundary it never runs on the server

The widget renders, but there is no structured data

Section titled “The widget renders, but there is no structured data”

Correct when your site owns its structured data: the Structured data setting is Never, or the page already carries its own node of the same type. Geoffy then serves the widget alone. If you expected structured data, check that setting in Geoffy, and check the page for a node of the same type that your site already emits.

The widget is gone after you set Structured data to Never

Section titled “The widget is gone after you set Structured data to Never”

Your @geoffy/headless is older than 0.3.4, which renders nothing when Geoffy sends no structured data. Upgrade the package.

Something is stripping the <style> element that travels inside widgetHtml. A sanitiser, most often. Do not sanitise the widget HTML.

A catch-all segment such as app/[lang] is answering it. You used a next.config.js rewrite that is not in beforeFiles, or the route file is not where you think it is.

My robots.txt is stale after I fixed something

Section titled “My robots.txt is stale after I fixed something”

The helpers cache their fetch of Geoffy for an hour by default. Mount the revalidate route, or pass revalidateSeconds: 10 while integrating. In dev, also clear .next/dev/cache, not .next/cache.

The mount is reported as not done, but the URL works in my browser

Section titled “The mount is reported as not done, but the URL works in my browser”

A 200 is not the check. Three things must be true, and a catch-all route answering with your home page satisfies none of them while looking fine. Checking it worked has the curl and the three conditions.

wrong_site specifically means our marker came back carrying a different site key: your GEOFFY_SITE_KEY belongs to another Geoffy site.

Products stay pending forever, and everything looks right locally

Section titled “Products stay pending forever, and everything looks right locally”

Expected until you deploy. Geoffy fetches your live page at its canonical URL, not your machine. What local cannot do.

A missing generateMetadata on your product page means all of them inherit the layout’s metadata and claim to be your home page. One missing export, one broken catalogue. Prove you own your domain.

Products index slowly, and nothing is wrong

Section titled “Products index slowly, and nothing is wrong”

Probably the IndexNow key. The namespace authorises only what is under /apps/geoffy/, so product-page pings are discarded unless you also serve public/{key}.txt. Nothing errors when you skip it. The IndexNow key.

The path is fixed at /api/geoffy/revalidate. Geoffy derives it from your domain rather than storing one you typed. A route file anywhere else is never called, and nothing reports it. How updates arrive.

The first page load after a publish still shows the old content

Section titled “The first page load after a publish still shows the old content”

The revalidate route fired (the second load is correct), but something passed a cache-life profile that permits stale content. Pass revalidateTag bare to createGeoffyRevalidateRoute and delete any wrapper around it: the package supplies { expire: 0 } itself, while "max" serves the pre-publish page for up to a year while the refresh runs. How updates arrive.

CauseFix
No secretReports are signed with GEOFFY_REVALIDATE_SECRET, and without it nothing is sent. Set it, or pass secret
The middleware file is not picked upNext 16 reads proxy.ts with export const proxy. Earlier versions read middleware.ts with export const middleware
Your matcher skips your product pagesA page the matcher does not cover never reaches the middleware
Nothing qualifiedOnly AI crawlers and visitors from an AI assistant are reported. Your own browser visits are not, by design
The package is older than 0.3.1Upgrade. 0.3.0 sends one visit per call, so a crawler sweep past 60 pages a minute is mostly dropped

AI visit tracking has the full setup.

AI visits show localhost, or crawler visits are never confirmed

Section titled “AI visits show localhost, or crawler visits are never confirmed”

Both are a self-hosted site behind a reverse proxy.

CauseFix
Visits are reported on localhost or an internal addressUpgrade to 0.3.2 or later, and have your proxy forward Host, X-Forwarded-Host and X-Forwarded-Proto
Crawler visits arrive but none is confirmedNo trusted visitor address reaches the middleware. Have your proxy overwrite X-Real-IP and pass clientIp: (request) => request.headers.get("x-real-ip")

Self-hosted (not Vercel) has the proxy settings.

Each .md twin under /apps/geoffy/ names its HTML page in a Link: <https://…>; rel="canonical" header. If the check finds no such line:

CauseFix
@geoffy/headless is older than 0.3.3Upgrade. Earlier versions do not pass the canonical Link on
A CDN or a middleware in front of the route removes itLet the Link and X-Robots-Tag headers through on /apps/geoffy/*

Check what your own site is actually serving:

Terminal window
curl -si https://yourdomain.com/apps/geoffy/sitemap.xml | head -20
curl -s https://yourdomain.com/your/product/page | grep -c 'data-geoffy'
curl -s https://yourdomain.com/llms.txt | head -20

Then compare against the source. Your site’s settings in Geoffy show the direct URL for each of your published surfaces; fetching one bypasses every cache of yours at once. If Geoffy and your site disagree, the problem is on your side of the fetch.