Boom Media
Boom Labs · Research & Strategy

boommedia.us — Google Optimization & SEO Audit

Live crawl of all 30 sitemap URLs on production, plus the Search Console “Blocked due to unauthorized request (401)” investigation. Every number below was measured against the deployed site, not estimated.

Crawled 28 July 2026 · repo bm-vercel · Vercel project boommediaus · Googlebot user-agent
30/30
Sitemap URLs returning 200
219ms
Median TTFB (p90 429ms)
14
Titles over 60 chars
10
Descriptions over 165 chars
100%
Images with alt text
30
Pages with canonical + schema

🚨 The 401 — root cause & fix

Fixed & deployed

Search Console was crawling protected preview deployments, not boommedia.us

I probed every sitemap path plus /admin, /portal, /studio and /api/* on production: nothing on boommedia.us returns 401. The 401s come from *.vercel.app deployment URLs. Vercel Deployment Protection is enabled, so those hosts 302 to vercel.com/sso-api?url=… — an unauthorized response from Google’s perspective.

Shipped in commit 922f09c:

// src/app/robots.ts — disallow-all on any non-production deployment
if (process.env.VERCEL_ENV && process.env.VERCEL_ENV !== "production") {
  return { rules: [{ userAgent: "*", disallow: "/" }] };
}
// production rules now also disallow /admin/

Preview deployments additionally send X-Robots-Tag: noindex, nofollow via next.config.ts. Once Google recrawls, the 401 bucket drains on its own.

Your move in Search Console: open the indexing report and confirm the affected URLs are on *.vercel.app. If any are on boommedia.us itself, send me the list — that would be a different cause than the one fixed here. Then use Validate Fix to trigger recrawl.

🔴 Priority 1 — costs you rankings today

P1

/contact renders nothing server-side — 0 H1s, 107 words

The entire form sits inside a <Suspense> boundary because it calls useSearchParams(). Next.js therefore prerenders the fallback — an empty <div style="min-height:100vh"> — and the page only exists after hydration. Googlebot does render JavaScript, but on a deferred second pass, and every other page on the site serves complete HTML on first response.

Fix: move the useSearchParams() read into a small child component and leave the form markup outside the Suspense boundary, so step 1 prerenders.

P1

Title template double-brands every page — 14 of 30 titles are truncated in results

src/app/layout.tsx sets template: "%s — Boom Media", but most pages already end their own title with | Boom Media or | BOOM Media. The result is a doubled brand and titles up to 96 characters — Google shows roughly 60.

/restaurants
  Restaurant Solutions — Online Ordering, POS, Digital Signage &amp; SEO | BOOM Media — Boom Media
  96 chars — everything past ~60 is dropped in the SERP

Fix: strip the hand-written | Boom Media suffix from each page’s metadata.title and let the template add it once.

🟡 Priority 2 — worth fixing this month

P2

Invalid schema type ComparisonTable on /blog/boom-vs-competitors

ComparisonTable is not a schema.org type. Google ignores the node, and an unrecognised @type in a graph can suppress rich-result eligibility for the valid BlogPosting markup alongside it. Replace it with a Table node, or model the comparison as an ItemList of Product/Service entries.

P2

10 meta descriptions exceed 165 characters

Google truncates around 155–165 chars, so the call-to-action at the end is cut. The longest is 251 chars on /boom-online-ordering.

P2

31 live, indexable pages are missing from the sitemap

These return 200 and are allowed by robots.txt, but src/app/sitemap.ts never lists them, so they rely entirely on internal links for discovery. Corrected upward from an earlier count of 4: that figure came from reading static route folders only, which missed every page generated by the blog/[slug] and services/[slug] dynamic routes. A full link crawl found 31.

The 20 /services/* pages are the real story here — that is an entire commercial section of the site left out of the sitemap.

Decide per page: add to the sitemap, or noindex it if it is a landing page you do not want in the index.

🔵 Priority 3 — polish

P3

5 pages have no og:image

Links to these pages render as bare text cards when shared on LinkedIn, Facebook or iMessage — including two of your highest-intent commercial pages.

P3

6 pages under 400 words

Not automatically a problem — /contact and /seo-audit are tools, not articles. But /websites, /hosting and /restaurants/pos are commercial pages competing on head terms, and they are thin for that job.

P3

project-t4qis.vercel.app serves the full production site at 200

Unlike the other *.vercel.app aliases, this one is not behind Deployment Protection — it serves every page, and its robots.txt says Allow: /. The canonical tags correctly point at https://boommedia.us, which is what keeps this from being a live duplicate-content problem, but the alias is unnecessary exposure. Remove it in Vercel → Project → Domains if nothing depends on it.

What is already right

Healthy

📊 Full crawl data — all 30 pages

PathStatusTTFBTitleDesc H1WordsAltSchemaFlags
/ 200 429 54 148 1 1404 3/3 1 clean
/about 200 238 80 156 1 880 3/3 1 title 80
/contact 200 233 45 161 0 107 2/2 1 h1 ×0 107w
/portfolio 200 279 42 153 1 585 2/2 1 clean
/guarantee 200 174 54 148 1 840 2/2 1 clean
/services 200 244 83 147 1 461 2/2 1 title 83
/websites 200 223 54 148 1 374 2/2 1 374w
/hosting 200 171 54 148 1 383 2/2 1 383w
/ai-automation 200 252 80 158 1 1118 2/2 1 title 80
/service-industry 200 600 75 184 1 721 2/2 1 title 75 desc 184
/restaurants 200 251 96 200 1 659 2/2 1 title 96 desc 200
/restaurants/ordering 200 198 86 185 1 401 2/2 1 title 86 desc 185 no og:image
/restaurants/pos 200 216 84 183 1 363 2/2 1 title 84 desc 183 no og:image 363w
/restaurants/signage 200 193 54 148 1 409 2/2 1 clean
/restaurants/seo 200 205 54 148 1 408 2/2 1 clean
/restaurants/printing 200 190 54 148 1 407 2/2 1 clean
/restaurants/photography 200 554 54 148 1 480 2/2 1 clean
/restaurants/online-ordering-costs 200 215 83 200 1 1454 2/2 2 title 83 desc 200
/boom-online-ordering 200 235 75 251 1 2083 2/2 1 title 75 desc 251 no og:image
/gloriafood-replacement 200 199 91 192 1 823 2/2 3 title 91 desc 192 no og:image
/gloriafood-migration-guide 200 245 68 133 1 868 2/2 1 title 68
/bar 200 204 55 185 1 993 2/2 1 desc 185
/compliee 200 119 84 156 1 656 2/2 1 title 84
/investment 200 259 60 183 1 2602 2/2 1 desc 183
/seo-audit 200 186 51 154 1 233 2/2 1 233w
/blog 200 120 37 134 1 358 2/2 1 no og:image 358w
/blog/gloriafood-alternatives 200 203 71 159 1 1925 2/2 5 title 71
/blog/boom-vs-competitors 200 240 69 193 1 517 2/2 2 title 69 desc 193
/privacy 200 219 54 148 1 970 2/2 1 clean
/terms 200 206 54 148 1 1166 2/2 1 clean
Column notes. TTFB in milliseconds, single uncached request under a Googlebot user-agent from a US connection — indicative, not a substitute for field CrUX data. Title/Desc are character counts. Alt is images-with-alt / total images. Schema is the count of JSON-LD nodes with an @type.

🧭 Suggested order of work

  1. Validate the 401 fix in Search Console once Google recrawls — already deployed.
  2. Un-double the title template — one edit per page, 14 pages, biggest SERP gain per minute spent.
  3. Make /contact server-render — fixes the SEO hole and the Twilio scrape risk in the same change.
  4. Trim the 10 long descriptions to ~155 chars.
  5. Replace the ComparisonTable node and re-test in the Rich Results tool.
  6. Add the 31 orphan pages to the sitemap (or noindex them), especially the 20 /services/* pages, and add the 5 missing og:images.
  7. Deepen /websites, /hosting and /restaurants/pos.
Nothing in the P1–P3 lists has been changed. This audit is read-only — the only code shipped was the 401 fix (robots.ts + next.config.ts, commit 922f09c).