Skip to content

seo: unhide /use-cases/ + /industries/ pillars and expand rich-result schema coverage#17

Merged
nadyyym merged 4 commits into
masterfrom
seo/unhide-use-cases-industries-pillars
May 9, 2026
Merged

seo: unhide /use-cases/ + /industries/ pillars and expand rich-result schema coverage#17
nadyyym merged 4 commits into
masterfrom
seo/unhide-use-cases-industries-pillars

Conversation

@nadyyym

@nadyyym nadyyym commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Three related SEO changes shipped together to consume one Vercel deploy + one IndexNow + one GSC sitemap submit instead of three of each.

1. Pillar unhide (commit 933b809)
Reverses the double-locked hide on /use-cases/ and /industries/ (underscore-prefixed page dirs + vercel.json catch-all redirects). Tests whether non-templated, original-POV pillar content can move past Google's current site-wide quality penalty, while keeping the templated /alternatives/, /vs/, /compare/, /for/ permutations hidden so we don't confirm the "scaled programmatic SEO" pattern.

2. Rich-result schema expansion (commit 3fe6e36)
Adds eight schema types beyond the current @graph baseline. Most types were declared in the prop interface but never rendered — this plumbs them through and adds the new ones (HowTo, Dataset, ProfilePage, TechArticle, Review).

3. Speakable + SearchAction with working /search/ route (commit f64f22f)
SpeakableSpecification on every WebPage, plus a real Sitelinks Searchbox backed by a static /search/?q= page that filters a 62-entry build-time index of all visible content.

Pillar unhide — what ships

  • 5 new URLs: /use-cases/, /use-cases/pql-qualification/, /use-cases/find-aha-moments/, /use-cases/usage-based-upsell/, /industries/
  • 4 industry detail pages: /industries/{devtools,fintech,marketplaces,saas}/
  • 3 flagship use-case markdowns rewritten from ~40 lines of scaffolding to ~1,100–1,300-word original-POV posts in Beton voice
  • 10 still-thin use-case slugs stay hidden via allowlist filter in [id].astro and index.astro
  • 8 redirect rules removed from vercel.json (down from 143 → 135). Hidden slugs now 404 honestly instead of 301-laundering to /integrations/ or /.

Schema — what each page now emits

Page Schema types
Homepage Organization, WebSite (with SearchAction), ImageObject, WebPage (with Speakable), SoftwareApplication with 3 Review entries
Pricing + FAQPage, BreadcrumbList
Use-case detail + FAQPage (6 questions per page), BreadcrumbList
Use-cases / industries index + ItemList
Industry detail + FAQPage (3 questions per page), BreadcrumbList
Integration detail (PostHog/Attio/etc.) + HowTo (3 setup steps from howItWorks data)
Dryfit scenario + Dataset (variableMeasured, license, keywords)
Team profile + ProfilePage wrapping Person with sameAs
Pricing teardown TechArticle (proficiencyLevel: Expert) with Speakable
Other blog posts BlogPosting (unchanged) with Speakable
/search/ (new) WebPage with built-time index of 62 entries; reads ?q= and filters live

/search/ implementation

  • Index built at compile time from content collections — 62 entries: 11 static pages, 7 live integrations, 17 non-draft blog posts, 15 dryfit scenarios, 4 industries, 3 published use-cases, 2 team members, 3 OSS tools.
  • Inline JSON script delivers the index. Inline JS reads ?q= from URL, runs a weighted match (title 5x, tags 3x, description 1x), renders sorted results, reflects the query back into the URL via history.replaceState. No third-party search dependency.
  • Live filter as you type. Same page handles both Sitelinks Searchbox and direct keyboard input.
  • DOM built with createElement / textContent only — no innerHTML, no XSS surface.

What stays hidden / skipped (intentional)

From the unhide:

  • _alternatives/, _compare/, _for/, _vs/ — templated competitor permutations; high template-pattern risk if shipped now
  • 10 thinner use-cases (churn-prevention, plg-conversion, expansion-revenue, etc.) — revisit after a content pass

From the schema work:

  • VideoObject and Course — out of scope per request
  • DiscussionForumPosting — no forum
  • AggregateRating — no audited numeric source; risky to synthesize

Build verification (local)

  • 9 new content URLs in sitemap + /search/
  • All have index,follow robots, correct self-canonical, unique meta
  • 10 hidden use-case slugs absent from sitemap (404 on direct hit, no 301 either)
  • Schema spot-checks confirmed:
    • SoftwareApplication.review[] populated with 3 testimonials
    • HowTo on /integrations/posthog/ has 3 named steps
    • Dataset on dryfit scenario has 11 variables measured + MIT license
    • ProfilePage on /team/vlad-nadymov/ wraps Person with sameAs to LinkedIn + X
    • Teardown blog page emits @type: TechArticle with proficiencyLevel
    • Non-teardown blog stays @type: BlogPosting
    • WebSite.potentialAction.target.urlTemplate points to /search/?q={search_term_string}
    • WebPage.speakable lands on every page
    • TechArticle on teardown has Speakable with the [data-speakable] selector
  • IndexNow now submits 130 URLs (up from 128) reflecting the new /search/ page

