Indexing, SEO and Agents
What each discovery file and tag does, and how to register the site with Google and Bing
Where the site's search data lives
Google Search Console and Bing Webmaster Tools hold the queries, clicks, backlinks and scan findings for terrain-viewer.iconem.com (owner access). Both finished their first processing on 2026-10-06. An agent can read them through their APIs. Bing: an API key from Settings → API access in Webmaster Tools; ours is BING_WEBMASTER_API_KEY in the repo's .env (the main checkout's, copied into each worktree; never committed), and GetQueryStats answers with it. Google: a service account (project mineral-math, the Search Console API enabled, the account a full user of the property) whose JSON key sits outside every repo, its path in .env as GOOGLE_SEARCH_CONSOLE_KEY_FILE; node scripts/search-console.mjs --days 28 --json .cache/sc.json signs the OAuth JWT itself (no dependency) and prints queries, pages, countries, devices and the sitemap status.
The app is a single-page app: without JavaScript its page is nearly empty. These pieces make it findable by search engines and usable by AI assistants.
What does what
robots.txt (public/robots.txt) allows all crawlers and points them to the sitemap.
sitemap.xml lists the app and every docs page, so crawlers find pages without following links. Generated by scripts/build-seo.mjs on every pnpm build, from the docs frontmatter.
Canonical URL. Every shared link (/?lat=…&zoom=…) is a different address for the same page. The <link rel="canonical"> in index.html tells search engines to rank them all as the root, and each docs page declares its own address. Links keep working; it is only a hint to crawlers.
Shell text and schema.org markup. index.html carries a description, links to key docs pages and a WebApplication JSON-LD block, for crawlers and fetchers that do not run JavaScript. React replaces the text on first render.
llms.txt at the site root is for AI assistants that read the web, ChatGPT search among them: what the app is, how to build a link to a place and mode, and every docs page. Generated with the sitemap. The docs also serve their own /docs/llms.txt and /docs/llms-full.txt.
The agent skill (skills/terrain-viewer/SKILL.md) does the same for agents that load skills, with step-by-step instructions. See Use with AI Assistants.
Search consoles. Google Search Console and Bing Webmaster Tools are where the owner proves the site is theirs, submits the sitemap and sees what gets indexed. ChatGPT search draws largely on Bing's index, so Bing matters as much as Google here.
Umami analytics
The app and the docs report to one Umami Cloud website, pageviews on the path only (no query string, no hash) and one custom event per intentional action (lib/analytics.ts). The website id is VITE_UMAMI_WEBSITE_ID in .env, not in the source: without it the tracker is not loaded, and the tracker only reports from the real hostnames, so a clone run elsewhere stays silent. Every load carries a tag: web, embed (inside the HeritageWatch or Anchise toolbox) or desktop. To keep your own sessions apart, open each site once with ?umamiTag=owner appended to its URL: the tag is stored in that browser and its loads then carry owner instead, which the dashboard filters out with Filter, Tag. Storage is per origin and per browser profile, so do it on terrain-viewer.iconem.com and on historical-satellite.iconem.com, in each browser you use; localhost never reports. ?umamiTag= with nothing after it clears the tag. The source-add event says whether a source came from the library or a pasted URL (origin). An export (Settings, Export) is read by scripts/umami-export-analyze.mjs, which lists the top sessions of given days.
Google Search Console
- Open search.google.com/search-console and add a property: URL prefix
https://terrain-viewer.iconem.com/, or Domainiconem.comfor every subdomain. - Verify: for URL prefix, put the
google….htmlfile it gives inpublic/and deploy (or add its meta tag toindex.html); for Domain, add the DNS TXT record. - Sitemaps: submit
https://terrain-viewer.iconem.com/sitemap.xml. - URL inspection: request indexing of
/and/docs/.
First read, 2026-10-09 (Sept 9 to Oct 7)
Google: 70 clicks on 1,035 impressions, average position 7.6. The home page takes 50 clicks (129 impressions, 39 % CTR, position 3); the sun-position estimator 14 clicks on 159 impressions (position 11.6); every docs page under 2 clicks. By query: "terrain viewer" 30 clicks on 43 impressions at position 1.6, "analemma calculator" 8 on 35 at 6.5, then single impressions on long-tail terms (heightmap viewer, esri imagery wayback, ndsm, lerc, mapterhorn). Two MapTiler Wayback URL queries gave 23 impressions and no click. Desktop 852 impressions, mobile 172 with twice the CTR. Countries: the USA 344 impressions but 5 clicks; Canada, Argentina, Turkey, Spain, the UK and the Netherlands 4 to 7 clicks each. The sitemap was last read on 2026-10-08 with no error. Reading: the site ranks for its own name and for the sun tool; the feature pages get impressions at positions 5 to 8 and almost no clicks, so their titles and descriptions are what to work on next.
Bing (node scripts/bing-webmaster.mjs, the same day): both sites verified; 5 clicks on 24 impressions over Oct 2 to 6; 105 pages crawled, 88 in the index, no open crawl issue; the home page was discovered on 2025-11-26 and last crawled on 2026-10-09 with 11 anchors pointing at it. The query, page and inbound-link endpoints answer empty so far: Bing fills them once there is enough traffic.
Bing Webmaster Tools
- Open bing.com/webmasters and sign in.
- Import from Google Search Console copies the verified site and its sitemap. Otherwise add the site and verify with
BingSiteAuth.xmlinpublic/, a meta tag, or DNS. - Check that
sitemap.xmlis listed under Sitemaps.
IndexNow
A free ping that tells Bing (and other participating engines) a page changed, so it is recrawled within minutes instead of days. Generate a key in Bing Webmaster Tools under IndexNow or at bing.com/indexnow, serve it as public/<key>.txt, and have the deploy call https://api.indexnow.org/indexnow?url=<page>&key=<key>. Not set up yet.
Fumadocs integration
How this documentation site uses Fumadocs — the visual editor (Studio), the added components and generators, and the Next base-path fixes
State Reference
Every URL parameter the app reads, generated from the source at build time — state parameters mirrored by nuqs, instruction parameters read once on load, and the settings kept in localStorage