Skip to content

fix(seo): resolve Semrush site audit findings - #131

Merged
vpetersson merged 2 commits into
sbomify:masterfrom
vpetersson-bot:seo-semrush-audit-fixes
Aug 10, 2026
Merged

fix(seo): resolve Semrush site audit findings#131
vpetersson merged 2 commits into
sbomify:masterfrom
vpetersson-bot:seo-semrush-audit-fixes

Conversation

@vpetersson-bot

Copy link
Copy Markdown
Contributor

Fixes every finding in the Semrush site audit for sbomify.com that originates in this repo. Data pulled from the Semrush API (full audit: info, snapshots, meta_issues and detail rows for all 19 issue types).

Structured data — 2 errors

The homepage Product JSON-LD carried a review with no reviewRating. Google requires reviewRating on every Review, so the block was invalid and invalidated the whole Product snippet. Product validates on offers alone, so the review is gone. We have collected no ratings and inventing one would breach Google's review policy — the Atsign testimonial stays as on-page content.

Cloudflare email obfuscation — 4 broken internal links + 1 4xx

Cloudflare rewrites anything shaped like an email address, which was mangling package identifiers in code samples:

  • /guides/javascript/ served express@4.18.2 as [email protected]
  • /faq/how-do-i-use-vex/ served requests@2.32.3 the same way

Each rewrite links to /cdn-cgi/l/email-protection, which 404s — that is the source of all four "broken internal links" and the single 4xx.

Rather than switching the feature off zone-wide, code blocks are now wrapped in <!--email_off--> markers, so obfuscation is scoped out of samples while genuine mailto: addresses in prose stay obfuscated. Three pieces were needed:

  1. minify.tdewolff.html.keepComments in hugo.toml — the minifier drops every comment otherwise
  2. layouts/partials/content.html (new) wraps each figure.code-block; the markers cannot live in the code block render hook because Hugo strips HTML comments emitted from render hooks
  3. the 12 {{ .Content }} call sites now route through that partial

keepComments is global, so every other HTML comment would have started publishing. Template comments moved to {{/* */}}, and comments in HTML content files (which goldmark does not touch) moved to a new no-op {{< comment >}} shortcode. Built output now contains the email_off/email_on markers and nothing else.

Everything else

Finding Count Fix
rel=nofollow on internal links 52 Removed from the /slack links — it is an internal URL
Non-descriptive anchor text 4 "Learn More" → "Explore the Trust Center"; "here" → "the sbomify-action workflow file"; "Go" → "Go (Golang)"
rel=nofollow on external links 4 Removed from the post-source link, which also got descriptive text
Multiple h1 2 Dropped the duplicate # Heading from privacy and terms; the layout already renders .Title
Anchor text is a bare URL 1 ICO link now reads "Information Commissioner's Office"
Title too long 1 New seo_title front-matter param: the ENISA post keeps its headline as h1 while its <title> fits Google's display limit

Verification

Production build: 457 pages, one h1 per page, three valid JSON-LD blocks with no review, zero nofollow anywhere, 411 code blocks wrapped with balanced marker pairs, and every email-shaped string inside a protected region. Rendered page text diffed against production is unchanged apart from the intended edits. bun run lint passes.

Not in this PR

Two audit items need dashboard access and cannot be done from the repo (the Semrush site-audit API is read-only — no settings or re-crawl endpoint):

  • HSTS is not enabled — Cloudflare → SSL/TLS → Edge Certificates (2 issues)
  • The audit crawl is capped at 100 pages with subdomain crawling on, so trust. and app. consume the budget while gpl-license-guide and sbom-generation-tools-comparison — the Fixes mobile rendering issue #2 and Adds favicon #3 organic traffic pages — are never crawled

Two external cisa.gov links return 403 to the Semrush crawler; they are fine for humans.

Note for review

This branch also carries the in-progress em-dash cleanup that was already in the working tree, plus dprint and d2 fmt normalisation from running the repo's own lint script. Those changes are interleaved with the SEO edits in several files, so they could not be split cleanly into separate commits.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QtZEQfycJaQ6jqLQaHNQWd

vpetersson-bot and others added 2 commits August 10, 2026 09:28
Pulled the full Semrush site audit for sbomify.com via the API and fixed
every finding that originates in this repo.

Structured data (2 errors): drop the review from the homepage Product
JSON-LD. Google requires reviewRating on every Review, so the rating-less
block was invalid and invalidated the whole Product snippet; Product
validates on offers alone. We have collected no ratings and inventing one
would breach Google's review policy, so the Atsign testimonial stays as
on-page content only.

Cloudflare email obfuscation (4 broken internal links + 1 4xx): Cloudflare
rewrites anything shaped like an email address, which mangled package
identifiers in code samples -- express@4.18.2 was served as
"[email protected]" in the JavaScript guide, requests@2.32.3 in the VEX FAQ,
each one linking to /cdn-cgi/l/email-protection, which 404s. Wrap code
blocks in <!--email_off--> markers so the feature is scoped out of samples
while genuine mailto: addresses in prose stay obfuscated. This needs three
pieces: keepComments in the minifier config, the markers applied in
partials/content.html (Hugo strips HTML comments emitted from render
hooks), and the 12 .Content call sites routed through that partial.

Enabling keepComments would have started publishing every other HTML
comment, so template comments moved to {{/* */}} and comments in HTML
content files moved to a new no-op {{< comment >}} shortcode. The built
output now contains email_off/email_on markers and nothing else.

Also: remove rel=nofollow from the internal /slack links (52 warnings) and
from the post-source GitHub link; drop the duplicate h1 from privacy and
terms, where the layout already renders .Title; give the ICO, Trust Center,
Go guide and post-source links descriptive anchor text; add seo_title
support so the ENISA post keeps its headline as h1 while its title tag
fits Google's display limit.

Verified against a production build: 457 pages, one h1 per page, valid
JSON-LD, zero nofollow, 411 code blocks wrapped with balanced markers, and
rendered page text unchanged against production apart from the intended
edits.

This also carries the in-progress em-dash cleanup that was already present
in the working tree, plus dprint and d2 fmt normalisation from running the
repo's own lint script.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtZEQfycJaQ6jqLQaHNQWd
Claude Code creates git worktrees under .claude/worktrees, which git sees
as embedded repositories and warns about on `git add -A`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtZEQfycJaQ6jqLQaHNQWd
@vpetersson
vpetersson merged commit b660e94 into sbomify:master Aug 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants