SEO: robots, sitemap, canonical, link previews and structured data #48

Closed
opened 2026-09-02 01:19:06 +00:00 by paulhitt · 1 comment
paulhitt commented 2026-09-02 01:19:06 +00:00 (Migrated from gitlab.com)

Ask: make the public pages findable.

What is actually there today (audited 2026-09-01)

layout.leaf has charset, viewport, <title>, description, and three Open Graph
tags — og:title, og:description, og:type. That is the whole of it.

Missing, all of it:

State
robots.txt 404
sitemap.xml 404
<link rel="canonical"> absent
og:image absent
og:url absent
twitter:card absent
application/ld+json absent
hreflang absent

So every link shared to Signal, WhatsApp, Slack or anywhere else renders with no preview
image
, and search engines are given no sitemap, no canonical, and no structured data.

Worth doing, roughly in order of return

  1. robots.txt and sitemap.xml. The cheapest possible win and currently a 404. The
    sitemap should be generated from the same route list the pages come from, not hand-kept
    — a hand-kept one is wrong within a month.
  2. og:image. Link previews are how this actually spreads: somebody shares
    flamenet.io in a group chat and it renders as a bare URL. A single well-made card
    would change every share.
  3. canonical and og:url. The same content is reachable on more than one host —
    relay.flamenet.io, flamenetmessenger.com, and every self-hoster's domain. Without a
    canonical, those compete with each other.
  4. Structured data (SoftwareApplication, Organization, FAQPage for the /get
    questions). /comparison and /get are the pages most likely to earn a rich result.
  5. Titles and descriptions per page. Check they are distinct and written for a person
    searching, not lifted from the <h1>.
  6. hreflang, once Spanish exists — see #47. Doing SEO and localization in the wrong
    order means redoing part of it.

Two things to be careful about

⚠️ Do not let SEO pull the copy toward keyword filler. The pages are plainly written and
avoid jargon on purpose — that is a product decision recorded in several places, and
"optimising" a sentence into search bait would undo it. Better titles and real structured
data beat stuffed prose.

⚠️ Do not index what should not be indexed. /downloads/* and any self-hoster's copy
of these pages should not compete with the canonical site, and robots.txt is where that
gets decided rather than discovered.

ℹ️ Related: #47 (localization — Spanish first, and six of the seven countries sign-up is
open in are Spanish-speaking), #44 (features page shape).

**Ask:** make the public pages findable. ## What is actually there today (audited 2026-09-01) `layout.leaf` has `charset`, `viewport`, `<title>`, `description`, and three Open Graph tags — `og:title`, `og:description`, `og:type`. That is the whole of it. **Missing, all of it:** | | State | |---|---| | `robots.txt` | **404** | | `sitemap.xml` | **404** | | `<link rel="canonical">` | absent | | `og:image` | absent | | `og:url` | absent | | `twitter:card` | absent | | `application/ld+json` | absent | | `hreflang` | absent | So every link shared to Signal, WhatsApp, Slack or anywhere else renders with **no preview image**, and search engines are given no sitemap, no canonical, and no structured data. ## Worth doing, roughly in order of return 1. **`robots.txt` and `sitemap.xml`.** The cheapest possible win and currently a 404. The sitemap should be generated from the same route list the pages come from, not hand-kept — a hand-kept one is wrong within a month. 2. **`og:image`.** Link previews are how this actually spreads: somebody shares `flamenet.io` in a group chat and it renders as a bare URL. A single well-made card would change every share. 3. **`canonical` and `og:url`.** The same content is reachable on more than one host — `relay.flamenet.io`, `flamenetmessenger.com`, and every self-hoster's domain. Without a canonical, those compete with each other. 4. **Structured data** (`SoftwareApplication`, `Organization`, `FAQPage` for the `/get` questions). `/comparison` and `/get` are the pages most likely to earn a rich result. 5. **Titles and descriptions per page.** Check they are distinct and written for a person searching, not lifted from the `<h1>`. 6. **`hreflang`**, once Spanish exists — see #47. Doing SEO and localization in the wrong order means redoing part of it. ## Two things to be careful about ⚠️ **Do not let SEO pull the copy toward keyword filler.** The pages are plainly written and avoid jargon on purpose — that is a product decision recorded in several places, and "optimising" a sentence into search bait would undo it. Better titles and real structured data beat stuffed prose. ⚠️ **Do not index what should not be indexed.** `/downloads/*` and any self-hoster's copy of these pages should not compete with the canonical site, and `robots.txt` is where that gets decided rather than discovered. ℹ️ Related: #47 (localization — Spanish first, and six of the seven countries sign-up is open in are Spanish-speaking), #44 (features page shape).
paulhitt commented 2026-09-08 15:02:28 +00:00 (Migrated from gitlab.com)

Done. The audit table from the description, re-measured against production 2026-09-08:

State then State now
robots.txt 404 200, names the sitemap
sitemap.xml 404 200, 27 urls, generated from the pages table
<link rel="canonical"> absent present, built from the requesting host
og:image absent present, absolute, from #(origin)
og:url absent present
twitter:card absent present
application/ld+json absent present (WebSite + Organization)
hreflang absent present where a translation exists

Shipped across !83 (robots/sitemap/canonical/og), !85 (structured data), !86 + !87 (three routes were rendering href="" because their contexts never set the chrome, and ReleasesContext encodes by hand and dropped it), and !91 (Spanish + hreflang).

hreflang reciprocates properly and only appears where it can:

/get      → en /get · es /es/get · x-default /get
/about    → none (no translation, so nothing to advertise)

⚠️ /es/get is live and reachable but deliberately not linked from the nav — it wants a native-speaker read first, since the copy is legal-adjacent in places and an overclaim in Spanish is the same FTC problem in another language. Remaining page translations are tracked in #47, not here.

Two things the tests now hold in place: every render call site must set the canonical, and a hand-written encoder must not drop it. Both were checked by reintroducing the bug.

Done. The audit table from the description, re-measured against production 2026-09-08: | | State then | State now | |---|---|---| | `robots.txt` | **404** | 200, names the sitemap | | `sitemap.xml` | **404** | 200, 27 urls, generated from the `pages` table | | `<link rel="canonical">` | absent | present, built from the requesting host | | `og:image` | absent | present, absolute, from `#(origin)` | | `og:url` | absent | present | | `twitter:card` | absent | present | | `application/ld+json` | absent | present (WebSite + Organization) | | `hreflang` | absent | present where a translation exists | Shipped across !83 (robots/sitemap/canonical/og), !85 (structured data), !86 + !87 (three routes were rendering `href=""` because their contexts never set the chrome, and `ReleasesContext` encodes by hand and dropped it), and !91 (Spanish + hreflang). `hreflang` reciprocates properly and only appears where it can: ``` /get → en /get · es /es/get · x-default /get /about → none (no translation, so nothing to advertise) ``` ⚠️ `/es/get` is live and reachable but **deliberately not linked from the nav** — it wants a native-speaker read first, since the copy is legal-adjacent in places and an overclaim in Spanish is the same FTC problem in another language. Remaining page translations are tracked in #47, not here. Two things the tests now hold in place: every render call site must set the canonical, and a hand-written encoder must not drop it. Both were checked by reintroducing the bug.
paulhitt (Migrated from gitlab.com) closed this issue 2026-09-08 15:02:29 +00:00
Sign in to join this conversation.