ο Spring Hill KS, 66083
I work where marketing meets engineering: the tracking that shows what is working, the technical faults that quietly cost money, and the systems that keep running after the person who built them is gone. Selected work from a home-services client, over the last twelve months. No client is named on this page.
Impressions were high and clicks were not. Over a trailing ninety days the site was shown 315,407 times and earned 310 clicks, a click-through rate of about a tenth of one percent. Nothing on the site recorded a lead, so there was no way to tell a good month from a lucky one.
The bulk of it was consolidation rather than creation. Legacy location pages were folded into their service hubs behind 301 redirects, which removed a set of scaled doorway pages that were a genuine penalty risk while keeping their equity. A redirect audit separated the orphaned URLs that were already resolving correctly from the block that was deliberately left alone. Title tags and the internal link structure were rebuilt around what the business actually sells.
Average position 27.4 across the account, with 64 keywords already in the top three and 297 in the top ten, and the money cluster still on page three. This is one measurement, taken on 22 July 2026 over a trailing ninety days. It is a starting line and not a result, and it is quoted that way on purpose.
The site scored C, 55 out of 100, on Mozilla Observatory, passing 7 of 10 tests. The domain had no enforced email authentication, so anyone could spoof mail from it.
Worked the header stack one item at a time, each gated on a measurement first. The last step was removing the unsafe-eval relaxation from the Content Security Policy, which I tested by deploying a report-only copy alongside the live one and confirming zero violations across real page loads before enforcing it. For email I parsed 223 DMARC aggregate reports covering 12 to 19 August, confirmed every legitimate source was passing, and only then moved the policy to reject.
Observatory A+, 105 out of 100, 9 of 10 tests. The one remaining failure is Subresource Integrity, deliberately not used because the scripts are Google hosted and change without notice. DMARC now p=reject at 100 percent.
Bing spend looked like it produced almost nothing. A single lead in five months carried a Bing source, while GA4 recorded 112 paid Bing sessions and 16 paid Bing form starts on the contact page over the same period. Those two numbers could not both be true. GA4 only labels a session bing / ppc when the tracking tags are physically present in the address, because it does not infer paid Bing from a referrer and does not read the Microsoft click id, so those 112 sessions were arriving correctly tagged and something downstream was overwriting the label.
Ran one controlled test: arrived through a Bing-tagged link and watched what the lead record said. It came back google / cpc, carrying a campaign, keyword and ad id that had never been in the address. The cause was a guard clause in the tag that read an explicit source and then discarded it whenever a stored Google click id from the previous ninety days existed. A trailing branch existed to merge them but was unreachable.
Rewrote it so the newest tagged arrival wins and the stale click id is cleared along with its cookie. Verified on both hostnames before publishing. Shipped as three separately reversible versions so any one could be rolled back alone.
One tag was attached to two triggers: the contact form and the click-to-call button. Both wrote the same event name. That event is imported into Google Ads as the Primary conversion for form leads, so the number the bidding algorithm optimizes against was mostly phone taps.
Split them at the trigger rather than touching any Google Ads conversion tag, because those are what the bidding runs on. Proved the split in Tag Manager Preview on the live site: tapping a real call button fired the phone tags and did not fire the lead tag.
Once that day's analytics finalised, 9 of the 10 recorded leads were phone taps and 1 was a real form. Verified again on live traffic the following day: a genuine phone tap produced a call event and zero lead events, and the only lead recorded was a real form submission.
The AI receptionist treated returning customers as strangers, asking again for a name and address they had already given. Callers hung up.
Added a lookup against the CRM on caller id. It asks to confirm rather than asserting, because a phone number is a household and not a person. It refuses when one number maps to more than one customer, which is 154 numbers out of 5,717, and never reads an address aloud. Built the whole thing on a cloned shadow assistant with its own test number first, and only promoted it after a live call proved it.
On the proving call the lookup fired and the agent asked to confirm the caller's name at 3.8 seconds with no dead air.
The cloud server running the intelligence stack was switched off. The customer profile system, the attribution bridge and the reporting all lived on it, and three years of call transcripts existed nowhere else.
Rebuilt the customer profile generator against data already held locally rather than restoring the server. Kept the scoring, segmentation and pitch logic untouched and replaced only the data layer. Treated the historical transcripts as the thing that must survive and merged rather than replaced.
4,010 profiles with all 59 fields, and 4,016 call transcripts carried forward including 3,567 going back to 2023. A structural diff against the previous version ran before anything was saved.
Not everything I built was switched on. These are complete systems that exist on the site or in specification today, held back by budget or by a decision that was never taken rather than by anything technical. They are here because the foundation is the part that takes the skill, and because it explains why the traffic curve on this page is flat while the ranking curve is not.
A complete publishing system sits on the site today: styled article templates, automatic read-time calculation, a table of contents, search with autocomplete, archive and popular-post components, analytics events wired for every scroll and click, and the redirect map for the URL structure. It is switched on and running. What it has never been given is a content program.
A campaign system and a reactivation strategy built on top of the customer profile work: segmentation by recency, value and service history, with the message logic and the do-not-contact handling already specified. The audience exists and is loaded. The sends were never approved.
A paid membership plan with tier structure, pricing and the margin arithmetic worked through, written to be handed to an owner as a decision rather than a suggestion. It has not been launched.
An audit of business listings across directories, including the ones search surfaces that the usual tools miss, with the single highest-impact fix identified: an opening-hours conflict where the site schema says one thing and the public profile says another. Specified and queued, not executed.
The event layer that tells the ad platforms what a lead is. This one did ship, and then I found it was counting phone taps as form submissions and fixed it. The wider event plan beyond leads was never implemented.
Most of what follows was learned by getting something wrong first and writing down what would have caught it.
A script reporting success is not evidence. A file edit gets re-read, a tag gets checked in Preview, an endpoint gets curled, a deploy gets fetched from outside. Every claim in this portfolio was checked from somewhere other than where the change was made.
Every mistake gets recorded with what it cost and what check would have caught it, and that check gets automated. There are 82 entries, and the most recent one is about this document. This portfolio itself was scoped down twice because the data did not support the first version of a claim.
A zero over one day and a zero over thirty days are different claims. Most false alarms in analytics are a date range left on the wrong setting, and most fake discrepancies are two different populations being compared.
Version number, previous value, or the single command to reverse it, recorded in the same breath as shipping. Nothing goes live without a way back.