My site was invisible to search engines. Here is every SEO fix I shipped in one session.
robots.txt was missing. The homepage had no metadata. The OG image 404'd after what looked like a clean deploy
Field Note #004 was the research. This one is the implementation.
I knew going in that the SEO was broken. robots.txt missing, OG image pointing to a 512x512 favicon, homepage with no metadata at all. The audit at the start of this session confirmed it was worse than I thought.
Seven problems. One Claude Code session. Here is what actually happened.
The audit
Before writing a single line of code, I had Claude Code read every relevant file and report back. The full picture:
No robots.txt. Not broken — gone. Crawlers hitting the site got zero guidance and no pointer to the sitemap.
Homepage had no generateMetadata() at all. The most important page was inheriting generic layout defaults, including generator: 'v0.app' — still wearing the scaffolding tag for four Field Notes in.
The Contentful SEO fields — robotsNoIndex, robotsNoFollow — were being fetched correctly, parsed correctly, and then completely ignored. The CMS toggle did nothing.
No canonical URLs anywhere. No Twitter/X card metadata. The /notes and /tools pages had titles but no OpenGraph block. defaultSeo from GlobalSettings was fetched on every request and consumed by zero pages.
The data layer was solid. The consumption layer was empty.
The fixes
Six files. One build. No errors.
Created app/robots.ts. Wired generateMetadata() into app/page.tsx pulling from Contentful with fallbacks. Added canonical URLs to every page. Fixed the OG image from a bare string to a proper object with width, height, and alt text. Wired robotsNoIndex and robotsNoFollow so Contentful actually controls them. Added publishedTime to article pages. Added Twitter card metadata to the root layout.
The build passed clean. Forty minutes of work.
The deployment
Then it got interesting.
PR merged. Vercel deployed. fieldnotes-ai.com/og-default.png returned 404.
The file was committed, tracked by git, 45KB, valid PNG. Everything looked fine. It took git ls-tree HEAD public/ to find the actual problem: the image existed on the feature branch but not in main's history. The squash merge collapsed all commits into one — and the OG image had been committed separately, after the PR was created. It fell through the gap silently.
No error. No warning. Just a missing file in production.
The fix was one command. The diagnosis was twenty minutes of staring at git output wondering why a committed file did not exist.
Current state
robots.txt: working. Sitemap: generating correctly. Canonical URLs: on every page. Homepage metadata: pulling from Contentful. OG tags: complete on every route. Default OG image: live.
Next session is dynamic OG image generation with @vercel/og. Each Field Note gets its own social card with the title, dek, and author photo generated at the edge. Worth doing properly.
What it cost
$13.41. 20 million tokens, mostly cache reads. The audit prompt, six fix prompts, a build verification, and more git debugging than I would like to admit.