We sell audits. So before pointing this site at a domain, we ran the same audit on it that we'd run on a client's, on the assumption that anything we'd flag for them we should have to fix for ourselves.
It found nine things. Some were embarrassing. Here they all are.
1. Every page had an empty <head>#
Thirteen pages. Not one canonical tag, not one Open Graph tag, no structured data, no favicon.
The practical effect: sharing any page to WhatsApp or LinkedIn produced a blank grey card. For a studio that sells SEO, this is the first thing a careful prospect would check, and it would have told them something true and unflattering.
Fixed with canonicals, full OG and Twitter card sets, and structured data throughout — Organization and WebSite on the homepage, WebPage and BreadcrumbList everywhere, Service on the service pages, and FAQPage generated from the actual <details> markup rather than hand-written.
That last detail matters more than it sounds. Hand-written FAQ schema drifts from the visible copy the first time someone edits a question and forgets the JSON-LD. Generating it from the DOM means it cannot drift.
2. The contact form discarded every submission#
action="#", and JavaScript calling preventDefault() unconditionally on submit. The visitor saw "Got it — we'll get back to you shortly." Nothing was sent. Nothing was stored.
Every CTA on the site pointed at this form.
The replacement is a PHP handler with four layers of spam defence, cheapest first:
- Honeypot — a field hidden off-screen and from assistive tech. Humans never see it, bots fill it. Notably not
display: none, because a good number of bots skip those. - Time trap — anything submitted within three seconds of page render is a script.
- Origin check, plus a CSRF token on the JavaScript path.
- Rate limit — five per IP per hour, file-backed sliding window.
Two decisions in there worth explaining. Bots that trip the honeypot or time trap get a success response — telling a bot it failed only teaches it to try differently. And every valid submission is written to disk before the send is attempted, because mail() fails silently more often than people expect and a lead should never depend on it.
3. Two colours failed WCAG AA#
Our accent orange, #D9480F, gives 3.81:1 against the paper background. AA for normal text needs 4.5:1. It was being used on eyebrow labels, badges, card numbers and links — all small text. The primary button label came in at 4.08:1. Also a fail.
The fix is one most brands should copy: split the accent into two tokens.
--accent: #D9480F; /* fills, borders — 3:1 is the bar for UI */
--accent-text: #A8330A; /* anything that is actually text — 5.93:1 */
Buttons, borders and fills keep the brighter orange. Text uses the darker one. Side by side the difference is barely perceptible, and the identity is unchanged — but one passes and one doesn't.
New numbers: eyebrows and links 5.93:1, button labels 5.76:1, button hover 8.30:1.
4. An ARIA role that made things worse#
The comparison table was a <div role="table"> with no role="row" or role="cell" descendants.
A screen reader announces a table, the user navigates in expecting rows and columns, and finds nothing. That's worse than no role at all — the plain <div> would at least have been read as ordinary content.
Removed. If it needs to be a table, it should be a <table>.
5. Fonts loading from Google#
Three families from fonts.googleapis.com: two DNS lookups, two TLS handshakes, a render-blocking stylesheet, then the font files.
Now self-hosted, subset to Latin, woff2. Fraunces is a variable font with SOFT and WONK axes we don't use — instancing those out took it from 125 KB to 69 KB. All weights of all three families now come to 206 KB, cached for a year.
Three wins from one change: LCP improves, the GDPR question about sending EU visitors' IPs to Google disappears, and the CSP can drop to default-src 'self' because nothing is third-party any more.
6. Six pages carried a fake phone number#
+1 (555) 013-4471, in a tel: link, on every niche page. A placeholder from the original build that would have shipped.
Removed rather than replaced, with a TODO(NAP) comment at each site. Nothing fake ships — and when the real number goes in, it needs identical formatting across the site, the Google Business Profile and every citation, because NAP mismatch quietly costs local rankings.
7. The audience pages were 18% identical#
Six landing pages, one per audience. Three of their seven sections were byte-identical across all six.
Measured as shared 6-grams: 18.3% mean overlap between pages, 34.7% at the worst pair. That's the pattern that makes a set of landing pages read as templated doorway pages rather than six pages that each earned their place.
Rewriting the shared sections in each audience's own language — "patients" for clinics, "AOV" for e-commerce, "your margin" for agencies — brought it to 7.5% mean, 18.1% worst.
The lesson generalises: if you're spinning up landing pages per audience, the shared boilerplate is the part that decides whether they rank. Write it six times.
8. One animation escaped the motion gate#
Every animation on the site was correctly wrapped in prefers-reduced-motion: no-preference. Except one:
html { scroll-behavior: smooth; }
Sitting in the global scope, applying to everyone. For people with vestibular disorders, smooth-scrolling a long page is exactly the thing the preference exists to prevent.
Moved inside the gate. Thirty seconds of work, and the kind of thing that survives every review because it doesn't look like an animation.
9. We claimed a product we couldn't prove#
The proof section listed two in-house plugins as Shipped · In-house product. One, Quantivs Testimonials, is live on wordpress.org. The other isn't published anywhere a prospect could find it.
On a site whose stated position is "no invented numbers, ever" and "we don't pitch what we don't do ourselves", that's the one item on this list that mattered most — and it's the one no automated tool would have caught. It's exactly the claim a careful buyer verifies.
The unpublished one is now marked In development. The published one is linked, because a claim you can check is worth more than a claim you can't.
What this cost#
About a day, most of it on the content rewrite in item 7. The technical fixes were a few hours.
The uncomfortable part is that eight of these nine are things we'd have flagged in a client audit within the first hour. They existed on our own site because nobody had run the audit — which is, more or less, why every site that has these problems has them.
If you want the same list for yours: we do site audits, and the first scope call is free.