Skip to content
Healthcare Website build + Google Ads

A Practice Website and Its Ad Account, Cut Over Together

I rebuilt handandwristinstitute.com off WordPress and moved the Google Ads account onto it in the same week. 533 legacy URLs carried forward, two DNS records changed, mail never in the blast radius, and 276 live ad changes. Every figure here is one I checked myself against the live domain.

HEALTHCARE
A Practice Website and Its Ad Account, Cut Over Together
Conner Crowe

The numbers

Legacy URLs inventoried before the move
533
Sampled redirect rules correct after cutover
40 of 40
DNS records changed to move the site
2
Live Google Ads changes across two nights
276
A Practice Website and Its Ad Account, Cut Over Together: hero screenshot

02   The breakdown

What Is Live

handandwristinstitute.com runs on Astro, deployed to Netlify, in the practice’s own hosting account. Dr. John T. Knight is a hand and wrist surgeon with offices in the Dallas and Southlake area, and the oldest page on that domain was published in 2009. I rebuilt it and moved his Google Ads account onto it in the same week.

I checked the live domain again on 15 September 2026 while writing this. The apex answers 200 behind a Netlify server header and www 301s to it, the certificate covers both hostnames, the page declares itself indexable and canonical to the apex, and the four sitemaps list 332 URLs between them: 263 blog posts, 32 condition pages, 24 treatment pages and 13 site pages. All eight ad landing pages answer 200.

The thing I care about most isn’t in that list. His mail never moved.

The Two Records

The cutover changed exactly two rows in the DNS zone: the apex A record from the old WordPress host to Netlify’s load balancer, and the www CNAME to the Netlify hostname. The nameservers stayed where they were.

That constraint is the whole design. A practice runs on its email. Patients reply to appointment confirmations, billing goes back and forth, and the referral chain lives in an inbox. Moving nameservers to a new provider means re-creating the entire zone by hand at the moment you’re least able to check it, and a transcription error in an MX record is mail that silently stops. Keeping the zone in place meant the mail path was never inside the blast radius. MX, SPF, both DKIM keys and DMARC came through the move byte for byte, and I verified them after cutover rather than assuming them.

A rollback path stayed available through the cutover window, reachable by changing one record back. I haven’t needed it.

The Address Book

The old site had 533 URLs. I crawled and inventoried every one of them before anything was built: status, final URL, title, description, H1, word count, canonical, whether it was indexable, whether it was in the sitemap. That file is what the new site was fitted to.

Most of the value on a site like this one sits in pages nobody would think to protect. 348 of those URLs are blog posts, many written years ago, and a good share of the practice’s inbound demand arrives through them. A rebuild that quietly drops a hundred old post URLs doesn’t announce itself. It shows up two months later as a decline someone blames on the season.

After cutover I sampled 40 legacy redirect rules against the live domain and checked both the status code and the target. All 40 matched. The forced media redirects land on the preserved originals, so old image URLs embedded in other people’s pages still resolve.

Redirects That Keep the Query String

This check mattered more than the redirect map itself, and I’d run it on any migration.

A redirect can return a correct 301 to a correct destination and still destroy your advertising measurement, because it drops everything after the question mark. The gclid Google appends to every ad click lives there. Strip it and the click still lands, the visitor still reads the page, the form still submits, and the conversion comes back to Google attached to nothing.

Five redirects were doing exactly that on this account, sitting under about a quarter of its paid clicks. They passed every standard check, because every one of them returned a 200 at the end.

So the cutover script refuses to repoint a single ad until each destination returns 200 and demonstrably preserves the query string. I re-ran that check by hand for this writeup:

curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" \
  "https://handandwristinstitute.com/blog/arthritis-hand-doctor/?gclid=TEST&utm_source=google&utm_medium=cpc"

301 -> https://handandwristinstitute.com/arthritis-hand-doctor/?gclid=TEST&utm_source=google&utm_medium=cpc

The parameters survive the hop. The landing pages answer 200 with them intact. The gate is cheap enough that there’s no excuse for skipping it. I’ve written up the failure mode in full in A 200 Is Not Proof, and it sits at the identity layer of The Tracking Stack.

The Ad Account

276 live changes went into the Google Ads account across two nights, and they were two different jobs.

