focosys.io
← Writing
Essay

How to Audit Your Healthcare Website for Tracking Compliance

A step-by-step healthcare website HIPAA audit you can run yourself in an afternoon, covering PHI in URLs, consent gating, hardcoded scripts, and BAA gaps.

How to Audit Your Healthcare Website for Tracking Compliance
Key takeaways
  • The Network tab is the only ground truth. A CMP dashboard reports near-100 percent consent compliance even while GTM tags fire regardless of user choice, so watch what actually leaves the browser after you reject consent.
  • A condition-specific URL path sent to Google or Meta alongside any identifier (even a gclid or a hashed email) is PHI in transit; Enhanced Conversions makes this worse, not better.
  • Hardcoded scripts like Hotjar, Intercom, or Clarity bypass your consent layer entirely because they never pass through GTM. View page source, not just Inspect, to find them.
  • A missing BAA is its own violation regardless of any leak, and Google signs none for GA4, Ads, or GTM and Meta signs none for the Pixel or CAPI. The real fix is architectural, a 4-to-8-week server-side project, so run the five steps first to scope it.

A regional orthopedic group asked me to look at their site before a board presentation. Marketing was proud of it. New CMP, cookie banner on every page, a signed statement from their web vendor that the build was "HIPAA compliant."

Fifteen minutes into DevTools, I had a Google Ads request payload showing /services/spine-surgery/schedule-consultation?insurance=medicare&location=downtown traveling to googleads.g.doubleclick.net, tied to a click ID. That's a Medicare patient's procedure interest and location, sent to Google, with no BAA covering the transmission.

Nobody had lied to them. Nobody had checked either.

This is the pattern I see at almost every healthcare marketing team I sit down with. The vendor says compliant. The CMP dashboard says compliant. Nobody has opened the Network tab and looked at what's actually leaving the browser.

Why "It Passed Review" Doesn't Mean Anything

Most healthcare compliance reviews check three things: is there a privacy policy, is there a cookie banner, does the site have an SSL certificate. None of those touch what happens after a tag fires.

A CMP vendor confirms their banner is installed and configured. That's true and irrelevant. The banner controls what shows up on screen. It says nothing about whether the tags underneath actually respect the choice a visitor makes, or whether the data those tags collect qualifies as PHI in the first place.

An audit that only checks for banner presence is a compliance theater exercise. The real audit happens in the browser's dev tools, the GTM container, and your vendor contract file. That's what takes 30-45 minutes and actually tells you something.

Step 1: Capture What's Actually Leaving the Browser

Step 1: Capture What's Actually Leaving the Browser

Open Chrome, go to any condition-specific or scheduling page on your site, and open DevTools (Cmd+Option+I on Mac, F12 on Windows). Click the Network tab, then filter by google, facebook, doubleclick, analytics, and any other ad or tracking vendor you run.

Reload the page. Click through the scheduling flow if you have one. Watch the requests populate.

For each request to an ad platform, click into it and look at the query string or POST payload. You're looking for:

  • Full page URLs containing condition names, procedure types, or provider specialties
  • Insurance type or plan name in any parameter
  • Appointment type, department, or diagnosis code
  • Any of the above combined with an email hash, phone hash, or click ID (gclid, fbclid, _fbp)

If you see /conditions/hiv-treatment or /services/oncology/chemo-scheduling in a request URL going to Google or Meta, alongside a user identifier, that's PHI in transit. The identifier doesn't need to be a name. A click ID is enough to make the health information identifiable on the receiving end.

Enhanced Conversions makes URL leakage worse, not better

If you have Google Ads Enhanced Conversions turned on, it hashes and sends email or phone data alongside the page context Google already has, including the referring URL. A hashed email combined with a condition-specific page path is still PHI. Hashing an identifier doesn't strip the health information sitting next to it in the same request.

Do this on at least four page types: homepage, a condition or service line page, a scheduling or intake form, and any authenticated patient area if one is public-facing. Each page type tends to leak differently.

Click "reject all" on your cookie banner. Clear cookies and local storage (Application tab in DevTools, right-click Clear site data). Reload the page and check the Network tab again.

If you still see requests going out to Google, Meta, or any other ad platform after rejection, your consent implementation is cosmetic. This is the single most common gap I find. The CMP is configured correctly on paper: consent categories are mapped, Consent Mode v2 signals are set up in the CMP's own dashboard. But nobody wired the actual GTM tags to check that signal before firing.

