WB × The Multiplier / AI in the studio

Case study

How I Rebuilt My Own Studio Site’s SEO in a Day With Claude Code (and What Was Broken)

A Next.js site launched in 2025, an honest audit, four commits, and a build that now refuses to ship the mistakes it found.

By Weston BeckwithUpdated 9 min read

Grey cables rising from a tangle on the floor into a neat, teal-lit patch panel.
Illustration for WBX Creative

On the morning of September 22, 2026, wbxcreative.com had no robots.txt, no sitemap, no canonical tags, no structured data, no Open Graph image, 194 MB of raw portfolio exports behind plain img tags, and seven of its 16 public pages sharing one title and description. By that evening it had every missing piece, the portfolio and images folders had gone from 216 MB to 42 MB, and a build step fails the deploy if any of it goes missing again. Four commits, one working day, Claude Code doing most of the typing and me reading every diff.

The rest is the audit that found the problems, the order I fixed them in, and where the agent needed a person in the chair. The Next.js SEO checklist covers how each fix works in the App Router.

What was broken?

WBX Creative is a one-person studio in Cape Coral, Florida: branding, web, marketing, wraps, print, CRM and ERP work, and AI systems. The site launched on Next.js in 2025 and does more than a brochure. The CRM lives at /admin on Supabase, and the portfolio holds 185 pieces across eight categories. I built it myself and shipped it with search on the later list.

Later was September 22, 2026. The audit ran against the live HTML, not the source, because a crawler never sees the source. It found:

  • robots.txt and sitemap.xml both returned 404.
  • No canonical tag on any page, no JSON-LD anywhere, no og:image, and a text-only summary Twitter card.
  • Seven of 16 public routes sharing the root title and description: Home, About, Contact, Pricing, Specials, Payment, and Portfolio. Each was a "use client" page with no metadata export, so Next used the layout's.
  • A homepage H1 that was the animated "WB × Branding" word cycle, and my name nowhere on the homepage.
  • @vercel/analytics installed and never rendered, no GA4 or Tag Manager, Search Console status unknown. A site: query surfaced the About page and a subdomain.
  • 194 MB of raw JPG and PNG exports in public/portfolio, the largest 13 MB, served through plain img tags with the next/image lint rule switched off. Zero of the 185 portfolio items had a description.
  • 42 Windows Zone.Identifier junk files in public/, and about 150 lines of uncommitted CRM changes in the working tree.
  • No performance baseline. PageSpeed's shared API quota was exhausted and the local Chromium was a snap stub, so there is no before score, and I will not invent an after.

None of it was hidden. It was the cost of shipping a site and never reading its output the way a crawler does.

How did I fix it?

I had tried to fix this site with AI-assisted automation once before. In January 2025 I asked for five optimization phases at once, ESLint and SEO files, a next/image migration, Framer Motion everywhere, structured data, and performance work, across more than ten files. The result was malformed JSX, extra closing tags, orphaned components, each fix compounding the last. I reverted everything and wrote down the lesson: one type of change at a time, build after every change, commit working states, no broad automation across many files.

The 2026 rebuild was that lesson applied, with Claude Code (Fable 5.1) as the agent. Anthropic describes the tool as one that "reads your codebase, edits files, runs commands, and integrates with your development tools," which is exactly the set of things you do not want happening across ten files at once.

  1. Audit against the output, in writing. Fetch /robots.txt and /sitemap.xml. View source on every route for a canonical, a JSON-LD block, and an og:image. Run the site: query. Grep the page.tsx files for "use client". Measure public/ on disk.
  2. One identity file. Name, legal name, phone, email, city, logo paths, social profiles, my bio URL, the public routes, and the routes that must never be indexed, in lib/site.ts, which every later phase imports.
  3. One branch per phase, one kind of change per commit. Metadata first: app/robots.ts, app/sitemap.ts, metadataBase, a title template, and a canonical on every route. Then the client-page split, eight pages turned into a server page.tsx with metadata wrapping a client component. Then lib/seo.ts, seven JSON-LD builders emitted as one graph on every page, plus a default Open Graph card from next/og and a real homepage H1 with my name in it. Then images: sources capped at 1,600 px with sharp, next/image for heroes and galleries, and a portfolio grid that server-renders every item so the titles are crawlable. Then noindex on four utility routes and an X-Robots-Tag header on /admin and /api. Then the gate. Then a Person page for me with ProfilePage schema, and an IndexNow key with a submission script.
  4. Build after every batch, with the gate in the build. npm run build now runs next build and then the gate, so a broken phase cannot merge. Before each merge I read the prerendered HTML under .next/server/app, then fast-forwarded to main.

Where the agent needed a person

  • Sequencing. The agent would have done all seven phases in one pass if asked. The order above is a human decision. The opinion piece on what Claude Code changes has the longer argument.
  • Judgment calls that look like config. Whether the sitemap carries a lastmod (only where a page has a real date, since Google uses the field only when it is consistently accurate). Which routes get noindex. Whether my name belongs in the homepage H1. None of these has a correct default.
  • Reading the output, not the intent. The metadata exports looked right in the JSX in January 2025 too. What matters is the HTML the build writes, so that is what I read before every merge and what the gate reads on every build.
  • Declining to invent a number. PageSpeed could not run that day. Publishing file sizes and no scores is not a decision an agent makes.
  • The working tree. About 150 lines of uncommitted CRM changes were sitting there before the first branch. Not an SEO finding, but exactly what an agent sweeps into an unrelated commit if nobody looks first.