The first night was structure, before the site moved. 166 phrase negatives went into a new shared set across all eight campaigns. 30 exact keywords went in, 11 of which needed a personalized-ads policy exemption because healthcare terms trip it. Two campaigns, two ad groups and six keywords came out. 16 new responsive search ads went in so all 11 enabled ad groups sit at Google’s cap of three enabled ads each, where seven of the eleven had been running on a single ad. Seven callouts went on at account level and eight structured snippets at campaign level, where there had been nothing campaign-specific. Nothing was disapproved.

The second night was destination, after the site was live. 24 ads across eight ad groups moved off old blog posts, most of them a decade old, and onto seven of the new landing pages. Six sitelinks went on per ad group, each anchored into the same page its ads land on: booking, insurance, locations, the surgeon’s bio, reviews, and what to expect at a first visit. Nine ad groups took them, across eight destinations, one of which is the home page rather than a landing page. 48 assets serve 54 links, because an asset is reused wherever two ad groups send traffic to the same place.

Those sitelinks are scoped to the ad group, never the campaign, and that was deliberate. One campaign here spans three separate conditions with three separate landing pages. Campaign-level sitelinks would have pointed a third of that traffic at the wrong page and undone the landing page they were meant to support. The script refuses to run if any ad group’s sitelink destination disagrees with where its own ads land.

Two anchors were left off on purpose. Informational intent in this account runs many times the cost per conversion of booking intent, and a sitelink is a chance to move somebody toward an appointment rather than toward more reading.

The 51% I Didn’t Move

Two ad groups carry 51% of the conversions in this account. Both still point at the site root. I left them there.

The thirty days before cutover show a roughly tenfold spread in conversion rate by destination inside one account. The two ad groups pointing at the site root converted at 11.76% and 11.06%. The ad groups pointing at old blog posts converted at 0.88% and 1.11%, with a condition page at 8.65%. That spread made repointing the eight blog-post ad groups an easy call and made these two a completely different question.

The root those two point at is now the new home page. Their 11% was earned on the old one, so their baseline was already invalidated the moment the site went live, whether or not I touched them. Moving them in the same week would stack a second untested change on top of a first untested change, on half the account’s conversions, and leave nothing readable afterwards.

The eight ad groups I did move were the account’s worst destinations, so they’re a free natural experiment. There’s nothing below a 0.88% conversion rate to lose, and they give me direct evidence on whether these landing pages convert before I go anywhere near the 51%.

The decision rule is written into the readout script rather than left to my judgment in three weeks. Once roughly 300 clicks have accumulated across the moved set, a conversion rate clearly above 11% moves the two held ad groups, 8 to 11% runs them as a 50/50 experiment, and clearly below 8% leaves them where they are. The reasoning is in The 51% I Didn’t Move.

What Went Wrong

The first build published on launch night was made with the wrong command, and it was broken for about an hour before I caught it and repaired it. Every page rendered. Underneath, the site search reported itself unavailable, two generated files the site links to from its own pages returned 404, and a build variable the bundler never saw had left a feature inert.

Three more traps fired the same night, all of the same species: environment variables that are session-local, a config file that quietly outranks a shell variable, and a host that rebuilt the artifact instead of publishing the one I had checked. None of them produced a page that looked wrong.

What came out of it is a deploy script that’s now the only way this site ships. It runs the full build lifecycle rather than the framework alone, gates the artifact before it moves, publishes exactly what was gated, and then interrogates the live domain afterwards, including checking that the mail records still resolve to the mail host. The whole account of it is in Four Ways a Site Launch Lies to You, and the migration-specific version, about a corpus that AI assistants already cite, is in Migrating a Site That AI Assistants Already Cite.

What I Did Not Claim

This page carries no performance result.

The site went live on 15 September 2026 and the ad cutover finished the same day. There’s no post-cutover conversion data yet, and the two held ad groups exist precisely so there’ll be something clean to read later. Any lift figure I published this week would be a number I made up.

I also haven’t claimed rankings improved or that leads went up. I haven’t measured either on the new site. What I can show is the work and the checks: 533 URLs inventoried, 40 of 40 sampled rules correct, two DNS records, mail verified unchanged after the fact, query strings preserved through every redirect an ad touches, and 276 account changes with no disapprovals.

The value-per-patient model behind the bidding work is deliberately running at count only, with no revenue value attached to any conversion, until the booking rate has been measured against the practice’s own intake records. A scored call isn’t a booked patient, and I would rather bid on nothing than bid on a number I assumed.

When the readout has its 300 clicks, I’ll publish what it says, including if it says the landing pages lost.

Ready to talk

Want this kind of breakdown on your account?

Thirty minutes on the phone. One clear set of next steps. Same person on the call as on the work.