A multi-location clinic group can almost always tell you which office got booked. It usually cannot tell you which campaign booked it. We traced 8 booking handoffs across 7 multi-location dental groups, hop by hop, from public pages only. Six of them drop campaign identity before the appointment exists, and the break lands in the same place nearly every time: the moment the patient is handed from the website to the booking application. Location identity survives that hop. Campaign identity does not.
This expands on a post I published on LinkedIn about where campaign identity dies. The one-page checklist I offered there is reproduced in full below, in the article, with nothing held back for a DM.
Key Takeaways
- Two identities travel with every patient: which location they want, and which campaign sent them. The first is load-bearing for the booking software, so vendors preserve it. The second is load-bearing only for you, so it gets dropped.
- The break concentrates at hop three of five. Campaign identity is lost entirely at the booking handoff in 6 of the 8 handoffs we inspected. One of those lost the location too.
- The form is the second leak. 0 of the 6 booking forms we inspected carry a
utm_orgclidhidden input. They capture page URL and referrer. Nothing else. - This is a configuration choice at every hop, not a platform limit. One group in the set carried its parent analytics container across the exact same subdomain hop that breaks everyone else, and another passes a facility code and a source key into the booking app. Same vendors, same architecture, different result.
- Three specific failures worth checking on your own stack: a vendor
campaignID=slot shipped empty by two unaffiliated operators, a hand-built call-tracking bridge with a hard-coded 7 day attribution window, and a location URL that returns 404 the moment any query string is appended. - None of the five fixes requires replatforming. They are hidden inputs, a first-party cookie, one campaign key carried into the booking app, an honest attribution window, and one per-location table where campaign id and location id sit on the same row.
Two Identities Travel With Every Patient. Only One Reaches the Chair
Every paid click into a multi-location clinic carries two facts. The first is where the patient wants to be seen. The second is what brought them. Those two facts ride the same URL out of the ad platform, and they do not arrive together.
Location identity is preserved because the booking software cannot function without it. It rides proprietary keys that the vendors built on purpose, the kind you see sitting in clinic URLs as fc=, officeid= or ?location=. Every hop in the chain has a reason to keep that value, so every hop keeps it.
Campaign identity has no such protection. It rides UTM parameters and gclid, which are conventions rather than requirements, and nothing downstream of the ad click breaks if they disappear. So they disappear. At the booking hop the scheduler keeps the key it needs and drops the ones it does not, and the appointment is created with no memory of the campaign that produced it.
The consequence is narrow and expensive: you cannot compute per-clinic return on ad spend when the data breaks at the final hop. You can report cost per lead at the network level and appointments at the location level, and you cannot join them. That is the same measurement gap that makes budget pacing across locations guesswork, and it sits underneath every per-location question in multi-location healthcare marketing analytics.
I had assumed booking vendors preserve click context by default. They mostly do not. We only found the break because we walked the flow hop by hop instead of reading the reports at the end of it.
The Five Hops, and What Dies at Each
Here is the whole trace, laid out as the five hops between an ad click and a booked chair. For each one: what breaks there, and the exact field to stamp.
Hop 1. Ad click
What breaks: nothing yet. gclid and utm_* are on the URL and intact. Every later loss is a choice made after this point.
Stamp this: nothing to add. Confirm your redirect chain preserves the query string instead of rebuilding the URL.
Hop 2. Landing and location page
What breaks: location survives, campaign starts thinning, and some location URLs reject the parameters outright. One location URL in our set returned 404 the moment any query string was appended, including a UTM. The bare URL returned 200.
Stamp this: persist utm_* and gclid into a first-party cookie on landing. Then curl the location URL bare and with ?utm_source=test, and compare status codes.
Hop 3. Booking handoff
What breaks: this is the break. Campaign identity is lost entirely at this hop in 6 of the 8 handoffs we inspected, and one of those lost the location too. Two unaffiliated operators run the same vendor's campaignID= slot empty. The field shipped with the template. Nobody filled it.
Stamp this: pass one campaign key into the booking app on every link. Use the vendor slot if it exists (campaignID=), otherwise ride the proprietary key already in the URL (fc=, officeid=, ?location=).
Hop 4. Form submit
What breaks: the form records where the person was, not how they got there. 0 of 6 booking forms inspected carry a utm_ or gclid hidden input. They capture page URL and referrer. Nothing else.
Stamp this: add hidden inputs for utm_source, utm_medium, utm_campaign, gclid and the location id, populated at page load from the URL or the cookie set at hop 2. If your campaign names are inconsistent across platforms, fix that first, because a hidden input faithfully preserves a value nobody can group by. UTM naming conventions are the unglamorous prerequisite here.
Hop 5. Chair, CRM and the phone call
What breaks: the attribution window closes before the decision does. One hand-built call-tracking bridge in the set hard-codes a 7 day cookie. A dental implant decision takes longer than 7 days, so the window expires mid-consideration and the booking arrives unattributed even where every earlier hop was clean.
Stamp this: set the attribution window to at least your real consideration cycle, not one week. Then keep one per-location table that carries campaign id and location id on the same row, so booked revenue joins back in a single query. That table is the physical form of appointment attribution, and without it the model stays theoretical.
Two notes on the numbers above, because they contain two different sixes. The 6 of 8 is handoffs: eight booking handoffs across seven groups, six of which lose campaign entirely. The 0 of 6 is forms: six booking forms, none carrying an attribution field. They are separate measurements of separate things, not the same six counted twice.
This Is a Configuration Choice, Not a Platform Limit
The temptation, when you see six of eight groups break the same way, is to conclude the category is broken and the fix is a replatform. The set contains its own counterexample.
One group carried its parent analytics container across the exact same subdomain hop that breaks everyone else. A second one passes its facility code and a source key into the booking application on every appointment link. Same class of vendors, same architecture, different result. The difference was configuration, made once, by someone who checked.
Two things are worth being precise about here, because this is where an argument like this usually overreaches. What the trace proves is that the subdomain hop is not inherently an attribution break, since at least one group preserves its container across it. What the trace does not prove is that any group's campaign identity survives all the way into a CRM record, because whether a gclid ever lands in a CRM field was not verifiable from the outside for any operator in the set, including the ones that look clean. The break at hop three is measured. The clean end-to-end path is demonstrated at the hops we could see and inferred past that point.
That is what makes the empty campaignID= slot the most useful finding in the trace. The vendor built the field. The template ships with it. Two unaffiliated operators, running the same product, both left it empty. Nothing was missing from the software. What was missing was anyone whose job it was to click through their own funnel and read the URL at the end.
None of the five fixes above requires changing vendors, and all five are the sort of work that gets deferred because nothing visibly breaks when you skip it. The reports still render. They are just reporting on a join that quietly stopped being possible.
Talk to an Improvado expert about joining campaign spend to booked appointments per location.
The Five Minute Self Test
You do not need an audit to find out whether your own flow has this problem. Three checks, about five minutes, no tooling beyond a browser and a terminal.
1. Curl one location URL bare, then with ?utm_source=test. Do the status codes match? If the bare URL returns 200 and the parameterized one returns 404, your location pages are rejecting the tracking you are paying to attach.
2. View source on your booking form. Is there a hidden gclid input? Search the page source for gclid and for utm_. If neither appears, the form is capturing page URL and referrer, and your paid clicks arrive at the CRM anonymous.
3. Click one of your own live ads, book through to the last screen, and read the URL. Does any campaign key survive in it? This is the check that settles the argument, because it tests the whole chain end to end rather than one hop in isolation, and it costs you one click of your own ad spend.
If all three come back clean, your flow is in the minority and I would genuinely like to hear how it is built. If any one of them fails, the fix is at that hop, and it is smaller than it looks.
The Fields Worth Stamping
The whole trace reduces to four fields that either survive to the chair or do not.
utm_source,utm_mediumandutm_campaignas hidden form inputs, not just URL parameters. A parameter on a URL is not data until something writes it down.gclidpersisted first-party at landing and read at submit, so the value survives the hops in between rather than depending on the query string arriving intact.- One campaign key carried into the booking app, whatever the vendor calls it. Use their slot if they built one. Ride their proprietary location key if they did not.
- Location id present on the same row as the campaign id, in one per-location table, so booked revenue joins back in a single query instead of a reconciliation project.
That is the entire fix list. It is unglamorous, it is mostly a day of work spread across the people who own each hop, and it is the difference between reporting appointments by location and knowing what an appointment costs by campaign at that location.
One last honest note on scope. This trace is eight handoffs across seven groups, inspected on a single day in July 2026 from public pages only, in one vertical. It is a small, dated sample and I am not going to inflate it into a category-wide statistic. It also stops where public observation stops: we could read pages, forms, links and containers, and we could not confirm what any of these groups' CRM records actually contain, so no claim here should be read as a verified end-to-end result. What it is good for is the mechanism: the specific hop where the break happens, and the specific fields that fix it. Those transfer to any multi-location business that hands a patient or a customer to a third-party booking application, which is most of them. Our full dental research, including the method and what we deliberately did not measure, is on the dental DSO research page.
Talk to an Improvado expert about stamping campaign and location identity into one governed table.
Frequently Asked Questions
What is a booking handoff in marketing attribution?
It is the moment a visitor leaves your website and enters a third-party booking or scheduling application to pick a time. For multi-location clinics this is usually a link to a vendor subdomain or a separate booking product. It matters for attribution because it is a boundary between two systems, and boundaries are where identity gets dropped. In the eight handoffs we traced, campaign identity was lost entirely at this hop in six of them, while location identity survived, because the booking software needs the location to function and does not need the campaign at all.
Why does the clinic location survive the handoff when the campaign does not?
Because the two values have different consumers. The location key is required by the booking application itself: it decides which calendar, which address and which provider list to show, so every hop in the chain has an operational reason to preserve it. Campaign identity is required only by your reporting, which sits outside the booking flow entirely. Nothing user-facing breaks when utm_campaign disappears, so nothing in the chain is built to protect it. That asymmetry, not vendor incompetence, is the mechanism.
How do I check whether my own booking flow drops campaign identity?
Three checks, about five minutes. Curl one of your location URLs bare and then with ?utm_source=test, and compare the status codes, because some location pages 404 the moment any query string is appended. View source on your booking form and search for gclid and utm_, since a form with no hidden attribution inputs records only page URL and referrer. Then click one of your own live ads, book all the way through to the final screen, and read the URL to see whether any campaign key survived. The third check is the decisive one, because it tests the entire chain rather than one hop.
Do I need to change booking vendors to fix this?
No, and the trace contains the evidence for that. One group in the set carried its parent analytics container across the exact same subdomain hop that broke the others, and another passes a facility code and a source key into its booking application on every appointment link, both using the same class of vendors as the groups that break. The most common failure we found was a vendor campaignID= slot that shipped with the template and was left empty by two unaffiliated operators, which is a configuration gap rather than a product limitation. The five fixes are hidden form inputs, a first-party cookie at landing, one campaign key passed into the booking app, an attribution window that matches your real consideration cycle, and one per-location table carrying campaign id and location id on the same row.
Why does a 7 day attribution window break clinic attribution?
Because the window has to outlast the decision, and for high-consideration procedures it usually does not. One hand-built bridge between call tracking and booking in our set hard-codes a 7 day cookie. A dental implant decision commonly takes longer than that, so the identity expires while the patient is still deciding, and the booking lands unattributed even when every earlier hop preserved the campaign correctly. The fix is to set the window to your actual consideration cycle, measured from your own booked appointments, rather than accepting a default that was chosen for a different kind of purchase.
How large was this research sample?
Eight booking handoffs across seven multi-location dental groups, inspected on 2026-07-26 from publicly accessible pages only, plus six booking forms across six of those groups. It sits inside a larger public-source study of 18 operators built from 552 public sources. No client data or spend data was used, and no operator is named here. It is deliberately a mechanism study rather than a benchmark: the sample is too small and too dated to support a category-wide percentage, but it is more than enough to identify which hop breaks and which fields fix it, and those findings transfer to any business that hands a customer to a third-party booking application.