Check this on the same four page types from Step 1. I've seen sites where consent gating works on the homepage but a scheduling page has a hardcoded pixel that ignores the CMP entirely, because a different team built the scheduling flow eighteen months later on a different template.

Don't trust the CMP dashboard, trust the Network tab

Your CMP will report near-100% consent compliance even when tags are firing regardless of user choice. The dashboard reports what it thinks it configured. It has no visibility into whether GTM actually respects that configuration. The only ground truth is watching requests after you reject consent.

Step 3: Open the GTM Container and Check Every Tag

Log into Google Tag Manager, go to your container, and open the Tags list. For each tag, check whether it has a consent-based trigger condition or Consent Mode v2 settings applied.

Faster method: click Admin → Export Container, download the JSON, and search the file for consentSettings. Every tag should have this block. If a tag is missing it, it fires unconditionally regardless of what the visitor chose.

Pay attention to tags marked "Firing Triggers: All Pages" with no additional condition. These are the ones most likely to have been added quickly by a developer solving an unrelated problem, without anyone thinking about consent at all.

Step 4: Search Your HTML for Scripts That Bypass GTM Entirely

View source on your key pages (right-click → View Page Source, not just Inspect). Search for <script src= tags that reference third-party domains directly in the HTML, rather than being loaded through GTM.

Common offenders on healthcare sites: chat widgets (Intercom, Drift, LiveChat), session recording tools (Hotjar, FullStory, Microsoft Clarity), review platforms, and A/B testing tools. These get added by developers for a specific project, and because they're hardcoded, they never pass through your consent layer no matter how well GTM is configured.

I found a Hotjar recording script on a patient intake form at a dermatology group. It had been added ten months earlier by a contractor doing a UX redesign, and forgotten. It was recording condition checkboxes, symptom descriptions, and insurance carrier selection on every session, with zero consent gating and no BAA with Hotjar in place. Marketing didn't know it existed until we pulled the page source.

If you find a script like this, remove it immediately, then figure out how to reimplement the underlying use case (if it's still needed) through GTM with proper consent checks, or through a HIPAA-eligible alternative.

Step 5: Inventory Your BAAs Against Your Actual Tag List

Take the full list of vendors receiving data from your site: every ad platform, analytics tool, chat widget, heatmap tool, and CDN. For each one, confirm with legal or your compliance officer whether a signed Business Associate Agreement exists.

Here's the part that surprises most teams: it doesn't matter whether you've confirmed PHI is flowing to a given vendor. If that vendor could plausibly access PHI through the service they provide on a healthcare property, you need a BAA regardless. The absence of a BAA is its own violation, separate from any data leak you find in Steps 1-4.

Google signs BAAs for Google Workspace and Google Cloud Platform. Google does not sign a BAA for GA4, Google Ads, or Google Tag Manager. Meta does not sign one for the Pixel or CAPI. Most third-party marketing and analytics vendors won't sign one at all.

What this actually means for your stack

If you're running GA4 or the Meta Pixel on any page where a patient could enter condition, treatment, insurance, or appointment information, you don't have a compliant setup even if you've filtered every parameter perfectly, because the underlying tool has no BAA available. The fix is routing that data through infrastructure that does carry one (Google Cloud services behind a BAA, for example), not just cleaning the payload going to a non-BAA tool.

Build a simple spreadsheet: vendor name, what data they receive, BAA status, and whether the vendor is even eligible to sign one. This becomes your remediation punch list.

What to Do With What You Find

Most audits turn up some combination of the same problems: PHI in URL paths hitting ad tags, a consent banner that doesn't gate anything, at least one hardcoded script nobody remembers installing, and a BAA gap with the primary analytics or ad platform.

None of these get fixed by adjusting a filter in GTM's UI. Filtering condition names out of a data layer variable doesn't help if the underlying tool has no BAA to begin with. The real fix is architectural: move data collection server-side, strip identifiers and PHI before anything reaches a third-party endpoint, and replace tools that can't sign a BAA with ones that can.

But that's a four-to-eight week project, not something to start blind. Run the five steps above first. You'll walk into that project knowing exactly what's leaking, where, and to whom, instead of guessing at scope. Most teams have never actually looked. That's step zero, and it takes less time than the meeting where you explain why you need budget to fix it.

Christopher Landaverde — Marketing Systems Engineer More writing →