Back

Project · Web / Growth

Clarity Ad Landing Pages

The landing-page platform our paid search runs on - 13 pages from one template, mobile PageSpeed from ~52 to ~90, with brand voice and performance enforced as tests.

  • Next.js
  • TypeScript
  • Tailwind CSS
  • HubSpot
  • Core Web Vitals
  • Vercel

I run Clarity's paid search, and I built the pages those ads point at. On this project, the biggest engineering decisions were marketing decisions.

Live at get.clarityrcm.com.

Problem

Clarity runs Google Ads to independent dermatology practices. Every click costs money, and most of it was landing on slow, generic pages. Mobile PageSpeed sat around 52. For a lead-gen page, that number moves conversion directly. A 0.1-second mobile speed improvement has been shown to lift lead-gen conversion (Deloitte, Milliseconds Make Millions).

The deeper issue was ownership. The path from ad click to form submit was split across an agency, a marketer, and whoever could touch the CMS that week. No single person owned the whole thing, so the page speed, the copy, and the conversion number all drifted.

Solution

I built and own the landing-page platform our ad spend runs on. Thirteen live pages served from one template, deployed continuously, guarded by a test suite that checks both performance and brand voice on every push. The person buying the traffic also owns the system it lands on.

Approach

I engineered it like a product, not a marketing page.

One typed template renders every route. Adding a new landing page is a type-checked content object, not new React code. I can stand up a conquest page (clarity-vs-modmed, say) in the time it takes to write the copy, because the layout is solved once and the tests catch anything that breaks.

I built speed into the architecture from the start. Every tracking script (GA4, Google Ads, HubSpot, LinkedIn, about 677KB of third-party JavaScript) loads last, off the critical render path. That includes my own attribution. The instinct in marketing is to fire tracking first, because that's how you prove the campaign worked, but the page has to paint before anyone converts, so I did the opposite. The hero is text only, so the largest element on screen is an H1 that loads instantly, and I reserve space for the form so the layout never jumps. Mobile PageSpeed moved from about 52 to about 90.

I also turned the brand rules into tests. A deploy fails if a headline runs long, an em-dash slips in, a required trust stat goes missing, or a page drops below WCAG 2.1 AA. Brand drift on paid traffic becomes a failing build instead of a manual review I have to remember to run.

A few details I cared about: if HubSpot's form embed gets blocked by an ad blocker or a Safari content blocker, the prospect would normally see a blank box and leave, and that's a click I already paid for. So after nine seconds the page swaps in a first-party booking link, and I test it by deliberately aborting the request. I also wired up real-user field data instead of trusting the lab score, because PageSpeed numbers are noisy and the only phone that matters is the prospect's.

Results

  • Mobile PageSpeed moved from about 52 to about 90. Layout shift held at zero.
  • Thirteen live production routes from one template. No manual page duplication.
  • 23 automated tests across unit, end-to-end, accessibility, and visual regression. The brand-voice and performance gates run on every deploy.
  • Live on real ad traffic at get.clarityrcm.com, with a preview deploy on every pull request.

Stack: Next.js (static prerender), TypeScript, Tailwind, HubSpot forms, Playwright and Vitest for testing, deployed on Vercel.