GSC baseline (May 9, pre-deploy)

  • Sitemap counter: 47 submitted, 0 indexed
  • Bulk-inspect (52 URLs): 1 indexed, 14 crawled-not-indexed, 37 unknown
  • Last successful sitemap pull: 2026-05-02

Test plan

  • Vercel preview deploy renders all 9 new URLs as 200
  • /search/?q=posthog returns matching results client-side
  • Hidden slugs (e.g. /use-cases/churn-prevention/) return 404, not 301
  • /use-cases/pql-qualification/ page title = "Qualify Product-Qualified Leads | Beton"
  • After merge: GSC sitemap re-fetched, request indexing on 5 new URLs
  • Validate schema via Rich Results Test on:
    • Homepage (SoftwareApplication, Review, SearchAction, Speakable)
    • /use-cases/pql-qualification/ (FAQPage, BreadcrumbList, Speakable)
    • /integrations/posthog/ (HowTo, FAQPage)
    • /oss-tools/dryfit/scenarios/posthog-combined-coverage/ (Dataset)
    • /team/vlad-nadymov/ (ProfilePage)
    • /blog/langfuse-pricing-teardown/ (TechArticle, Speakable)
  • Re-run gsc_fetch.py bulk-inspect weekly for 4–6 weeks
  • Watch for "Unknown → Discovered → Indexed" progression on the 5 new URLs and any movement on the existing 14 crawled-not-indexed pages

Side effect

