PLAINFINCH learn by building

Third-party scripts

You will load a chat widget from another site only when someone asks for it, so the page shows and responds quickly.

What makes a third-party script expensive?

A third-party script is code that comes from another company's server: a chat widget, a map, a reviews badge, analytics, a booking calendar, an advert. You add one line, and that line can bring in more weight than your whole page.

On the bakery's “find us” page, the chat widget costs four things. A new connection to chat.example.net, which on 4G means three round trips before a single byte. 160 KB of JavaScript to download. 180 ms of running on the phone's main thread, plus a polling task every so often. And a second file, chat.css, that the widget asks for once it runs. The page itself is under 1 KB of HTML and 10 KB of CSS.

You also give up control. The other site decides how big the file is, when it changes, how long it may be cached, and what else it loads. A widget that is light today can triple in size after an update you never see.

Why is a script from another site slower than your own?

Your own files come over the connection the page already opened. A file from another origin needs its own connection: a DNS lookup, a TCP handshake and a TLS handshake. In the simulator that is three round trips, about 450 ms on 4G, before the request can even be sent. Other sites' servers also take a little longer to answer, 80 ms here against 20 ms for your own files.

In the starting Waterfall you can see each part on the widget's bar: the connect section, the wait, then a long download. Because the script is plain and in the head, the first paint waits for the whole bar plus the time to run it, and lands at about 2.5 seconds.

Every extra origin adds another connection. A page with a tag manager, a font service, a map, a chat widget and a reviews badge can easily be opening six connections, and on a phone those compete with your own photos.

FigureTwo timelines of the bakery find us page. The plain widget script adds a 450 ms connection, 230 ms wait, 800 ms download and 180 ms run, so paint lands at 2.46 s. A facade paints at 1.02 s.Two timelines of the bakery find us page. The plain widget script adds a 450 ms connection, 230 ms wait, 800 ms download and 180 ms run, so paint lands at 2.46 s. A facade paints at 1.02 s.
Every part of the widget bar sits in front of the first paint: connection, wait, download and run. The facade removes the whole bar from page load.

Is async enough?

Adding async is the first step, and it helps a lot: the page paints at about 1 second instead of 2.5, because the parser no longer waits. Most providers' instructions already include async, and you should never remove it.

Look at Vitals after that change, though. Total blocking time rises from about 20 ms to about 150 ms. The widget still downloads 160 KB on every visit and still runs its 180 ms of code, now while the visitor is reading and trying to scroll or tap. If someone taps Order bread during that task, the page responds late.

For scripts that every visitor needs, such as the analytics you rely on, async and keeping the script small may be the best you can do. For things most visitors never use, there is a better option.

What is a facade, and when should you use one?

A facade is a lightweight stand-in for the real widget: a button, an image or a link that looks like the start of the thing. The heavy script loads only when someone uses it. For the bakery, a “Chat with the bakery” button costs nothing to show, and a short click handler adds the widget's script tag on the first tap.

With the facade, the page makes two requests on load, about 11 KB in total, and total blocking time is zero. The visitor who wants to chat waits a moment after tapping while the widget loads, and the button text says so. Everyone else never pays for it.

Use a facade when the widget is used by a small share of visitors, when it is large, or when it does a lot of work as it starts. Chat widgets, video players and maps are the usual candidates. Analytics and consent tools, which must run on every page, are not.

<button id="chat-btn" type="button">Chat with the bakery</button>
<script>
  document.getElementById('chat-btn').addEventListener('click', function () {
    var s = document.createElement('script');
    s.src = 'https://chat.example.net/widget.js';
    document.head.appendChild(s);
  }, { once: true });
</script>

When does preconnect help?

A <link rel="preconnect" href="https://chat.example.net"> in the head opens the connection to that site early, before any request needs it. It saves the three round trips only when the request would otherwise be discovered late.

On the starting page it saves nothing: the preload scanner finds the widget's script tag in the head at once, so the connection starts at the same moment anyway. Preconnect pays off for files found late, such as a font named in another site's stylesheet, an image a script inserts, or the widget behind a facade when you expect many visitors to tap it.

Keep preconnects to the two or three origins that matter most. Each one opens a real connection, which costs the phone some work and is closed again if it is not used within about ten seconds. dns-prefetch is a cheaper hint that only does the DNS lookup, saving one round trip.

<link rel="preconnect" href="https://chat.example.net">

How do embeds like maps cause trouble?

An <iframe> from a map or video service loads a whole page inside your page, with its own HTML, scripts, styles and images. The bike shop's map embed in the Break It is 420 KB, more than all its own files together, and every visitor downloads it.

There are two good fixes. Add loading="lazy" to the iframe so it only loads when it is near the screen; that helps when the map sits far down the page. Or replace it with a small static map image that links to the full map, which costs about 30 KB and gives a better experience on a phone, where the visitor's own maps app will open.

Reserve space for anything a third party inserts. The reviews badge in the Break It appears late and pushes the address down. A min-height on its container keeps the space from the first paint.

How do you find out what third parties cost?

In Chrome DevTools, the Network panel has a filter for third-party requests, and you can add a Domain column (right-click the column headers) and sort by it to see how many origins a page talks to. The Performance panel shows each script's main-thread time. Lighthouse lists third-party code by provider with its size and blocking time, and PageSpeed Insights shows the same for real pages.

The simulator gives each script a fixed size and run time, set in the lesson. Real third-party scripts vary with the visitor, the time of day and the provider's latest release, and many load further scripts of their own. Measure your real page every so often, and again whenever you add or update a widget.

What does AI often get wrong here?

AI tools usually paste the provider's snippet as given and stop there. They rarely ask whether every visitor needs the widget, rarely suggest a facade, and often add preconnect hints for five or six origins, which spreads the phone's effort thinly.

They also sometimes rewrite a provider's async snippet as a plain <script src> because it looks tidier, which turns a harmless widget into one that blocks the whole page. Check every script tag for another site's address and look at its row in the Waterfall.

Field notes

  • Code from another company's server can weigh more than your whole page.
  • Each new site needs its own connection, which costs several round trips.
  • Adding async stops the parser waiting, but the code still keeps the phone busy.
  • A facade, such as a button, loads the real widget only when someone taps it.

Easy to get wrong

A plain third-party script makes every visitor wait for another site's connection and code before anything appears. Most visitors never open the chat.

Each preconnect opens a real connection. Too many compete with the files the first screen needs.

Map embeds load a whole page of their own, often hundreds of KB, for visitors who mostly only need the address.

Questions people ask

Will a facade hurt people who want to chat?

They wait a moment after tapping while the widget loads. That is a fair trade when most visitors never chat. Make the button say what is happening, and preconnect to the widget's site if many visitors use it.

Can I host a third-party script on my own server?

Sometimes, and it saves a connection. Many providers update their scripts often and expect them loaded from their servers, so check their terms and plan to refresh your copy.

Does async help with total blocking time?

No. It moves the script's work after the first paint, where it counts towards total blocking time. Only running less code, or running it later, reduces that.

What about consent banners?

They usually need to run on every page, so a facade does not fit. Load them with async, reserve their space or use a fixed position, and keep an eye on their size.

Keep going