What changed?

Morning of September 22, 2026Evening of September 22, 2026
robots.txt404Generated by app/robots.ts; disallows /admin and /api/, points at the sitemap
sitemap.xml404Generated by app/sitemap.ts; lastModified only on dated posts
Canonical tagsNoneOne per route, resolved against metadataBase
Unique titlesSeven of 16 public routes shared the root titleEvery route has its own; the eight client pages split into server wrappers
JSON-LDNoneOrganization, Person, and WebSite on every page; WebPage, Breadcrumb, FAQ, Article, and ProfilePage where they apply
Open Graph imageNone; Twitter card summaryDefault card from next/og on every route
Homepage H1Animated "WB × Branding" word cycleA sentence with the studio's name and mine
NoindexNoneFour utility routes by metadata; /admin and /api by header
Images194 MB of raw portfolio exports through plain img221 files capped at 1,600 px, 216 MB to 42 MB, next/image for heroes and galleries
Portfolio gridRendered client-side; empty to a crawlerServer-rendered; every title in the HTML
Build checkNonescripts/gate.mjs inside npm run build; 23 pages, 0 failures

The portfolio and images folders went from 216 MB to 42 MB of JPG and PNG across 221 files, 215 of them rewritten. The same folders hold about 35 MB of MP4 hero video and PDF menus that were not touched, so du on the two folders reads about 80 MB. The image piece has the method.

The gate is what keeps the day from being undone. Ported from the one WBX Creative built for The Outpost, a programmatic SEO publication for Power Lodge Florida, it walks every HTML file under .next/server/app after the build and fails on thin pages, placeholders, orphans, broken links or images, missing metadata, duplicate titles, bad JSON-LD, a noindexed page in the sitemap, or a missing robots or sitemap file. There is no bypass flag. Its first green run covered 23 pages with zero failures, and the Vercel production build of commit 945b187 ran it in CI and passed.

Two things did not change that day. Analytics: @vercel/analytics was still unrendered and there was no GA4 or Tag Manager when the four commits landed; that is its own setup. And the portfolio data: zero of 185 items had a description on the 22nd. On the 23rd, three agents captioned every item from the artwork and found 59 titles naming the wrong client, medium, or vehicle, plus three duplicates, all fixed the same day. The data behind a portfolio drifts unless someone looks at every image.

What I would do differently

  • Audit before launch. Everything in the audit above was visible in view-source on launch day in 2025.
  • Never silence a lint rule to make a warning stop. The no-img-element rule was off. What it would have flagged was 194 MB of unsized images.
  • Get a measurement baseline before touching anything. I can show file sizes and cannot show a Core Web Vitals delta.
  • Wire Search Console and analytics on day one. "Status unknown" is the worst state, because you cannot tell whether any fix worked.
  • Write the gate first. Most of the findings above are now a failing check. With the gate in place in 2025, the site could not have shipped as it was.

Stack

Next.js 15.4.8 on the day, bumped to 15.5.26 on September 23 for the out-of-band security patch; 16.3.6 is current as of September 2026 and the upgrade is planned before Next 15 leaves maintenance on October 21, 2026. React 19.1, TypeScript 5, Tailwind CSS 3.4, sharp for the image cap, next/og for the cards, Supabase behind the CRM, Vercel with Git integration, Cloudflare DNS, GitHub. The agent was Claude Code with Fable 5.1 (the tool's current release as of September 22, 2026 is 2.1.280). Commits 2978e4e, 945b187, edade4b, and ca18ae4 on main.

If your site was built with the same plan I had, search later, the technical services page is where a retrofit starts. Send the URL first. The audit is the cheap part.

Want the same audit on your site?

Send the URL. I will tell you what a crawler sees before we talk about anything else.

Start a conversation

Questions people ask

Can Claude Code do technical SEO on a Next.js site?
Yes, for the mechanical part: metadata exports, robots and sitemap files, JSON-LD builders, image components, and a build gate. On wbxcreative.com it did most of that typing in one day. It cannot decide what should be indexed, what a page is about, or whether a number is true. Those decisions were mine, and so was reading every diff.
Why did seven pages on my Next.js site have the same title?
Because they were client components. A page.tsx that starts with "use client" cannot export metadata, and Next.js falls back to the metadata of the nearest layout. The fix is to keep page.tsx on the server, export metadata there, and move the interactive code into a child component. Eight pages on my site went through that split.
How long does a technical SEO fix take on a small site?
The SEO layer of my 16-page studio site took one working day on September 22, 2026, with an agent typing and me reviewing, and shipped in four commits. The portfolio captions and analytics were separate work. A site with more routes or a custom CMS takes longer, mostly in the review, not the typing.
What is a build gate for SEO?
A script that runs after the build, parses the prerendered HTML of every page, and fails the deploy if anything required is missing: a title, description, canonical, og:image, one H1, valid JSON-LD, a robots.txt and sitemap, no thin pages, no broken links. Mine has no bypass flag. The first green run covered 23 pages with zero failures.
Did the rebuild improve rankings?
I do not know yet, and I will not guess. No performance baseline could be measured that day, and search results take weeks to reflect a change. What I can say is that every page now has its own title, canonical, and schema, and Search Console can tell me page by page whether Google fetched and indexed them as intended.

Sources

Keep reading