BLUF. Search is not a trick. Google has to find, read, and trust the live host, then see a page that actually answers what a customer typed. New domains also need links, brand searches, and engagement — on-page work alone underperforms for months. Helpers do the on-site work. Humans submit the sitemap, (for local) fill the Maps listing, and post the off-site listings. Do not ask “Node Dough or Executive Nail Suite?” — resolve the host from the task + R12.
Live: https://projects.jbnx.io/framework/seo Tracking (required on the same host): https://projects.jbnx.io/framework/tracking-doctrine Customer funnel proof: https://projects.jbnx.io/framework/monthly-funnel-proof Voice: https://projects.jbnx.io/framework/human-framework
A ship without a live /insights 200 on that hostname is still not done. SEO does not replace R13.
Copy once. After that, point at this URL. Do not re-paste the whole page.
SEO — mandatory whenever we ship or fix a public page people should find.
Spec: https://projects.jbnx.io/framework/seo
Tracking (same host): https://projects.jbnx.io/framework/tracking-doctrine
0. Resolve the host yourself. Task text + https://hi.jbnx.io R12 +
GET /api/1099/deploy-targets. Never ask SaaS vs local as a multiple choice.
Classify: saas | local | localfave-tenant | marketing.
Canonical host = the live public origin. Dead aliases (ai.fedm8.com,
scan.fedm8.com, mock.jbnx.io) must 301 there and must not appear in
<link rel=canonical>, sitemap <loc>, or JSON-LD url.
1. Technical (AI ships these):
HTTPS that browsers trust. One indexable host (apex or www 301, not both
200). robots.txt Allow: / and Sitemap: https://<host>/sitemap.xml.
sitemap.xml 200, this host only, https locs, no ops paths.
noindex: /insights /collect /go /api /admin /stack /t/ (path tenants),
plus thin pages, tag archives, parameter URLs.
Viewport. Images WebP. Core Web Vitals on the live URL:
LCP < 2.5s, INP < 200ms, CLS < 0.1 (INP replaced FID in 2024).
Title ≤60 chars, target phrase near the start. Meta description 120–160.
Unique title + description per indexable URL. Clean path, no .html junk.
Visible last-updated on articles. Answer-first opening paragraph.
2. Structure: pillar + 5–10 cluster pages per topic, tightly interlinked.
Money pages ≤3 clicks from /. Descriptive anchors. No index bloat.
3. People-first + E-E-A-T: write for the customer, then place the phrase
they type in URL / title / H1 / description. Named author or owner,
About, contact, privacy, terms. First-hand proof (license, years,
prices, outcomes). Image filenames + alt. JSON-LD required:
Organization + SoftwareApplication or LocalBusiness; FAQ, Review,
BreadcrumbList when that content is visible. NAP = Maps listing.
4. Off-site: new domains need links and brand mentions. SaaS: G2/Capterra/
Product Hunt/AlternativeTo, partner/integration pages, data-led PR.
Local: GBP first, plus Apple Maps, Bing Places, Yelp, trade directories.
Do not buy links or run a link scheme.
5. Human (one batched ask with URLs):
Search Console URL-prefix + sitemap submit + inspect priority URLs.
Bing Webmaster (ChatGPT/Copilot read Bing). IndexNow ping is extra.
Local: Google Business Profile complete; NAP match; reviews + replies.
Do not add Google Analytics / Clarity as the number we report.
6. Penalties to refuse: scaled content abuse (mass AI pages), link schemes,
site reputation abuse, expired-domain abuse. Keyword stuffing is still
a fail; those four are the 2024+ spam policies.
7. Measure: weekly Search Console (impressions before clicks; positions
20–40 rising is the early signal). /insights for on-site people.
New domain: 3–6 months before meaningful traffic. On-page without
links will sit. Done = verify block in /framework/seo on the live host.
That is the instruction. If they ignore it, the live URL is the argument.
The source draft asked “Node Dough, Cipherdeck, or Executive Nail Suite?” That is a human question. Helpers already have the map.
| Input | What you do |
|---|---|
| Chat names a host or brand | Use that host. Confirm against R12. |
| Chat names a slug | GET /api/1099/deploy-targets + R12 row → prod URL. |
| Chat says “this site” in a tenant repo | The Host you are editing (src/lib/tenants.ts on LocalFave). |
| Still ambiguous after boot + R12 | One batched question listing the matching hosts, not a category quiz. |
Then classify. Extra work hangs off the class; the technical bar is the same.
| Class | Examples (R12) | Extra |
|---|---|---|
saas | nodedough.com, fedm8.com, scytherdeck.com / CipherDeck | Index marketing + docs you want found. noindex app shells, auth, /admin, /quick, config, health. No Maps listing. Comparison / integration / changelog playbook below. |
local | executivenailsuite.com, Tensuite shop pages | LocalBusiness JSON-LD, NAP, GBP (Map Pack > organic), /go/call + /go/map if a public phone/address exists. |
localfave-tenant | marcobros / zensoma / vanessa *.localfave.org | New site = new portal slug + new hostname on this stack. Do not invent a repo, [App Host] service, or [Database]. JSON-LD + per-host sitemap in the Worker / src/app/sitemap.ts. Same local playbook. |
marketing | localfave.org, fedm8.net, tensuite.net, jbnx.io | Index the pitch. noindex /stack and operator pages. |
Canonical host rules (estate traps):
fedm8.com. ai.fedm8.com and scan.fedm8.com are redirect-only. A sitemap or canonical that still lists ai.fedm8.com is a defect.fedm8.net. Do not 301 the company into the app.https://<slug>.localfave.org until a client CNAME exists. Do not mix marcobros.com (old origin) into the new sitemap./t/<slug> on the hub is a preview. Disallow /t/ on tenant hosts so Google does not index the duplicate.Claim the slug for that host before you edit. One claim per PR. Public-language --done: say “search listing” / “sitemap”, never the vendor stack.
Google cannot rank a page it cannot fetch. Core Web Vitals are ranking inputs; “loads quickly” is not a target.
| Check | Pass |
|---|---|
curl -sSI https://<host>/ | 200 (or 301/302 to the canonical URL, then 200). Certificate trusted. |
http://<host>/ | 301 to https://<host>/ (or https canonical). |
www vs apex | Exactly one returns 200. The other 301s. |
| HSTS | Present on the canonical host once HTTPS is trusted (strict-transport-security). |
Do not tell Chrome users to click through an expired cert. That is a rank-zero failure (see the marcobros.com audit).
Live shapes that already pass (copy the pattern, do not invent a second):
# https://marcobros.localfave.org/robots.txt
User-agent: *
Allow: /
Disallow: /api/
Disallow: /collect
Disallow: /go/
Disallow: /insights
Sitemap: https://marcobros.localfave.org/sitemap.xml
Tenant extras: Disallow: /admin (Vanessa tracker), Disallow: /t/ (path previews), Disallow: /stack (hub). SaaS extras: /admin, auth, health, config.
Sitemap rules:
GET https://<host>/sitemap.xml → 200, Content-Type XML, not a 303 to HTML.<loc> is https:// on this host (or the one canonical host after a documented 301)./insights, /collect, /go/, /api/, /admin, /stack, noindex pages, or parameter copies.cf-worker/src/listing.js, hub ping in cf-worker/src/worker.js). That is a hint, not a substitute for Search Console submit.LocalFave code: src/app/robots.ts, src/app/sitemap.ts, Worker routes for /robots.txt and /sitemap.xml per host. A Next-only change is not live while the Worker is the origin — edit the Worker assets too.
New sites die from index bloat as often as from missing pages.
| Do | Do not index |
|---|---|
| Homepage, money pages, pillar, each cluster page | Thin stubs, tag/category archives, faceted/parameter URLs (?utm_ landing copies, sort/filter) |
| Unique titles on those URLs | Paginated duplicates without rel=prev/next or a canonical to the clean URL |
noindex,follow on thank-you / account / search-result HTML | A second 200 host (www + apex, http + https, dead alias) |
After ship: human URL Inspection → Request indexing on / and each money page (cap: a handful, not the whole sitemap). IndexNow / Bing ping from the Worker is allowed and already exists on LocalFave — keep it. Do not spam the inspect button.
Vague “be fast” is replaced by field/lab thresholds. INP replaced FID in March 2024.
| Metric | Pass | Fail if |
|---|---|---|
| LCP | < 2.5s | Hero image uncompressed, no dimensions, late preconnect |
| INP | < 200ms | Huge JS on first tap, layout thrash on click-to-call |
| CLS | < 0.1 | Images/fonts without size, injected banners |
| Viewport | <meta name="viewport" on every indexable HTML page | 800px Dreamweaver cage |
| Images we own | WebP (or AVIF), width/height, descriptive alt | Insert Logo Here, hotlinked dying origins |
| Fonts | display=swap | Display font blocking first paint |
Verify (one pass, not a loop):
curl -sS -o /dev/null -w '%{size_download}' https://<host>/ — flag uncompressed megabyte homepages.| Path | robots | HTML |
|---|---|---|
/insights | Disallow | noindex,nofollow |
/collect /go/ /api/ | Disallow | not a document |
/admin /stack | Disallow | noindex |
| Health, probes, config | Disallow | noindex or 404 |
A 200 insights page that is indexable is a leak of operator copy, not a ranking win.
| Field | Rule | Verify | |
|---|---|---|---|
<title> | ≤60 characters. Primary phrase + brand. Unique per URL. | `curl -sS https://<host><path> \ | grep -i '<title'` |
| Meta description | 120–160 characters. One sentence a human would click. Unique per URL. | grep name="description" | |
| Canonical | <link rel="canonical" href="https://<canonical-host><path>"> matching the sitemap <loc>. | grep canonical | |
| H1 | One H1, matches the search intent of that URL. Homepage is not allowed to skip it. | ||
| Path | Lowercase, hyphens, no .html, no _Us Dreamweaver names. Keyword in the slug when it is a real service page (/irrigation, not /page2). | sitemap <loc> | |
| Last updated | Visible date on articles / service pages we revise (<time datetime>). Helps people and AI snapshots. |
Keyword stuffing in the title is a fail. “Irrigation Silver Spring” in the title of an irrigation page is the job.
Open Graph / Twitter cards: same title + description + one real image. They do not replace the HTML title.
Do not plan “one keyword, one isolated page.” Pick a topic the business can own, then ship:
/irrigation, /budgeting, /government-vendor-list)./irrigation/backflow-testing, /irrigation/winterize). Each links up to the pillar and across to siblings with descriptive anchors.Money pages (book, call, signup, pricing) stay ≤3 clicks from / even inside a cluster.
Hub vs tenant: localfave.org ranks for us. marcobros.localfave.org ranks for Marco. Never cross-canonical them.
/go/call and /go/map (R13). SEO and tracking share those wrappers.BreadcrumbList JSON-LD on any URL deeper than /.Google rewards pages that look like a person who does the work wrote them. Load https://projects.jbnx.io/framework/human-framework before drafting public copy.
Experience, Expertise, Authoritativeness, Trust (E-E-A-T) is how that is judged. Anonymous new domains are held back longer. On every indexable site ship:
| Signal | Where |
|---|---|
| Named owner or author with a real role | Byline, About, JSON-LD author / founder |
| Credentials that are true | License (MHIC), years, “who answers the phone” |
| About page | Who, where, what you will not do |
| Contact | Public phone or a form. Match NAP. |
| Privacy + terms | Linked in the footer. Needed for ads and for trust. |
Vanessa has no public phone — that is correct. Do not invent a byline or a license.
For the host, list 3–8 phrases a customer would type. Evidence, not a brainstorm:
name / areaServed).marcobros-search-listing, zensoma-search-listing, Insights “search” on that host.massage Cherry Hill, tree-based budget, not “unlock synergy”).Those phrases become the cluster map, not ten near-duplicate pages. Put the primary phrase in: path, title, H1, first paragraph, meta description. Secondary phrases in H2s and internal anchors. If the sentence only exists to hold the keyword, delete it.
The first paragraph on an indexable page states the answer in plain prose: who, what, where, what it costs or what happens next. Then the proof. This is the block AI Overviews, AI Mode, ChatGPT, and Perplexity quote. Do not open with a brand manifesto.
| Class | Put on the page |
|---|---|
| Local | License number, years, service area, prices if they are real, who answers the phone. |
| SaaS | What the user can do in one sitting, what it will not do, a true empty state. |
Do not invent reviews, star ratings, or “over 10 years” that contradicts the founded year. The marcobros.com audit failed on exactly that class of copy.
silver-spring-irrigation-backflow.webp, not IMG_4032.jpg.alt: what is in the photo, in words a screen reader and a crawler can use. Empty alt only for pure decoration.http://marcobros.com/...) from the new host.Schema.org JSON-LD is not optional. It enables rich results and is how AI engines parse the page. Only mark up what is visible. Fake Review / AggregateRating is a spam policy issue.
| Type | When |
|---|---|
Organization | Every public host (legal name, url = canonical, logo) |
LocalBusiness (or subtype) | local / localfave-tenant. telephone E.164 only if public. address + areaServed. Omit phone for Zen Soma / Vanessa. |
SoftwareApplication | saas marketing homepage |
WebSite + SearchAction | Only if a public site-search exists |
FAQPage | FAQs visible on that URL |
Review / AggregateRating | Real, named, on-page reviews — never sample stars |
BreadcrumbList | Any URL with a breadcrumb |
Article | Guides / changelog posts, with dateModified |
One graph per page. @id / url are the canonical host. Verify: view-source contains application/ld+json. Optional human: https://search.google.com/test/rich-results
On-page SEO on a new domain without links will underperform for months. Rank needs other sites naming this host.
Helpers prepare the on-site NAP, listing copy, and partner pages. Humans submit the profiles. Do not buy links, swap PBNs, or stuff footer links onto client sites.
| Class | Primary listings | Link-earning pages we can ship |
|---|---|---|
saas | G2, Capterra, Product Hunt, AlternativeTo, relevant “best of” lists | Comparison (X vs Y, X alternatives, best [category] tools), integration/partner pages, indexed docs, public changelog, one free tool that other sites cite |
local / tenant | Google Business Profile first (Map Pack). Then Apple Maps, Bing Places, Yelp, chamber / trade boards | One URL per service; one city page per city you actually serve; photos NAP-identical to GBP |
marketing | Same as the product it pitches | Original data, a number someone else will quote |
Digital PR = original data or a true outcome, then a page others can link. Not a “10 best” listicle we wrote about ourselves.
Brand mentions without a link still help when they match the NAP / product name. Keep the name string stable.
Google uses click and engagement data (Navboost; 2024 API leak and DOJ testimony). Branded search volume (“nodedough”, “marco bros irrigation”) is a trust signal we cannot fake in the title tag.
Build audience off Google, then they search the name:
Measure engagement we own on /insights (real people, R13). Do not install GA or Clarity to “see Navboost.” Search Console CTR is the Google-side read (human, weekly).
A page that ranks and gets skipped will fall. Titles and descriptions earn the click; the answer-first paragraph + speed earn the stay.
Traffic now also comes from Google AI Overviews / AI Mode, ChatGPT, Copilot, and Perplexity. Those systems quote clear answers on crawlable HTML, not a SPA shell with no first paint.
Ship on every indexable URL:
Bing Webmaster is required, not optional. ChatGPT and Copilot use Bing’s index. Same sitemap as Google.
Do not wrap the main content in a client-only render that curl cannot see. If curl -sS https://<host>/ lacks the H1 and first paragraph, neither Google nor Bing nor ChatGPT has them.
“Avoid keyword stuffing” is still true and is no longer the main way sites get dropped. Refuse these by name (March 2024 core spam updates and later):
| Policy | What it looks like here | What we do |
|---|---|---|
| Scaled content abuse | Mass AI/generated pages, thin location doorways we do not serve, 200 near-duplicate “city” URLs | Write fewer pages. City pages only for cities on the truck / in areaServed. |
| Link schemes | Bought links, PBNs, guest-post networks, “link exchange” footers | Earn listings and data-led mentions. No payments for links. |
| Site reputation abuse | Third-party content on our domain to rank for their queries (parasite SEO) | Our host publishes our business. No coupon/casino subfolders. |
| Expired domain abuse | Ranking a new product on a aged domain’s leftover authority | New LocalFave tenant = new hostname. Do not revive random aged domains. |
| Keyword stuffing / hidden text | Titles that repeat the city five times; white-on-white | Human-framework voice. One primary phrase. |
A helper that “generates 40 SEO pages” for a new shop is proposing scaled content abuse. Push back. Use the cluster cap (pillar + 5–10).
Only when Phase 1–3 pass on the live host. Every line is a URL. Helpers do not ask for a paste of a verification token in chat.
Search Console (every class)
https://<host>/ : https://search.google.com/search-console/welcomehttps://<host>/sitemap.xml : https://search.google.com/search-console/sitemaps/ and money pages → Request indexing: https://search.google.com/search-console/inspectBing Webmaster (every class — AI search)
Google Business Profile (local / localfave-tenant only)
Do not ask the human to “do SEO.” Ask them to verify the property and paste nothing back. If DNS verification is required, give the record name + type and the put-URL for [DNS Server] DNS — never the live secret.
| Cadence | Where | What “working” looks like |
|---|---|---|
| Live, any time | https://<host>/insights | Real people, this host only. Not bots, not our curls. |
| Weekly | Search Console Performance | Impressions move before clicks. Queries at positions 20–40 rising = early win. CTR problems = title/description, not “more pages.” |
| Weekly | Search Console CWV | LCP/INP/CLS in the pass band, or a named fix. |
| Weekly (local) | GBP | Views, calls, direction requests. Map Pack matters more than organic #3. |
| Month 1–2 (new domain) | Coverage + sitemap | Indexed count ≈ URLs we meant to index. Not 0, not thousands of junk. |
| Month 3–6 (new domain) | Performance | First non-brand clicks. Brand queries appearing is a trust signal. |
A new domain with strong on-page and no links should be expected to sit for months. That is not a bug in the title tag. Work the listings and one link-earning page (SaaS free tool, local data, partner page).
Do not compare GA4 “uniques” to /insights. We do not install GA as the reported number.
H=https://<host> # canonical, no trailing path
curl -sS -o /dev/null -w 'home %{http_code}\n' "$H/"
curl -sS -o /dev/null -w 'insights %{http_code}\n' "$H/insights" # 200; that GET must not increment page views
curl -sS "$H/robots.txt"
curl -sS -o /dev/null -w 'sitemap %{http_code} %{content_type}\n' "$H/sitemap.xml"
# titles / canonical / description / json-ld / viewport (digest, do not dump HTML)
curl -sS "$H/" | python3 -c "import sys,re; h=sys.stdin.read();
print('title', re.search(r'<title[^>]*>([^<]+)',h,re.I).group(1)[:80] if re.search(r'<title',h,re.I) else None)
print('canon', (re.search(r'rel=[\"\\']canonical[\"\\'][^>]*href=[\"\\']([^\"\\']+)',h,re.I) or re.search(r'href=[\"\\']([^\"\\']+)[\"\\'][^>]*rel=[\"\\']canonical',h,re.I)))
print('desc', bool(re.search(r'name=[\"\\']description[\"\\']',h,re.I)))
print('viewport', 'viewport' in h.lower())
print('jsonld', 'ld+json' in h.lower())
print('noindex-home', bool(re.search(r'noindex', h[:4000], re.I)))
print('h1', bool(re.search(r'<h1', h, re.I)))"
Pass bar:
200 on HTTPS canonical host. curl sees H1 + answer-first paragraph (not an empty shell).robots.txt 200, allows /, points at this host’s sitemap, disallows ops paths.sitemap.xml 200 XML, https locs, this host only, every public money + cluster page listed, no thin/param URLs.Organization + LocalBusiness or SoftwareApplication)./insights 200 for this host only (R13). Home is not noindex./go/map dest matches that address. Phone wrapper only if the number is public.[PASS/FAIL] seo <host> with those lines. Max one live pass. Do not curl /go/call as proof.
A host is SEO-ready when:
Not done: “added keywords.” Not done: sitemap 303. Not done: canonical to ai.fedm8.com. Not done: indexing /insights. Not done: 40 generated city pages. Not done: on-page only with zero listings on a new domain, promised as “we will rank next week.”
Use for nodedough.com, fedm8.com, CipherDeck / scytherdeck.com. Skip GBP unless there is a walk-in shop.
Index: homepage, pricing (if it exists), comparison, integrations, docs you want found, changelog, the free tool. noindex the signed-in app, /admin, /quick, config, health, ticket inboxes.
Ship, in order:
Organization + SoftwareApplication JSON-LD.X vs Y, X alternatives, best [category] tools — honest, Human-framework voice, no fake “winner” tables.dateModified.Use for executivenailsuite.com, Tensuite shops, every *.localfave.org tenant.
Map Pack > organic position. GBP is the priority surface.
Organization + LocalBusiness JSON-LD. NAP identical on page, JSON-LD, /go/map, Insights dest./go/call only if the number is public. No public phone (Zen Soma, Vanessa) → form only, no fake tel.*.localfave.org host: expect 3–6 months. Listings and GBP move local faster than blog posts.New LocalFave site: new portal slug + <slug>.localfave.org on this stack. Copy the Marco/Zen/Vanessa metadata pattern; do not invent a second repo.
Do
/insights live and noindex.src/lib/tenants.ts, per-host layout metadata, Worker /robots.txt + /sitemap.xml).memory_facts trap when a live host taught us something (≤160 chars).Don’t
http:// locs, four indexable hosts, or duplicate titles./t/marcobros on the hub), or “ranks next week” on a new domain with no listings.| Doc | Why |
|---|---|
| https://projects.jbnx.io/framework/tracking-doctrine | /insights, /collect, /go/* — same host, real people only |
| https://projects.jbnx.io/framework/monthly-funnel-proof | What we show a paying customer |
| https://projects.jbnx.io/framework/human-framework | How the public sentences sound |
| https://projects.jbnx.io/framework/app-review-framework | When the ask is a ranked audit, not a ship |
| https://projects.jbnx.io/framework/marcobros-security-seo-2026-08-31 | Worked example of an SEO fail (expired TLS, no mobile, no descriptions) — not the playbook |
v2 — 2026-09-02. v1 converted the on-site ranking blueprint into an AI playbook. v2 adds 2026 search: off-site links, brand/engagement, AI search + Bing, full schema, CWV numbers, topic clusters, E-E-A-T, indexing hygiene, named spam policies, measurement window, SaaS and local playbooks.