Third-party scripts: governance before they eat your site
Felix's audit — the honest inventory, the cost measuring, the CSP fence, from our third-party script audit — is day one. This piece is about day two onwards, because the audit doesn't fail; it decays. Six months after a beautiful audit, a campaign adds a pixel, a vendor demo embeds a snippet, a well-meaning marketer pastes into the tag manager, and the site is back to forty third-party origins with nobody sure why. Audits are events; governance is a system. This is the system we install: a consent-aware loading architecture, budgets enforced where code is reviewed, and a small ritual that keeps marketing and engineering on the same side.
The architecture: one loader, no raw snippets
The foundational rule: no third-party script loads except through the first-party loader. Not "prefer the loader" — no exceptions, because every exception becomes a precedent, and precedents become the network waterfall you were trying to escape. The loader is a small typed module, checked into the repo, code-reviewed like any other code, that knows about every vendor:
// scripts/vendors.ts — the registry is the policy
export const vendors = {
analytics: { script: '...', consent: 'necessary', budgetKB: 25, owner: 'growth' },
chat: { script: '...', consent: 'functional', budgetKB: 60, owner: 'support', facade: true },
adsPixel: { script: '...', consent: 'marketing', budgetKB: 15, owner: 'marketing', campaignOnly: true },
} as const
Three properties make this work. The registry is data, and data gets reviewed: adding a vendor means a pull request with a named owner and a declared budget, which means the conversation happens before the script ships, not in the incident review. The loader enforces consent categories mechanically — a marketing-category script cannot load without marketing consent, not by policy but by code, so the cookie banner's promise is kept by the same system that made it. And it enforces loading discipline: everything async or deferred, facades where possible (a chat widget that renders a first-party button and loads its 60KB of vendor JavaScript only on first interaction is the single highest-value pattern in this space), and campaignOnly tags scoped to the campaigns that need them rather than the whole site.
If your organisation's marketing team needs agility engineering can't review same-day, run the tag manager — but treat it as one vendor in the registry (with a budget and an owner), and govern what goes into the container through the quarterly ritual below. A container bypassing code review is a sanctioned backdoor; half-governed is better than ungoverned, and honest about what it is.
Budgets per vendor, enforced in CI
Aggregate budgets ("third parties: 100KB total") fail because nobody owns the total. Per-vendor budgets work because each has an owner and a consequence. The mechanics:
- Declare the budget in the registry (transfer size, and where relevant, long-task time on a reference device).
- Measure in CI on preview builds. Synthetic checks catch budget breaches at pull-request time, when the fix is a conversation rather than a rollback. Lighthouse-style budgets wired to the registry mean a vendor shipping a surprise 40KB update fails someone's build, loudly and attributable.
- Alert on drift in production. Real-user monitoring of long tasks by origin — observable attribution is imperfect, but long-task timing plus script URLs gets you most of the way — feeds the quarterly ritual with facts instead of vibes.
- Breach protocol, agreed in advance. A vendor over budget for two consecutive quarters gets a remediation conversation; over budget with a facade alternative available gets the facade; over budget with no owner claiming value gets removed. The point of a written protocol is that the hard conversation happened once, calmly, in advance.
This slots into the wider bundle budget discipline — third-party spend belongs in the same ledger as first-party bundle size, because the user's device does not care whose logo is on the JavaScript.
The contract terms nobody reads (you should)
Governance includes two boring clauses we now insist on at vendor onboarding. Data destiny: what does the script collect, where does it go, is it sold onward, does it set cookies beyond its consent category. Vendors that can't answer clearly don't get loaded — a decision made easier in Australia since the privacy-reform temperature rose, and in any jurisdiction where your consent banner makes promises your tags have to keep. Notice period for breaking changes: vendors version-bump their snippets without warning; an onboarding email that says "we load v-pinned URLs where available; notify before deprecations" costs nothing and occasionally saves a launch.
The quarterly ritual: forty-five minutes, both teams in the room
The ritual is what turns the architecture into governance. Once a quarter, engineering and marketing sit down with three printouts: the registry (every vendor, owner, budget, usage), the RUM drift report, and the value column — for each vendor, the number that justifies it. Analytics: is anyone acting on it? The chat widget: tickets deflected, conversion assisted. The ads pixel: spend currently attributed through it.
Each vendor gets one of three verdicts — keep, fix, kill — and kills are normal, celebrated even. A healthy regime removes two or three tags a year as campaigns end and vendors drift. The ritual also handles requests: new tag proposals bring a use case and an owner, and get a yes/no in the meeting, not in a thread that dies. Marketing gets speed (decisions in the room), engineering gets integrity (one loader, real budgets), and both sides stop treating the other as the obstacle, which — in our experience across growth and engineering collaborations — was most of the actual problem.
Two anti-patterns the ritual exists to prevent. Campaign graffiti: tags added for a six-week campaign, still firing in month nine. The registry's campaignOnly flag plus an expiry date makes removal the default. Ownership amnesia: vendors whose owner left the company, still billing and still loading. Any vendor without a living owner is automatically up for kill at the next ritual.
What good looks like after a year
The numbers we use as a health check: third-party transfer under ~10% of page weight on key templates; zero scripts outside the loader; every vendor with a living owner and a value sentence; consent categories mechanically enforced; and a quarterly meeting that's mostly boring. Boring is the target state. Governance that produces drama has failed; governance that produces a quarterly shrug and a shrinking registry is compounding.
Key takeaways
- Audits decay. Governance — architecture, budgets, ritual — is what keeps third-party scripts from re-accumulating.
- One first-party loader with a typed registry: every vendor is a code-reviewed row with an owner, a consent category and a budget.
- Enforce consent mechanically at the loader; facades for heavy interactive vendors; campaign tags scoped and expiring.
- Budgets per vendor, in CI, with a pre-agreed breach protocol — never one aggregate nobody owns.
- The quarterly ritual (keep/fix/kill, with marketing in the room) is the governance; boring-by-design is the success state.
FAQ
Marketing says review slows campaigns down. Honest answer? It adds hours, occasionally a day — and the registry makes the cost visible instead of hiding it in page performance for years. The quarterly ritual exists partly to be the faster channel: bring the proposal there, get a decision in the room. If same-hour deployment is genuinely needed, that's what the governed container is for — one vendor, one budget, one owner, audited quarterly.
What about the CMP (consent management platform) itself? The CMP is a vendor too — it goes in the registry, gets a budget, and gets audited like the others. Its special role (deciding what may load) doesn't exempt it; it makes exemption more dangerous. Loader and CMP integrate deliberately, consent state passed explicitly, never each assuming the other handled it.
Server-side tagging instead of all this? It moves the trust problem to your server, which you govern better — that's a genuine architecture, increasingly the right one for analytics and conversion pixels. It doesn't remove the need for the registry, the consent categories or the ritual; it relocates the enforcement point. Third-party calls from your server are still third-party dependencies.
Where does this land in a Brassfern engagement? The audit is usually week one; the loader architecture and registry ship inside a website engagement or a performance-focused sprint; the quarterly ritual is the handover artefact — we run the first two cycles alongside your team, then it's yours. The registry file, with its owners and budgets, is the governance in a form a future hire can read.
Auditing third-party scripts before they audit you
Third-party scripts are a governed supply chain, not a paste bin. Our audit method: measure the cost, gate on consent, fence with CSP, and assign every tag an owner.
Experiments that don't shift the layout
A/B testing without layout shift: server-side assignment, experiment flags that never leak into the DOM, metric integrity, and the true cost of visual editors.
A search index built at build time
A build-time search index for static sites: tokenisation, stemming, synonyms, size budgets, sharded delivery, worker-side ranking, and proof it got better.