plugins/frontend-toolkit/skills/third-party-scripts/SKILL.md
Audit and optimize third-party scripts — analytics, tag managers, chat widgets, embeds — with the right loading strategy, performance budget, facades, and CSP/consent controls. Use when adding a script, when TBT/INP regress, when a GDPR/CCPA consent requirement arises, or before shipping. Not for first-party bundle size (use bundle-optimization) or broad Core Web Vitals diagnosis (use rendering-performance).
npx skillsauth add jaykim88/claude-ai-engineering third-party-scriptsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Keep third-party scripts (analytics, tag managers, chat, A/B tools, embeds) from silently destroying performance and privacy. Each script earns its place: right loading strategy, measured cost, CSP-controlled, consent-gated where required.
Universal — loading-strategy classification, performance budgeting, facade patterns, and CSP/consent controls apply to any site; only the script-injection helper differs by framework.
Inventory every third-party script
Assign a loading strategy per script
<script> in <head>Use a facade for heavy embeds
Prefer server-side / first-party where possible
Set a third-party performance budget
Connection hints for unavoidable origins
preconnect / dns-prefetch for the script origin (saves TCP/TLS handshake) — coordinate with api-caching-optimizationSecurity + privacy controls
script-src (coordinate with security-audit) — no blanket 'unsafe-inline''unsafe-inline' or nonce gymnastics)Measure impact (validation loop)
| ❌ Anti-pattern | ✅ Correct |
|---|---|
| Synchronous <script> in <head> for analytics | Async, loaded after hydration / when idle |
| Chat widget loaded eagerly on every page | Facade placeholder → load on click |
| Blanket script-src 'unsafe-inline' for vendors | Allowlist each origin + nonce / SRI |
| Loading tracking before consent (GDPR) | Consent-gate loading (Consent Mode v2 in EEA); load only after opt-in |
| Tag manager any teammate can publish to | Governed publish access + container audit + CSP review |
| Adding scripts with no budget check | Each script must fit the third-party budget or displace one |
| Tier | Examples | Action SLA |
|---|---|---|
| Critical | Render-blocking sync third-party script in <head>; tracking loaded pre-consent in a GDPR region | Block release; fix immediately |
| Major | Eagerly-loaded heavy widget (chat / embed) inflating INP / TBT; third-party JS over budget; missing CSP allowlist; ungoverned tag manager (anyone can inject runtime scripts) | Fix this sprint |
| Minor | Missing preconnect for a used origin; unowned script of unclear value | Schedule within 2 sprints |
docs/third-party-scripts.md — script / purpose / owner / strategy / size / budget impactscript-src allowlist + SRI hashes (coordinate with security-audit)perf(3p): defer <script> / feat(3p): facade for <widget>next/script with strategy — beforeInteractive (rare, critical only), afterInteractive (default), lazyOnload (idle), worker (Partytown, experimental — runs off the main thread; test each script, those needing direct DOM/cookies often break in a worker)react-lite-youtube-embed, lazy chat triggers)<link rel="preconnect"> in the root layoutscript-src allowlist in next.config.ts headers() (see security-audit)useHead({ script: [{ src, defer }] }), or @nuxt/scripts (purpose-built: facades, consent, perf strategies)<svelte:head> for script tags; manual facade components; Partytown integration for worker offloadingRenderer2) with an explicit per-script strategy; manual facades for embeds<script async/defer>, preconnect / dns-prefetch, CSP script-src, SRI, and the facade pattern are web-platform standards; Partytown (web-worker offloading) is framework-agnosticrendering-performance — third-party JS is a top INP / TBT regression sourcebundle-optimization — first-party bundle vs. third-party loaded scripts are different leverssecurity-audit — external scripts need CSP allowlisting + SRIafterInteractive / lazyOnload, use facades for heavy widgets (load on interaction), and hold every script to a measured budget — a script with no owner and no measured value is a removal candidate. Two governance traps: a tag manager is a runtime backdoor that bypasses your CSP/budget/review (govern publish access), and consent must gate script loading (Consent Mode v2 in the EEA), not just post-load configuration.development
Apply the Testing Trophy (mostly integration tests with RTL + MSW, sparing E2E with Playwright) and set coverage thresholds. Use before new feature work, after bug fixes, when CI coverage falls below target, or when tests are flaky or break on every refactor. Not for wiring coverage gates + Playwright into the GitHub Actions matrix (use cicd-pipeline) or auditing WCAG a11y compliance (use accessibility-audit).
development
Inventory and prioritize technical debt — TODO/FIXME/HACK, any usage, deprecated APIs, untested logic — with impact × effort matrix. Use at quarter start, before a refactoring sprint, when a new teammate joins, or when feature velocity slows. Not for actually paying down debt (use code-refactoring) or recording a migration approach (use decision-records) — this only inventories and prioritizes.
development
Decision framework for choosing the right state location — URL, server cache, local component, or shared/global store. Use when state-sync bugs appear, prop drilling gets deep (3+ levels), filters/tabs lose state on reload, or quarterly review. Not for form state specifically (use form-ux) or when the state is actually server data (use api-caching-optimization).
development
Apply Next.js Metadata API per route — title template, og:image, generateMetadata for dynamic pages, JSON-LD structured data, robots, sitemap, canonical, hreflang. Use when adding a new route, when search visibility drops, when rich results are needed, or before shipping. Not for choosing a route's render mode (use render-strategy-decision); align generateMetadata with that route caching choice.