๏ Spring Hill KS, 66083
Copywriting
SEO Optimization
Social Media Marketing
Web Design
Three projects, each written in full with the question, the data, the method and the result.
EPA Fuel Economy
41,837 rows
Data cleaning and regression across 20 columns and four decades of vehicles. A routine cleaning rule would have deleted every row.
Iris Species Comparison
8 visuals
A Power BI report with cross-filtering slicers and an authored theme, built so every visual stays honest when the reader filters it.
HR Attrition Dashboard
9 tabs
A Google Sheets dashboard tracking termination and retirement attrition against 25% and 10% targets, with protected sheets.
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 Kansas City home-services client, over the last twelve months.
๐ Every number on this page can be checked. The ranking figures come from the Google Search Console API, the security grades from Mozilla Observatory and a live DNS lookup anyone can repeat, and the engineering work from a dated ledger with the verification attached to each entry. Where the data did not support a claim, the claim is not here. There is no traffic growth headline on this page, because the honest series does not show one.
60% better ranking ยท CTR 2.2ร ยท clicks +25% on 42% fewer impressions
Average position sat at 54.8, which is page six of the results. Impressions were high and worthless: 196,183 in a single month producing 217 clicks, a click-through rate of 0.11 percent.
The bulk of it was consolidation rather than creation. 41 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 found 129 orphaned URLs already resolving correctly and a further block deliberately left alone. Alongside that, title tags and the internal link structure were rebuilt around what the business actually sells. The strategy was deliberately to shed impressions that were never going to convert.
Average position 54.8 to 22.0. Clicks 217 to 271, up 25 percent, while impressions fell 42 percent from 196,183 to 112,784. Click-through rate went from 0.111 percent to 0.240 percent, more than double.
๐ How it can be checked: Google Search Console API, monthly, August 2025 through July 2026. The chart above is that series, unedited.
Mozilla Observatory C 55/100 โ A+ 105/100 ยท DMARC none โ reject
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.
๐ How it can be checked: Verifiable from outside right now: the live response headers carry HSTS with includeSubDomains, a per-request CSP nonce with no unsafe-inline and no unsafe-eval, and a DNS lookup of the client domain's _dmarc record returns p=reject.
Present since March, invisible until one deliberate test
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.
๐ How it can be checked: Recorded in the ledger with the before and after tested in the same browser on the same day. I also measured the historical damage honestly and revised my own first estimate down: 66 real lead emails since March, best estimate ten to fifteen mislabelled, stated as an estimate rather than a measurement.
On the day it was found, 9 of 10 recorded leads were phone taps
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 optimises 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.
๐ How it can be checked: Before and after read out of Tag Manager version history, so both states are on the record rather than asserted. Rollback is republishing the previous version.
Answers the real business line ยท confirms identity in 3.8 seconds
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.
๐ How it can be checked: Promotion recorded with a configuration hash before and after, and a one command rollback documented alongside it.
4,010 customer profiles rebuilt ยท 3,567 historical transcripts preserved
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.
๐ How it can be checked: Verifier exit code zero, with profile count, field count and transcript count all checked against the prior file rather than eyeballed.
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.
โ๏ธ Blog engine
2,517 lines across 9 snippets, all live
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 programme.
๐ง Email and reactivation programme
designed against a real 4,010 profile base
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.
๐ฐ Membership programme
pricing, tiers and economics modelled
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.
๐ Citation and local listing correction
gaps identified, fixes specified
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.
๐ Conversion event architecture
built, and then corrected
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.
๐ก The pattern worth noticing: the work that shipped is measurable and improved. The work that did not ship is built and ready. Neither of those is a story about effort, they are stories about which decisions got made.
Most of what follows was learned by getting something wrong first and writing down what would have caught it.
๐งญ The tool that made the change never confirms 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.
๐ A written correction log, not just a win log
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.
๐ Numbers carry their window and their source
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.
โฉ๏ธ The undo is written before the change
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.
๐ The work is documented, not just described. Alongside the results above sits a 2,233 entry engineering ledger, reference documentation for twelve platforms written from live systems rather than vendor pages, and a teaching cookbook that maps every piece of code running on the site function by function, so the next person does not have to reverse engineer it.
MS, University of Tennessee, 2016
Google Search Console API
ranking and click series
GA4 Data API
sessions and lead events
Mozilla Observatory
security grade
Security Headers
and a live DNS TXT lookup
Engineering ledger, 2,233 entries
Code cookbook, function by function
Platform documentation, twelve systems
Full work package index
Robert N. Dove ยท compiled 23 August 2026 ยท every figure traces to Search Console, GA4, live headers, live DNS or a dated ledger