Healthcare & Medical · project showcase · measurement architecture
Conversion tracking for a medical practice that never lets a patient detail reach the tag
Most practice sites either measure nothing or push form values and appointment reasons into an analytics tool never designed to hold them. This is the reference build we use instead: a measurement layer that counts every booking and call without a single clinical detail leaving the building.
At a glance
The engagement in brief
Services
- Technical SEO
- Booking Intake
- Reporting
- Web Development
- CRM
Stack
- Google Tag Manager
- Google Analytics 4
- server-side tagging
- call tracking under a BAA
- scheduling widget (isolated frame)
- consent banner
The situation
What we walked into
A practice that wants to know which campaign produced which appointment has two bad options in front of it by default. Measure nothing, and every media decision is a guess. Or install the standard tracking a marketing agency installs anywhere else, and within a week the analytics account is holding appointment reasons in page paths, names in form field values, and phone numbers in call-tracking transcripts held by a vendor nobody has a business associate agreement with. Both of those are decisions, and the second one is usually made by accident.
The most common way a practice leaks protected health information is not the analytics tool. It is a thank-you page URL carrying the appointment reason in a query string, indexed and passed to every tag on the page.
What we found
The diagnosis
01
The leak is almost always the URL, not the tool
Booking systems love to write state into the address bar: reason, provider, insurance, date of birth. Every tag on the page receives the full URL by default. Stripping query parameters at the tag layer, and configuring the booking system not to write them in the first place, removes more risk than any setting inside the analytics product.
02
A call-tracking vendor is a business associate whether or not anyone treated it as one
Recorded calls to a medical practice contain protected health information within the first fifteen seconds. If the vendor will not sign a business associate agreement, the build uses call counting without recording, and that constraint is decided before the number is provisioned, not after.
03
A conversion you cannot name is still a conversion you can count
The event taxonomy carries appointment_request and call_started, never appointment_request_dermatology. Service line lives in a parameter with a fixed allow-list of non-clinical categories, so reporting can still separate new-patient from returning demand without describing anyone's condition.
04
Consent and containment are different jobs and a banner only does one of them
A consent banner governs whether tags fire. It does nothing about what those tags receive once they do. The containment work — parameter stripping, field-value suppression, an isolated scheduling frame that passes no data to the parent page — has to exist underneath the banner.
The number behind it
What this is built around
**89% of patients say booking at any hour matters, but only 11% of medical groups say most of their patients can** (Experian Health 2024; MGMA 2024), and physician search converts at **12.43%** at a **$40.04** lead cost (WordStream 2026). You can't optimise a 24/7 booking funnel you're legally barred from measuring the normal way — so measurement is the precondition.
What we built
The system
Everything is event-based and nothing is free-text. The scheduling widget renders in an isolated frame that cannot read or write the parent page, so the parent page never sees what was booked. Tag Manager runs a strip-and-allow model: query parameters are removed before any tag receives the URL, form-field values are never read, and only a named list of events and parameters is permitted through. Tagging runs server-side so the payload is inspectable before it leaves. Call tracking is count-only unless the vendor is under a business associate agreement. The result is a reporting layer that can answer which channel produced which appointment type without holding anything about a person.
The sequence
How it was delivered
Week 1
Data inventory
Every field, parameter and URL the current site writes, listed and classified
Owner: OmniFlow
Weeks 1–2
Containment layer
Parameter stripping, event allow-list, isolated scheduling frame
Owner: OmniFlow
Weeks 2–3
Server-side tagging
Payloads routed through a server container and inspected before dispatch
Owner: OmniFlow
Week 3
Vendor review
Business associate agreements confirmed or the vendor's capability reduced to counting
Owner: OmniFlow + practice
Outcome
What shipped
This entry makes no performance claim. It documents an architecture and the constraints it was designed against. What it produces is a reporting layer a practice can hand to its own compliance reviewer without a redaction pass first, and a set of decisions that are far cheaper to make before a tag is installed than after eighteen months of data has accumulated in the wrong shape. The artefact worth copying is the written data inventory: every field, parameter and URL the site produces, classified once, so that any later addition has an obvious place to sit or an obvious reason to be refused.
Reporting
What you would actually see
These are the surfaces this engagement is run and measured from, shown with representative figures built around the benchmarks cited on this page. Every account we run reports into views like these, and you keep ownership of all of them.
These are demo dashboards. They show the reporting surfaces this engagement is run and measured from, with representative figures generated around the published benchmarks cited on this page — not a client account and not a client result. Live reporting for your own account replaces every number here.
Google Analytics 4
Healthcare & Medical · all web data
Sessions
2,818
+42.8%
Key events
75
+53.5%
Session key event rate
2.7%
+0.7%
Engagement rate
55.2%
+4.4%
Sessions by month
Dashed line marks the month the engagement started.
| Session default channel group | Sessions | Key events | Rate |
|---|---|---|---|
| Organic Search | 1,233 | 39 | 3.2% |
| Paid Search | 661 | 17 | 2.6% |
| Direct | 461 | 13 | 2.8% |
| Referral | 250 | 7 | 2.8% |
| Organic Social | 212 | 6 | 2.8% |
CRM pipeline
Healthcare & Medical · inbound and outbound
Leads created
78
+67.6%
Qualified
33
+77.7%
Meetings booked
14
+81.1%
Answered on first attempt
72.5%
+10.7%
Leads created by month
Dashed line marks the month the engagement started.
| First-touch source | Leads | Qualified | Meetings |
|---|---|---|---|
| Google Ads — high intent | 24 | 10 | 5 |
| Organic search | 21 | 9 | 4 |
| Business Profile — call | 15 | 6 | 3 |
| LinkedIn outbound | 11 | 5 | 2 |
| Referral | 7 | 3 | 1 |
Honestly
What we would do differently
The first version of the event taxonomy encoded the service line into the event name itself, which made the reports readable and made every event name a small disclosure. It had to be pulled back into a parameter with a fixed allow-list. Naming conventions are a compliance surface in this vertical, and they should be reviewed before anything is instrumented rather than after the reports look good.
Next
Start the same conversation
Start the same conversation
Tell us what you are working on and we will say plainly whether this is the right shape of engagement for it.