DEV Community

Vishal Singh for CometChat

Posted on

Third-Party Scripts Are the Real Performance Budget on a CMS-Driven Site

A developer-facing marketing site has an awkward property: the people who publish to it every day are not the people who own its performance. Content editors add a demo embed, a webinar form, a chat widget, a heatmap tool. Each addition is reasonable on its own. The page is measurably worse a quarter later, and no single commit caused it.

I run into this on the CometChat website, which is built on a headless CMS with components that marketing composes freely. Our own product is an embeddable SDK, so the problem is not abstract to me: we ship a script that other people put on their pages, and we host pages that carry other people's scripts. Both sides of that trade have the same lesson.

First, measure what the user experiences, not what your laptop does

Lab tools tell you whether a page can be fast. Field data tells you whether it is. On a CMS site the gap is usually caused by content, not code: a hero image an editor uploaded at full resolution, an embed added to one template, a font swapped on a single landing page.

The three metrics worth arguing about:

  • LCP is nearly always an image or a web font on marketing pages. It is a content problem more often than a delivery problem.
  • INP is where third-party JavaScript shows up. A tag manager that evaluates on the main thread during page load competes with your own hydration.
  • CLS is where late-loading embeds and consent banners live. Anything that inserts DOM after first paint needs reserved space.

Segment field data by template, not just by URL. "Our blog is fine and our pricing page is not" is an actionable sentence. "The site scores 74" is not.

The audit that actually changes behaviour

Rather than a one-off cleanup, produce an inventory that a non-engineer can read. For every third-party script:

Question Why it decides the outcome
Who asked for it, and for what decision? Half of them are answering a question nobody asks any more
What does it cost in transferred bytes and main-thread time? Bytes are cheap to quote; main-thread time is what users feel
Does it need to run before interaction? Almost nothing does, except consent and A/B testing
Does it insert DOM? If yes, it needs reserved layout space
What happens if it fails? It must be able to time out without blocking anything

I have never run this inventory without finding at least one script still loading for a campaign that ended.

Guardrails beat cleanups

A cleanup lasts until the next campaign. Guardrails last longer, and they belong in the CMS layer where the content is composed:

  1. No raw HTML embed field. If editors can paste a <script> tag into a rich-text field, your performance budget is advisory. Replace it with typed components: a video component, a form component, a code-sample component. Each one is implemented once, lazily, correctly.
  2. Media handled by the pipeline, not the uploader. Resize, compress and serve modern formats at the component boundary. Give images explicit dimensions from the CMS asset metadata so layout is stable before the bytes arrive.
  3. Defer everything that is not needed for first interaction. Chat widgets, heatmaps, and video players load on interaction or on viewport entry. A chat launcher is a button; the widget itself can arrive after the click.
  4. Budgets in CI, on templates. Fail the build when a template's script weight or estimated main-thread time crosses a line. The failure message should name the component that grew.
  5. A single owner for the tag list. Tags added directly through a tag manager bypass every check above. That is the hole in most otherwise-good setups.

Point 3 is where the largest wins are, and it is also the one that most often gets reversed by a stakeholder who wants their widget "available immediately". Have the number ready: what interaction latency costs in conversion is a more persuasive argument than what it costs in milliseconds.

The other side: shipping a script other people embed

Building an embeddable product changes how you read your own audit. If your SDK is on someone's landing page, you are the third-party script in their inventory, and they will run exactly the questions above against you.

What that implies, in the order the questions get asked:

  • Ship a small loader and fetch the rest on demand. A launcher button does not need the full conversation runtime.
  • Do your initialisation work off the critical path, and never block first interaction on a network round trip.
  • Reserve your own space. If your widget mounts into a fixed-position container with known dimensions, you contribute nothing to CLS.
  • Fail invisibly. If your API is unreachable, the host page must still be fully usable.
  • Publish your weight. Teams that are auditing scripts will pick the vendor whose numbers are documented over the one whose numbers require a WebPageTest run.

Those are the same constraints, viewed from the other end. The audit you run on your own site is the audit your customers run on you.

What I would do first

If you inherit a slow CMS-driven site, resist the rewrite. Do this instead:

  1. Pull field data, grouped by template.
  2. Inventory third parties with owners named.
  3. Delete the ones nobody defends.
  4. Convert the remaining critical-path scripts to interaction-loaded.
  5. Replace the raw HTML field with typed components so the problem stops regenerating.

Steps 1 to 4 recover most of the loss. Step 5 is the one that keeps it recovered.

Sources

Top comments (0)