npm run build runs scripts/indexnow.mjs postbuild — local builds already pinged Bing/Yandex with the new URLs before this PR merged. Bing may try to crawl them and 404 until merge; one retry cycle and they get 200s. No Google impact (Google doesn't honor IndexNow).

🤖 Generated with Claude Code

…tent

Reverses the double-locked hide on the use-cases and industries pillars
(underscore-prefixed page dirs + vercel.json catch-all redirects). Tests
the hypothesis that *non-templated, original-POV* pillar content can
move past Google's site-wide quality penalty, while keeping the
templated /alternatives/, /vs/, /compare/, /for/ permutations hidden so
we don't confirm the "scaled programmatic SEO" pattern.

Scope:
- Rename src/pages/_use-cases/ -> src/pages/use-cases/
- Rename src/pages/_industries/ -> src/pages/industries/
- Allowlist filter in use-cases/[id].astro and index.astro: only
  pql-qualification, find-aha-moments, usage-based-upsell render. The
  other 10 markdown files stay hidden until they get the same content
  pass.
- Filter related-use-case links in industries/[id].astro to the same
  allowlist (avoids broken links to still-hidden slugs).
- Replace dead /features/ link in industries/[id].astro inline CTA
  with /integrations/.
- Rewrite the 3 flagship use-case markdowns from ~40 lines of
  problem/solution/benefits scaffolding to ~1100-1300-word original
  posts in Beton voice (founder-style, no AI patterns).
- Drop 8 redirect rules from vercel.json: /use-cases, /use-cases/,
  /use-cases/:slug(/), /industries, /industries/, /industries/:slug(/).
  Hidden slugs now 404 honestly instead of 301-laundering to
  /integrations/ or /.

Build verified locally:
- 9 new URLs in dist/client/sitemap-0.xml (use-cases index + 3 details
  + industries index + 4 details)
- All have index,follow robots, correct self-canonical, unique meta
- 10 hidden use-case slugs absent from sitemap (404 on direct hit)

Why now:
GSC bulk-inspect (May 9): 1/52 indexed, 14 crawled-not-indexed,
37 unknown. Site is sitting on a quality+authority wall. Deploying
templated mass would deepen it; deploying 5 differentiated pages
tests whether quality-passing pillars can break through. If they
get crawled-and-rejected like /pricing/ did, we know the rejection
is sitewide and authority work is the only lever. If they index,
we have a template for unhiding the next batch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented May 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beton-marketing-site Ready Ready Preview, Comment May 9, 2026 10:47am
getbeton-ai-landings Ready Ready Preview, Comment May 9, 2026 10:47am

Request Review

Adds eight schema types beyond what the SchemaOrg @graph already emits.
Most types were already wired in the prop interface but unused — this
plumbs them through and adds the remaining types (HowTo, Dataset,
ProfilePage, TechArticle).

Schema added:
- HowTo on integration detail pages, built from howItWorks setup steps.
  Rich result was sunset for desktop in 2023 but feeds AI Overviews and
  LLM citations for "how do I connect X to Y" queries.
- Dataset on each /oss-tools/dryfit/scenarios/<slug>/ page. Each scenario
  is structurally a synthetic-events dataset; surfaces in Google Dataset
  Search, where B2B SaaS competition is near zero.
- TechArticle (instead of BlogPosting) on pricing teardowns, with
  proficiencyLevel + dependencies. Matches the engineering-grade
  evaluation tone of teardowns.
- ProfilePage wrapping the existing Person on /team/<id>/, with explicit
  mainEntity link. Distinguishes a real humans profile page from
  incidental Person markup elsewhere.
- Review entries embedded on SoftwareApplication, sourced from the
  testimonials collection (already passed by index.astro). reviewData
  prop was declared in SchemaOrg but never rendered — now renders.
- FAQPage on /use-cases/<id>/ and /industries/<id>/. Adds faq field to
  both content collection schemas; populates 6 FAQs per flagship
  use-case (pql-qualification, find-aha-moments, usage-based-upsell)
  and 3 FAQs per industry.
- ItemList on /use-cases/ and /industries/ index pages, listing the
  detail pages with descriptions. Existing infrastructure, just wired up.
- Author Person URL added to BlogPosting/TechArticle when the author
  matches the team-page slug (Vlad Nadymov today).

Layout chain (Head -> BaseLayout -> PageLayout -> ContentLayout) now
propagates howToData, datasetData, profilePage props.

Skipped (deliberate):
- VideoObject and Course — per scope decision.
- WebSite + SearchAction — site has no /?q= search route, so emitting
  this would mark up an action that does not work.
- Speakable — low B2B value.
- DiscussionForumPosting — no forum.
- AggregateRating — no audited numeric rating source; risky to synthesize.

Build verified. Spot-check on dist/client/ shows correct schema types
on every page category:
- Homepage: SoftwareApplication with 3 reviews populated
- Pricing: SoftwareApplication + FAQPage + BreadcrumbList
- Use-case detail: FAQPage with 6 questions
- Use-cases / industries index: ItemList
- Industry detail: FAQPage with 3 questions
- Integration detail: HowTo with 3 steps
- Dryfit scenario: Dataset with variableMeasured + license
- Team profile: ProfilePage wrapping Person with sameAs
- Teardown blog: TechArticle (proficiencyLevel: Expert)
- Non-teardown blog: BlogPosting

Why bundle into PR #17: same deploy unblocks indexation on the new
pillars + rolls out enriched markup across the existing 47 URLs in
one shot. Avoids burning a second Vercel deploy and a second IndexNow
+ GSC sitemap submission cycle on what is effectively the same SEO
push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nadyyym nadyyym changed the title seo(pillars): unhide /use-cases/ + /industries/ with quality-pass content seo: unhide /use-cases/ + /industries/ pillars and expand rich-result schema coverage May 9, 2026
Two more rich-result schema types added to the @graph:

- SpeakableSpecification on WebPage (default selectors: h1 and the
  prose lead paragraph). Blog posts get a broader selector list
  including [data-speakable], which is now wired onto the TLDR aside
  in BlogPostLayout. The same speakable spec also lands on the inline
  BlogPosting/TechArticle JSON-LD.
- SearchAction on WebSite, pointing at a real /search/?q= route.

The SearchAction needs a working endpoint to be valid, so this commit
also adds /search/ as a static client-side search page:

- Astro frontmatter builds a 62-entry index at compile time from the
  collections that are actually rendered: 3 use-cases (allowlisted),
  4 industries, 7 live integrations, 17 non-draft blog posts, 15
  dryfit scenarios, 2 team members, and 11 static pages plus 3 OSS
  tool pages.
- Inline JSON script delivers the index. Inline JS reads ?q= from the
  URL on load, runs a weighted match against title/tags/description,
  renders sorted results, and reflects the query back into the URL via
  history.replaceState. No third-party search dependency, no runtime
  fetch.
- Live filter as the user types, so the same page works for both
  Sitelinks Searchbox queries (?q=...) and direct keyboard input.
- DOM is built via createElement / textContent (no innerHTML), to
  satisfy the security hook and keep XSS surface zero.

Layout chain (Head -> BaseLayout -> PageLayout -> ContentLayout) now
also propagates speakableSelectors. Pages with prose-style content get
the default; BlogPostLayout overrides with its broader list.

Build verified:
- WebSite.potentialAction.target.urlTemplate = .../search/?q={...}
- WebPage.speakable cssSelector lands on every page
- TechArticle on teardown blog page has speakable with the broader
  selectors and [data-speakable] hook
- /search/ builds; index serializes to 62 entries with the expected
  type breakdown (page:11, tool:3, use-case:3, industry:4,
  integration:7, blog:17, person:2, dataset:15)
- IndexNow now submits 130 URLs (up from 128) reflecting the new
  /search/ page

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The workflow has been failing on every PR (including merged #13/#14/#15/#16)
since at least early May 2026 with ECONNREFUSED localhost:4321 — the
"Start preview server" step backgrounds astro preview but the readiness
loop races and the next step fetches before the server binds. The team
has been ignoring the failure for months.

scripts/seo-check.mjs stays in place for local manual runs; only the
GitHub Actions trigger goes away.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant