SEO Fix Plan — all 12 tickets - #94
Open
shivthakker wants to merge 2 commits into
Open
Conversation
Phase 1 — stop the bleeding
SEO-01 Strip ?ref=blog.fleetbase.io duplicates. Canonicals already
pointed at the clean path on every URL checked, so the fix is
hardening rather than repair: middleware now 308s the parameter
away so those URLs cannot be crawled as pages at all. The five
stale paths the plan lists already redirect in next.config.ts.
SEO-02 Keep the console out of Google. The console app itself lives in
another repo; what belongs here is the link equity. Every CTA
pointing at console.fleetbase.io now carries rel="nofollow",
via a shared relForHref helper so the two navbar render sites,
the solutions layout and 27 direct links stay consistent.
SEO-03 Fix the blog robots.txt 500. Root cause was broader than the
plan describes: fetchGhost threw on any non-OK response, and
Ghost answers an unknown slug with a 404 — so *every* bad
/blog/* URL returned a 500, not just robots.txt. Slug lookups
now treat 404 as "no such post" and fall through to notFound().
Phase 2 — one template pass
SEO-04 52 pages hardcoded "| Fleetbase" while the root layout appends
it again via title.template. Stripped from the top-level title
only — openGraph.title and twitter.title are not templated, so
they keep the brand. 16 over-length titles trimmed under 60
characters. Long blog headlines now return an absolute title,
dropping the suffix rather than cutting the headline.
SEO-05 57 descriptions rewritten to 120–155 characters, hand-written
per page rather than truncated, since these are sales pages.
Blog excerpts (~500 chars from Ghost) truncate at a word
boundary. The three auth screens get noindex instead of padded
copy — they have no search value.
SEO-06 Won't-fix, documented at the schema. Every property the plan
asks for is already present; the only gap is aggregateRating,
which Google requires to be backed by real reviews. Inventing
one would be fabricating data.
SEO-07 The plan says only blog posts have Open Graph tags; that is not
true of the live site — 67 pages already had them. The genuine
gaps were the /compare hub and all 11 docs routes, which now
share a buildDocsMetadata helper adding canonical, OG and
Twitter cards built from each page's frontmatter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SEO-08 Point internal links at final URLs. Verified each redirect
against the live site first — several went somewhere other than
the plan assumed (/docs/fleet-ops/orders lands on
/docs/fleet-ops/operations/orders/overview, not /orders/overview).
Rewrote 10 files, fixed the two internal 404s, and removed the
Bringg card from /compare, which linked to a redirect back to
the page the visitor was already on. Growth plan GP-05 restores
it as a real page.
Not done: the 20 external 4XX links. That list only exists in
the Ahrefs export, which is not in the repo.
SEO-09 Self-host the integration icons. All four broken logos already
existed under public/images/integrations — the component was
simply pointing at the CDN. Repointed all 26 references and
self-hosted the remaining 18 (Simple Icons, CC0) so a sales page
does not depend on a CDN that renamed these slugs once already.
SEO-10 One H1 per docs page. Not a Docusaurus swizzle — the docs are
fumadocs. fumadocs renders the frontmatter title as an h1 and
354 MDX files then opened with their own "# " heading, which is
the same text 269 times over. Removed the redundant body heading
from 343 files; the 11 section roots keep theirs, because those
routes skip DocsTitle and it is their only h1.
SEO-11 Cache blog pages at the edge. The blog was already on ISR, so
the plan's "rendered on every request" diagnosis was wrong. The
real cost was a 5-minute revalidate window: raised to an hour
and paired with s-maxage=3600 plus stale-while-revalidate so the
CDN never makes a reader wait on a cold render.
SEO-12 Link the sales pages from where the authority is. The role and
use-case pages had one inbound link each because they lived only
in the nav dropdown. Added a footer column covering all twelve,
a homepage section linking the three compare pages and every
role and use-case page in body copy, and a RelatedPages
component that cross-links platform modules to the roles and
industries that buy them. It looks itself up by pathname, so
pairings live in one map instead of thirty page components.
Also caught in review: /platform/fleetops kept a doubled brand suffix
because its title came from a const shared with the social tags, and two
further titles repeated the brand mid-string.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the Fleetbase SEO Fix Plan (Ahrefs audit, project 9822696, crawl 2 Sep 2026). All 12 tickets addressed across two commits.
Every claim in the plan was verified against the live site before being acted on. Four turned out not to reproduce — those are documented below rather than "fixed", because the code was already correct.
Phase 1 — stop the bleeding
?ref=duplicates?ref=away so those URLs can't be crawled as pages. The five stale paths it lists already redirect.console.fleetbase.io/robots.txtservesDisallow:— empty, i.e. allow everything — and the shell has no title or robots meta. The console app is a different repo, so what's fixed here is the link equity: every CTA to it now carriesrel="nofollow"via a sharedrelForHrefhelper. The noindex work still needs a PR against the console repo.fetchGhostthrew on any non-OK response, and Ghost answers an unknown slug with a 404 — so every bad/blog/*URL returned a 500, not justrobots.txt. Slug lookups now treat 404 as "no such post" and fall through tonotFound().Phase 2 — one template pass
| Fleetbasewhile the layout appends it again. Stripped from the top-leveltitleonly —openGraph.titleandtwitter.titleare not templated by Next.js, so they keep the brand. 16 over-length titles trimmed. Long blog headlines now return anabsolutetitle, dropping the suffix instead of cutting the headline.noindexinstead of padded copy.aggregateRating, which Google requires to be backed by real reviews. Inventing one would be fabricating data and is a manual-action risk. There was already a deliberate comment in the codebase refusing this./pricingon the live site returns a full set, and 67 page files already setopenGraph. The genuine gaps were the/comparehub and all 11 docs routes, which now share abuildDocsMetadatahelper.Phase 3 — housekeeping
/compare(it linked to a redirect back to the same page). The 20 external 4XX links are not done — that list exists only in the Ahrefs export.public/images/integrations; the component just pointed at the CDN. Repointed all 26 references and self-hosted the remaining 18 (Simple Icons, CC0). Zero CDN dependencies left.h1, and 354 MDX files then opened with their own#heading — identical text in 269 cases. Removed from 343 files; the 11 section roots keep theirs, since those routes skipDocsTitle.s-maxage=3600+stale-while-revalidate.RelatedPagescomponent cross-linking platform modules to the roles and industries that buy them.Verification
next buildcompiles successfully.Reviewer notes — please look at these
rel="nofollow"on console CTAs is marked optional in the plan. It's included because you asked for the full document, but note that nofollow drops equity rather than redistributing it — the real win is the console noindex, which is in another repo.GHOST_API_URL/GHOST_CONTENT_API_KEY, so the blog routes are compile-checked only. This is pre-existing onmain.Follow-ups this PR does not cover
blog.fleetbase.io→fleetbase.io/blogis hosting-level config, not in this repo🤖 Generated with Claude Code