Every healthcare site I audit has at least one third-party script on it that the current team cannot explain. A chat widget the previous marketing lead installed. A heatmap from an A/B test that ran in 2023. A cookie consent banner that also ships its own tracking. Every one of them is a potential HIPAA violation, and every one of them is why OCR has been writing enforcement actions since late 2022.
The contrarian position: your privacy policy does not protect you, your BAA with your hosting provider does not protect you, and "we do not sell data" is the slogan of organizations that have not read the December 2022 bulletin. The thing that protects you is a clean script inventory, a Content Security Policy that enforces it, and a default of removing anything you cannot justify. Script hygiene is one leg of the stool; the other legs are covered in the regulated DTC healthcare engineering map, which shows how script inventory sits next to vendor evaluation, audit logging, and consent capture.
The script nobody remembers adding
When I audit a healthcare site, I pull the network tab on the key authenticated pages and the key marketing pages. The minimum bar for clean is: every third-party request is something a named person on the current team can justify. The reality for most sites is that there are between three and eight third-party requests on the average page, and the team can justify maybe half.
The unjustified half is the liability. It tends to fall into four categories.
Marketing stack drift. A pixel from a campaign that ended two years ago. A retargeting snippet from an agency that left. A conversion tag from a vendor the business no longer uses. The tag fires every pageview. The vendor is still collecting data. Nobody has logged into the vendor's dashboard in 18 months to notice.
Chat and support widgets. A support chat widget that the founder installed during the MVP. The widget loads the vendor's full SDK, which loads analytics, session recording, and often a customer-data-platform integration. The integration was fine when the business was pre-PHI. It has not been revisited since the business became covered.
Consent banner ironies. A cookie consent banner from a vendor that charges for "HIPAA-compliant cookie management" and, in the same bundle, ships its own analytics script that tracks how users interact with the banner. The tracking is on by default. The banner's own privacy policy buries it in a sub-section.
A/B test residue. A test platform that was evaluated, used for one test, then forgotten. The snippet stays in the theme. The platform's default configuration captures the element content of rendered pages, which on a member-area page means PHI ends up in the test platform's backend.
- yoursite.comown codeBAA ✓
- cdn.yoursite.comimagesBAA ✓
- connect.facebook.netlegacy pixelNO BAA
- googletagmanager.comGTM containerNO BAA
- www.google-analytics.comGA4NO BAA
- chat-widget.example.iosupport widgetNO BAA
- heatmap.example.comA/B residueNO BAA
- consent.example.orgbanner + trackingNO BAA
- yoursite.comown codeBAA ✓
- cdn.yoursite.comimagesBAA ✓
What OCR actually said in December 2022
The December 2022 bulletin from the Office for Civil Rights is three pages of plain English. The key sentence is that when a covered entity uses tracking technology that transmits PHI to a third party without a BAA, the covered entity is in violation of the Privacy Rule. The word "tracking technology" is broad. It includes pixels, cookies, session recorders, fingerprinters, and first-party tags that relay data to third parties.
The part most teams misread is the scope. They assume the rule only applies to pages behind a login. It does not. The updated guidance in March 2024 clarified that unauthenticated pages that contain content indicating a user's health condition (a page about a specific treatment, a symptom checker, a condition-specific landing page) are also subject. A visitor who lands on a page about a specific condition, gets a Meta Pixel fired with their IP and URL, is now in a database that a covered entity allowed PHI to flow to without a BAA.
Meta does not offer a BAA for Meta Pixel. Google does not offer a BAA for GA4. LinkedIn does not offer a BAA for Insight Tag. The list of major tracking vendors that do not offer a BAA is longer than the list that do. If the business has one of these on a condition-relevant page, the posture is not defensible.
The supply chain problem
Scripts load scripts. A chat widget's SDK loads an analytics script. An analytics script loads a session-replay script. A session-replay script loads a CDN. Every one of those is a separate vendor with a separate data policy, and the originating script's privacy policy may not cover the downstream ones.
The illustrative example is the consent banner that ships its own analytics. The banner's privacy policy says "we help you comply with privacy regulations." True statement. The same banner's script loads analytics that track how users interact with the banner itself. The analytics vendor is a sub-processor of the banner, but the banner's contract language does not necessarily treat that sub-processor as bound by the same BAA you think you have with the banner.
The only way to know is to audit the network requests after the page has loaded and every script has run. Browser extensions like uBlock Origin or the DevTools network panel make this visible. The pattern I use on audits is the same one I apply to the commerce side in the productized DTC stack diagnostic: load the page, let it sit for 30 seconds, capture the full network waterfall, and flag every domain that is not first-party or a named, BAA-approved vendor. The same vendor-evaluation discipline I describe in the BAA and vendor-risk questions for small teams applies to every domain in that list.
The privacy policy is not the defense
The defense teams most often reach for is the privacy policy. "Our privacy policy discloses our use of analytics." "We state that we share data with advertising partners." Neither statement resolves the HIPAA issue.
The Privacy Rule requires a BAA for disclosures of PHI to business associates. A disclosure in the privacy policy is not a BAA. The privacy policy is a notice to users; the BAA is a contract with the vendor. The two are independent. A covered entity can have a fully disclosed analytics setup in its privacy policy and still be in violation because no BAA is in place with the analytics vendor.
"We do not sell data" is similarly not a defense. The standard is not commercial sale; the standard is disclosure to a business associate without a BAA. A free analytics service that does not sell data but that ingests IP addresses and URLs from authenticated healthcare pages is still receiving PHI disclosure from a covered entity. The absence of a commercial transaction does not change the compliance posture.
“Privacy policies describe intent. Network requests describe behavior. Regulators read the network requests.”
The actual defense: CSP, audit, removal
The three things that actually work.
Content Security Policy. The CSP header tells the browser which domains are allowed to load scripts, images, and other resources. This is the browser-level complement to the server-level discipline in the audit-logging pattern for regulated Next.js apps. A CSP with a strict script-src allowlist prevents an unauthorized script from loading even if someone adds the tag to the theme. Start with a restrictive default and explicitly allow each vendor domain. A typical healthcare CSP for the member area:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{request-nonce}';
connect-src 'self' api.sentry.io api.resend.com;
img-src 'self' data: storage.yourdomain.com;
frame-ancestors 'none';
The nonce approach means inline scripts must be explicitly nonced by the server on each render, and no third-party script can load unless you have added its domain. This is stricter than most marketing-side policies and is appropriate for the member area. The marketing side can have a looser policy scoped to its subdomain, per the split-domain pattern from regulated analytics without GA4.
Quarterly script audit. Schedule a script inventory review on the calendar, not just when something breaks. The inventory lives in a document. For each script, the audit records: the vendor, the business purpose, the BAA status, the owner on the team, and the renewal date. Any script that cannot be matched to a named owner is a candidate for removal. The audit takes under an hour for most sites. Skipping it for a quarter means the inventory goes stale, which is exactly how the unexplained script in my opening paragraph gets there.
Remove first, ask questions later. For anything in the "cannot be justified" column after an audit, the default is removal. The friction is always the same: "but marketing might need it." Send an email to marketing, give them a deadline, remove it if they miss the deadline. The cost of removal is a conversation. The cost of keeping an unjustified script is a potential enforcement action. The asymmetry is clear.
For teams working on the commerce surface of the same platform, the script-audit discipline extends to the server-side tagging and CAPI diagnostics covered in the productized DTC stack audit, which reviews the same class of vendor sprawl from the attribution angle.
The posture I recommend
The posture for a healthcare site is "deny by default on third-party scripts, allow with documented BAA and named owner." Every script on the page is there because someone on the current team justified it last quarter. Anything older than a quarter without re-justification comes off.
The contrarian part of the position is that this is much stricter than most teams are used to. Marketing will push back because A/B testing is harder. Sales engineering will push back because chat widgets are useful. The pushback is valid and the answer is not "no scripts ever," it is "every script has a BAA and a named owner and a quarterly review." The tools that meet that bar are fewer than the tools that do not, and the work to pick them is smaller than the work to remediate a violation.
FAQ
What about Google Tag Manager as a way to centralize scripts?
GTM centralizes script management, which is useful. It does not address the BAA problem, because the scripts loaded through GTM still need vendor-level BAAs. GTM itself does not offer a BAA. Treat GTM as a container, not a compliance boundary. The same script-audit discipline applies to tags inside GTM as to scripts in the theme.
Does server-side tagging solve the third-party-script problem?
Partially. Server-side tagging moves the data-collection boundary from the browser to your server, which gives you control over what is transmitted to the vendor. It does not remove the BAA requirement; you still need one with any vendor receiving PHI. Server-side CAPI through a vendor without a BAA is the same compliance issue as the browser pixel, just implemented in a different place.
What is the risk if I keep Meta Pixel on a condition-specific marketing page?
Based on OCR enforcement actions since 2023, the risk is a complaint investigation, a request for the BAA chain, and a finding if the BAA does not exist (Meta does not sign one). Enforcement has included multi-million-dollar settlements for larger covered entities. For a small healthcare operator, the risk is lower in dollars but higher in disruption. The honest answer is that the risk-adjusted value of Meta Pixel on those pages is negative for a regulated business.
Is a cookie consent banner enough to get user consent for tracking?
A banner collects user consent for tracking under GDPR and some US state laws. HIPAA does not offer a consent path that overrides the BAA requirement. User consent does not substitute for a signed business associate agreement with the vendor. The banner is useful for the privacy regimes where consent is the basis; it is not a defense against the HIPAA disclosure rule.
How often should I run a script audit?
Quarterly is the cadence I recommend. Monthly if the team is actively adding marketing infrastructure. Annually is too slow; the half-life of an undocumented script is about four to six weeks before the original installer forgets why it is there.
What is the fastest way to identify third-party scripts on my site?
Open the browser's DevTools, go to the Network tab, filter by "JS" or by the third-party domain column, and load the page. For a more rigorous audit, tools like Request Map Generator and Chrome's Lighthouse audit surface third-party requests with bytes transferred and vendor identification. The full audit takes 20 minutes for a typical site.
Sources and specifics
- OCR bulletin on tracking technology: HHS Office for Civil Rights, "Use of Online Tracking Technologies by HIPAA Covered Entities and Business Associates," December 2022, updated March 2024.
- HIPAA disclosure rule: 45 CFR 164.502(a) for disclosures to business associates; 45 CFR 164.504(e) for the BAA requirement.
- Meta Pixel and similar vendor BAA availability as of writing; verify on the vendor's current policy before assuming a posture.
- CSP reference: MDN
Content-Security-Policydocumentation and OWASP CSP Cheat Sheet for the nonce pattern. - Script-audit methodology derives from production audits of regulated healthcare sites; the per-script inventory document pattern is standard operational discipline.
- All patterns derived from production audit findings without naming specific clients, vendors in violation, or organizations.
