fix(seo): resolve Semrush site audit findings - #131
Merged
vpetersson merged 2 commits intoAug 10, 2026
Conversation
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
approved these changes
Aug 10, 2026
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.
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
ProductJSON-LD carried areviewwith noreviewRating. Google requiresreviewRatingon everyReview, so the block was invalid and invalidated the whole Product snippet.Productvalidates onoffersalone, 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/servedexpress@4.18.2as[email protected]/faq/how-do-i-use-vex/servedrequests@2.32.3the same wayEach 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 genuinemailto:addresses in prose stay obfuscated. Three pieces were needed:minify.tdewolff.html.keepCommentsinhugo.toml— the minifier drops every comment otherwiselayouts/partials/content.html(new) wraps eachfigure.code-block; the markers cannot live in the code block render hook because Hugo strips HTML comments emitted from render hooks{{ .Content }}call sites now route through that partialkeepCommentsis 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 theemail_off/email_onmarkers and nothing else.Everything else
rel=nofollowon internal links/slacklinks — it is an internal URLrel=nofollowon external links# Headingfrom privacy and terms; the layout already renders.Titleseo_titlefront-matter param: the ENISA post keeps its headline ash1while its<title>fits Google's display limitVerification
Production build: 457 pages, one h1 per page, three valid JSON-LD blocks with no
review, zeronofollowanywhere, 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 lintpasses.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):
trust.andapp.consume the budget whilegpl-license-guideandsbom-generation-tools-comparison— the Fixes mobile rendering issue #2 and Adds favicon #3 organic traffic pages — are never crawledTwo external
cisa.govlinks 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 fmtnormalisation 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