VibeFlow Marketing logoVibeFlow Marketing
← All posts
·4 min read·by Liz Kintzele

I Built an SEO Agent and Made It Audit My Own Site

I built an SEO agent and made it audit my own site. Real fixes, fabricated stats, and the moment I realized the tool was fine — the eyes were broken.

Share𝕏Share on XLinkedIn

I built VibeFlow's SEO agent — the evaluate_on_page and evaluate_technical subtypes that crawl a live site and spit back specific, actionable fixes. To prove it worked, I ran it against vibeflow.marketing.

It caught real wins. It also hallucinated. The hallucinations taught me more than the wins.

The Four Gaps I Actually Missed

The agent flagged a self-referencing canonical URL that didn't exist. It was right. I fixed it using Next.js 16's metadata API in about two minutes.

Missing JSON-LD structured data for Organization and SoftwareApplication. Right again. I added inline JSON-LD with three real Offer entries — Free tier at $0, Launch Kit at $49.99, Annual at $99.99. I deliberately did not invent an aggregateRating or claim "trusted by X founders" because Google's structured-data guidelines tank your trust score if a crawler catches you lying, and crawlers always catch you.

No /robots.txt. Correct.

No /sitemap.xml. Also correct.

All four fixed in forty minutes using Next.js file conventions and the metadata API. The agent had delivered actual value.

The Confident Lies

Then it kept going. The same audit told me my H1 was missing. It wasn't. My H1 is the tagline at the top of the page: "One prompt. Full campaign. Always on-brand." The agent insisted it didn't exist.

It also claimed I had zero H2s. I have six.

Then it suggested a rewrite: "Join 500+ Founders Shipping Campaigns Faster."

I have not shipped to 500 founders. I haven't shipped to anyone yet — VibeFlow is pre-launch, and the agent had no idea. It pattern-matched its way to the default shape of every indie SaaS site on the internet and called it an optimization.

That's when I got curious about why.

Why the Parser Breaks

The agent fetches the page, scrapes it, and looks for semantic HTML. But it was using regex to find H1 tags.

Regex is not an HTML parser. Regex squints at text and matches patterns. My H1 wraps two color-styled spans with a line break in the middle:

<h1>One prompt. <span style="color:#05AD98">Full campaign.</span><br /><span style="color:#878787">Always on-brand.</span></h1>

Regex tries to capture everything between <h1> and </h1>. With nested tags, inline styles, and minified attributes — what Next.js actually serves to a crawler in production — it gives up or returns garbage. Real parsers walk the tree as a DOM. They don't pattern-match against strings.

When an LLM sees a summary that says "H1: NOT FOUND," it has no way to tell whether the data was wrong or the page was wrong. So it fills the gap. And the gap it fills is always the same shape — social proof, usage numbers, trust signals. The kind of language that's indistinguishable from every competitor's homepage, because that's the pattern it learned.

The agent wasn't being dumb. It was being confidently incomplete. It had bad signal, so it synthesized signal.

The Fix Came Down to Three Changes

I swapped the regex parser for cheerio, the Node.js implementation of jQuery. It's what everyone uses. It actually walks the HTML tree as a DOM instead of pattern-matching against strings. Nested tags, quoted attributes, void elements, malformed markup — cheerio handles all of it.

Then I expanded what the agent can see. It now gets html lang, viewport, meta robots, hreflang count, image alt coverage (I found three missing alt texts out of twelve), and parsed @type values from JSON-LD instead of a yes/no boolean. More signal. Better recommendations.

Last, I added confidence diagnostics. If the parser finds zero H1s but the raw HTML still contains the substring <h1, the agent now hedges: "H1 may be present — verify in view source." It doesn't assert. It flags uncertainty. Same with SPA detection and malformed structured data.

The agent went from confidently wrong to usefully cautious.

The Actual Lesson

I spent hours on the parser problem because I assumed the agent needed to be smarter. It didn't. The agent was fine. The tool feeding the agent was broken.

Here's the thing about LLMs: they're pattern-matching engines. They're great at structure — taking vague input and turning it into coherent output. They're awful at fact verification when the source is weak. Feed them bad data, and they'll hallucinate in the shape of whatever pattern they've memorized. Feed them good data, and they'll structure it into something useful.

A human asking "is this actually true?" is the difference between a tool that saves you time and one that confidently wastes it.

The fix wasn't about making the agent more aggressive or more skeptical. It was about making the scanner more precise. Better input means better output.


The agent didn't lie. It had bad eyes. Fix the eyes, the agent gets honest.

Postscript: After fixing the scanner I went a step further and built a new audit mode specifically for AI search readiness — separate from classic SEO ranking signals. Google's AI Overviews are a different scoreboard. The work is in Google Rewired Search. Here's What I Shipped in Five Days. and the receipt (Google's AI Mode now citing VibeFlow) is in Google's AI Mode Cited VibeFlow. The same lesson — the agent's not lying, we just gave it better eyes — got generalized into Fact Guard, the trust feature that runs on every generation across every agent.

Found this useful? Share it.
Share𝕏Share on XLinkedIn

Ship marketing as fast as you ship code.

VibeFlow turns one prompt into a full launch — content, social, SEO, ads, ASO, email. Free to try.

Start free →