Skip to content
Go back

I audited my Astro blog and here's what was broken

Published:  at  10:13 AM

My blog sat untouched for two months. Not the content (I was updating posts), but the actual site infrastructure. The HTML, the schema, the components. I assumed it was fine because it looked fine.

It was not fine.

I spent a weekend running a full source-level audit on kentgigger.com and found problems on almost every page. Some were embarrassing. Some were invisible to visitors but very visible to Google. A few were time bombs waiting to break things.

Here’s everything I found and fixed, grouped by severity.

Table of contents

Open Table of contents

The one-character bug that affected every page

My Card.astro component accepts a variant prop for rendering post titles as either <h2> or <h3>. The ternary that handles this? Both branches rendered <h2>. The h3 path was dead code.

// Before: both branches output h2. Oops.
{variant === "h2" ? <h2>...</h2> : <h2>...</h2>}

One character fix. But the impact cascaded across the entire site because every post card on every listing page was an <h2>, which meant my homepage went <h1> directly to <h2> (post titles) with no section headings in between. Google uses heading hierarchy to understand page structure, and mine was telling Google that every post title carried the same weight as the page sections.

The homepage had its own problem on top of this. “Featured,” “Recent Posts,” and “Tags” were all <h3> with no <h2> in sight. So the document outline was h1 > h3 > h2 (post cards). Completely backwards.

Fixed both. The homepage now has clean h1 > h2 > h3 structure. Took ten minutes, should have been caught months ago.

We’ll see if it makes a difference to Google. Moving the section titles to <h2> and the post titles to <h3> does make me a little nervous, but I’ll watch it. This blog is small enough that I doubt the algorithm will even notice. Famous last words.

I was lying to Google on every page

This one stung. Every page on the site (homepage, about, tags, search, 404) was emitting BlogPosting structured data with undefined dates and empty headlines. That’s not just wrong, it’s invalid schema on 20+ pages.

The fix: only emit BlogPosting on actual blog posts, and use WebSite schema everywhere else. Invalid structured data doesn’t necessarily trigger penalties, but it does get ignored. And if Google is ignoring your schema, you’re leaving rich results on the table.

The whole site is a blog, but it’s still a website in other areas, and I have plans to grow it. I’ll test it and see how the Google machine digests it all over time.

Dead affiliate infrastructure

My tech-stack page had affiliate disclaimers, (affiliate) labels, and eight tools with url: "#" placeholder links. None of the affiliate programs were active. I’d built out the infrastructure optimistically and then never followed through.

Here’s why this matters beyond looking sloppy: a page covered in affiliate markers with no actual affiliate links signals to Google that the page exists to monetize, not to inform. I stripped all of it (the affiliate property, the disclaimer banner, the labels) and kept the tools themselves. Clean page, honest intent.

I’ll add affiliates back when I actually have active partnerships. There’s a backlog item for it. For now, the page just lists what I use.

It’s mostly laziness, if I’m being real. I do have active partnerships, but I don’t post about them because I haven’t earned that yet. Here’s my rule: if I recommend something here, it’s because I use it. I’m not going to sell you gold shoes I wouldn’t wear myself.

The newsletter form nobody could use

The newsletter signup had multiple problems stacked on top of each other:

I rewrote it with proper accessible labels (screen-reader-only, so the visual design stays clean), removed the target blank, and added client-side fetch with inline states. “Subscribing…” while it works, “You’re in!” on success, and an actual error message with retry if something breaks.

I need to get better at the newsletter side of things too. I’m working on projects that don’t always become blog posts, and I think there’s interesting stuff worth sharing there. But I’m not going to lie: it’s hard to write here, get work done, and still have time for family, friends, and the side projects I’d actually like to finish someday. The newsletter is on the list. It’s a long list.

The invisible bug: tags inside a conditional

The Tags section on my homepage was nested inside a SOCIALS.length > 0 conditional block. As long as I had social links configured, it worked. If I ever removed social links? Tags would vanish from the homepage with no error, no warning, nothing.

This is the kind of bug you only find by reading the source. It rendered correctly, passed every visual check, and would have silently broken the moment I touched an unrelated config. Gotta love it!

Site description was claiming topics I don’t write about

My meta description mentioned “blockchain” and “affiliate marketing.” I have zero posts about blockchain. I have zero posts about affiliate marketing. Claiming topics you don’t cover confuses Google’s topical categorization of your site.

Old description was a list of categories. New one frames a perspective:

A builder’s notes on shipping software, ranking pages, and figuring out the rest.

The shift matters. Google evaluates topical authority per domain. A site that claims eight topics builds shallow authority in all of them. Framing a perspective instead of listing categories lets the content speak for itself.

I’d love to write about those topics down the road. Can’t get to everything. Part of the experiment with this site is trying to rank on Google without using AI-generated content. And let me tell you, that is hard. Google is changing so fast that I’m almost tempted to break my own rule. But I’m not there yet. I’m thinking about starting a separate site (I have more domains than finished projects) where AI helps with the content, and I can write about the process here. Keep the two clean.

About page images: no dimensions, no lazy loading

Six <img> tags on the about page with no width, height, or loading="lazy". All 1080x1350px images loading eagerly with no space reserved in the layout.

This causes CLS (Cumulative Layout Shift), which is a Core Web Vital. The browser doesn’t know how big the images are until they download, so the page reflows as each one loads. Added all three attributes. Quick fix, measurable impact on Lighthouse scores.

Pure laziness on my part. Nobody needs pictures of me on an about page, but I thought they were fun. I’m incredibly photogenic. (Don’t answer that.) Judge for yourself.

The content updates (GSC-driven)

The structural fixes above took maybe two hours. Then I turned to the content.

I pulled impression data from Google Search Console and cross-referenced it with what my posts actually said. My conversation history post has over 56,000 impressions and drives 85% of site traffic. Several of its claims were outdated. Features I’d said didn’t work now do. Commands I’d covered had been replaced by better ones.

I updated four posts total:

I also reviewed and updated my Claude Code workflow post with seventeen new technical claims verified against current documentation. I’m still the kind of person who reads docs. When your highest-traffic page is a reference guide, factual accuracy is the whole game. Read the docs, people. Don’t get lazy on me.

What I’m not fixing yet

I have a full prioritized list. Some things I’m leaving alone for now:

The audit wasn’t hard. Finding the time was.

None of these were hard fixes. The heading hierarchy bug was one character. The structured data fix was a conditional check. The affiliate cleanup was deleting code, not writing it.

The problem was never difficulty. It was attention. I was writing and updating content while the foundation underneath it was quietly rotting. A heading hierarchy bug on a post card component doesn’t show up in Lighthouse. Invalid structured data on your tag pages doesn’t break anything visible. But Google sees all of it. (Google sees everything. Close those incognito tabs.)

If you’re running an Astro blog (or any static site, really) and you haven’t looked at your source output in a while: do the audit. View source on your homepage. Check your structured data in Google’s Rich Results Test1. Run your heading hierarchy through an outline checker. You’ll find something. I found twenty things.

Footnotes

  1. Google Rich Results Test

New posts, shipping stories, and nerdy links straight to your inbox.

Real insights. Zero filler.



Next Post
Claude Code is still crushing it - My updated workflow