Third-party scripts: the page speed you gave away
Third-party scripts are often your slowest code. You can measure what each one costs, decide what to keep, then load the rest on your terms. This guide shows how to do it with Lighthouse and your browser, and how to fix the usual culprits on a small site.
By Théophile Louvart, founder of Porteur · Updated 14 September 2026 · Markdown
Find what each script costs
Start with one URL that gets visits. For example, yourproduct.com/pricing.
- Open pagespeed.web.dev, paste the URL, select Mobile.
- Read the top field section. This is real user data from the Chrome User Experience Report over 28 days. It decides your Core Web Vitals pass or fail.
- Scroll to Diagnose performance issues. This is a Lighthouse run on a simulated mid-range phone over throttled 4G. Scores vary between runs.
- Find the audit named Reduce the impact of third-party code. Expand it. You will see each third-party origin and its main-thread time and transfer size.
Note which origins take main-thread time and block rendering. Tag them for deeper inspection in your browser later: analytics, chat, A/B testing, consent, embeds, fonts, social, ads.
Read Lighthouse’s third-party audit the right way
Lighthouse shows lab data from one simulated load. Use it to spot heavy scripts and long tasks. Do not treat the score as a ranking factor.
- Check the main-thread time attributed to each third-party origin. This is time your JavaScript blocked the thread.
- Look at Total Blocking Time. Lighthouse weights it 30 percent in the Performance score. Third-party scripts often cause long tasks here.
- Open the View Treemap link. It shows the bundle weight by source. Third-party packages often sit in their own boxes.
- Click each opportunity and diagnostic that names third parties. For example, Minimize third-party usage, Defer offscreen images if embeds pull iframes, Avoid enormous network payloads.
Then cross-check against field data. PageSpeed Insights will show the Core Web Vitals assessment from real users when there is enough traffic. Those figures win when they disagree with lab runs.
Use the Performance panel to see what blocks
Record one slow load
Open Chrome DevTools, Performance panel. Check Screenshots and Web Vitals. Throttle to Fast 3G or Slow 4G. Hit Record, hard-refresh the page, stop after it renders.
Find long tasks
In the Main track, look for red long-task bars over 50 ms. Click them. The Summary will name the function and script URL. Many will be third-party.
Inspect interactions
If your INP is poor, record a click on your pricing table. The Event Log shows handlers and time spent. Heavy analytics listeners and A/B tools often show up here.
Map costs to origins
In the Network panel, group by Domain. Sort by Size and Waterfall Start. Note every third-party origin and when it starts, blocks, or shifts layout.
You now have a list by cost, not by brand. That is how you decide what to keep.
The usual third-party inventory on a small site
- Analytics: one tag. Often two. Old ones are still loading.
- Chat: Intercom-style widgets. They parse JSON, load fonts and attach many listeners.
- Consent: a banner and a vendor list. Many inject before content and shift layout.
- Video embeds: a full YouTube or Vimeo iframe on the homepage.
- Maps: a full Google Maps JavaScript API on /contact.
- Fonts: Google Fonts CSS and multiple hosts. Each adds DNS and TLS handshakes.
- A/B testing: a synchronous snippet that blocks rendering to prevent flicker.
- Social buttons: share and like widgets that pull more scripts.
- Ads: tags that add iframes and shifts above the fold.
Audit each one. If nobody uses it, remove it. If few use it, load it on interaction. If it must run, defer it and keep it small. Where possible, self-host assets.
Decide per script: remove, load on interaction, defer, self-host
- Remove: a heatmap from last quarter, a second analytics tag, a legacy A/B tool. Delete the tag and the container rule.
- Load on interaction: chat opens on click, video loads when Play is pressed, maps load after a user asks for directions.
- Defer: analytics that do not need to block rendering. Load after load or use defer or type=module.
- Self-host: fonts and small helper scripts. Avoid a DNS lookup, connection and TLS handshake to a third-party host.
Example, before: You load a YouTube iframe on your homepage hero. LCP is a poster inside the iframe and arrives late. After: a static image button replaces the iframe. The iframe loads after click. LCP is now your H1 text or a hero image with fetchpriority on it.
<!-- Defer analytics that are not needed for first paint -->
<script defer src="/scripts/analytics.js" data-api="/collect"></script>
<!-- Module scripts defer by default -->
<script type="module" src="/scripts/app.js"></script>Facades for video and maps
A facade is a static shell that looks like the thing. You swap it for the real iframe on click. You serve less JavaScript, fewer connections and no layout shift until needed.
Build the video facade
Render a poster image, a play button and the video title. Use the watch URL to build a thumbnail URL at build time. Add width and height.
Swap on click
On click, replace the wrapper with the YouTube iframe embed URL with autoplay=1. Set loading=lazy on the iframe.
Maps: use a static image first
Show a static map image from a Static Maps service or a screenshot you host. Add a View map button. Load the JS API only on click.
The dimensions in the example below are typical, not measured. Set width and height to your own poster and video, so layout is stable.
<!-- Video facade example: sizes shown are typical, not measured -->
<a class="video" href="https://www.youtube.com/watch?v=ID" aria-label="Play video">
<img src="/img/video-ID.jpg" width="640" height="360" alt="Video title" loading="lazy" decoding="async">
<span class="play">Play</span>
</a>
<script type="module">
document.querySelectorAll('.video').forEach(v => v.addEventListener('click', e => {
e.preventDefault();
const id = new URL(e.currentTarget.href).searchParams.get('v');
const iframe = document.createElement('iframe');
iframe.width = 640; iframe.height = 360; iframe.title = 'Video';
iframe.src = `https://www.youtube.com/embed/${id}?autoplay=1`;
iframe.loading = 'lazy';
e.currentTarget.replaceWith(iframe);
}));
</script>A fixed page keeps the hero text as LCP, has no layout jumps when the facade swaps, and loads the iframe only after the click.
Fonts from third parties: costs and options
Fonts are a third party too when you link to a remote host. Each host adds a DNS lookup, a connection and a TLS handshake before the file. You also risk layout shift on swap.
- Self-host WOFF2 files. Use a single variable font if you can.
- Preload the face used above the fold: rel=preload as=font with crossorigin.
- Use font-display: swap or optional.
- Subset with unicode-range to ship fewer glyphs.
- Match metrics with size-adjust and ascent-override to avoid CLS.
- A system font stack costs nothing and is fine for UI copy.
<!-- Preload and swap a self-hosted font -->
<link rel="preload" as="font" type="font/woff2" href="/fonts/brand-regular.woff2" crossorigin>
<style>
@font-face { font-family: Brand; src: url('/fonts/brand-regular.woff2') format('woff2'); font-display: swap; }
html { font-family: Brand, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; }
</style>Preconnect only what must load early
Preconnect opens the DNS, TCP and TLS to an origin early. Use it for origins you must hit in the first paint. Do not spam it. Each open connection has a cost.
- Use <link rel=preconnect> for one analytics endpoint if it runs on load.
- Preconnect your own CDN or image host if the hero image is there.
- Do not preconnect chat, video or map hosts if you load them on interaction.
<!-- Preconnect examples -->
<link rel="preconnect" href="https://cdn.yourproduct.com" crossorigin>
<link rel="preconnect" href="https://analytics.yourproduct.com" crossorigin>Tag managers: power with limits
A tag manager is only as light as the tags inside it. A small container with strict triggers is fine. A container that injects many vendors on every page is not.
- Keep one container. Clean out paused and legacy tags.
- Fire analytics after load on content pages. Fire conversions on the event only.
- Do not use document.write or synchronous scripts in a tag manager.
- Restrict vendor tags to the pages that need them, for example, chat on /support only.
- Version and test in preview mode. Measure TBT before and after each change.
How third-party scripts hurt the three Core Web Vitals
- Largest Contentful Paint: heavy third-party code can delay TTFB and render, or make the hero image load late. Do not lazy-load the hero. Use fetchpriority=high and a preload when the hero is a CSS background.
- Cumulative Layout Shift: banners injected above content, widgets that resize, swapped web fonts with different metrics. Give media boxes width and height. Reserve space for notices. Use overlays instead of pushing content down.
- Interaction to Next Paint: every click, tap and key press counts. Third-party scripts cause long tasks, heavy event handlers and hydration delays. Break up long tasks. Keep scripts few and small. Move work to a web worker when you can.
As of 2026, the Good thresholds are 2.5 s for LCP, 0.1 for CLS and 200 ms for INP. INP replaced First Input Delay in March 2024. PageSpeed Insights shows the field assessment when there is enough data for the URL or origin.
Apply the fixes on one page, then roll out
Pick one target URL
Use /pricing or / to start. It should have traffic so field data appears. If not, rely on lab tests and user timings for now.
Remove and delay
Delete unused vendors. Move chat and video to load on interaction. Defer analytics. Self-host fonts and small helper scripts.
Preconnect the few that remain
Open early connections only for origins that must load in the first paint. Drop the rest.
Retest in Lighthouse
Run PageSpeed Insights again. Compare main-thread time by third-party origin. Check TBT, LCP and CLS in the lab run.
Record an interaction
In DevTools, measure a click or type path. Aim for the slowest interaction under 200 ms. Break long tasks and cut listeners until you reach it.
Watch field data
Give it time. Field data uses the 75th percentile over 28 days. You should see the Core Web Vitals assessment move from Fail to Pass when users feel the gains.
A fixed page will start fast, stay stable and feel instant on click. Your hero asset appears without delay, the layout does not jump, and clicks paint the next frame quickly.
Questions
Yes. They can delay your largest content, shift your layout and slow interactions. They add main-thread work and network cost. Remove what you do not need, load on interaction where you can, and defer the rest. Then measure in PageSpeed Insights and DevTools.
Self-host fonts and small helper files. You avoid extra DNS and TLS, and you can cache them. For vendor JavaScript that changes often, self-hosting can go stale or break updates. If a vendor supports a first party endpoint, use it. Otherwise, prefer loading on interaction or deferring over proxying code you do not control.
The container is not the problem. The tags are. A lean container with strict triggers is fine. A container that injects many vendors on every page will hurt Total Blocking Time and can hurt INP. Keep one container, clean old tags and fire only on needed events.
The Lighthouse score is a lab estimate from one run, not a ranking factor. Use it to find issues, not to chase 100. For Search, the Core Web Vitals field assessment in PageSpeed Insights is what matters. Aim to pass at the Good thresholds.
Aim for Largest Contentful Paint under 2.5 seconds in the field for most users. Keep Cumulative Layout Shift under 0.1. Keep the slowest common interaction under 200 ms. Fix third-party delays first, because they often sit on the main thread.
Cut payloads and long tasks first. Remove unused vendors. Load on interaction. Split work with scheduler.yield or setTimeout. Defer non-critical scripts. Move heavy work off the main thread with a web worker. Keep the DOM small to reduce layout cost.
Sources
Check my site, free
Paste a URL to get a free thirty second read of your site, the searches around it and rivals on them, with three full findings you can act on next.
- Free check, no card
- Read-only, your own accounts
- Readable by your agent
Read next
- GuideHow to read PageSpeed Insights: field data first, then the score
- GuideCore Web Vitals for a product site: the three numbers
- GuideHow to improve Interaction to Next Paint
- GuideRender-blocking resources: what blocks the first paint and how to unblock it
- GuideWeb fonts and page speed: load one face, and load it first
- GuideDoes page speed affect SEO? What Google has said and what the data does
- GuideHTTP/2 and HTTP/3: what they change for a site’s speed
- GuideClaude Code for SEO: what it can fix in your repository, and what it cannot see