Skip to content
AscendQ.ca — Websites, Apps & SEO Systems

Performance 9 min read

How to Fix "Use Efficient Cache Lifetimes" — the Honest Version

Use efficient cache lifetimes — Est savings of 509 KiB
fbevents.js — Cache TTL: 20m
js.hs-analytics.net — Cache TTL: 5m
static.hsappstatic.net — Cache TTL: 1m
First-party assets — Cache TTL: 14d

This audit is one of the most misleading items in a Lighthouse report — not because it is wrong, but because of what it quietly implies. It lists resources with short cache lifetimes and a tempting "estimated savings" number, and every guide tells you to "add Cache-Control headers". Here is what the guides skip: for most sites, the majority of flagged resources are served from other companies' domains. Facebook decides how long fbevents.js is cached. HubSpot decides its analytics script TTL. LinkedIn decides theirs. No header you set anywhere changes a byte of that.

And on hosted platforms (HubSpot CMS, Wix, Squarespace, Shopify), your OWN asset cache headers are set by the platform too — usually to sane values you cannot edit. So is the audit useless? No — it is pointing at a real problem, just not the one it names. The real problem is how many tracking scripts you load, and whether some of them are duplicates or dead weight. That part is very fixable, and fixing it improves much more than a cache score.

You're In The Right Place If…

  • "Use efficient cache lifetimes" tops your Lighthouse/PageSpeed report with big estimated savings
  • The flagged resources are mostly tracking and marketing scripts: Facebook, LinkedIn, Bing, HubSpot, Clarity, chat widgets
  • Your own assets are flagged at 14d or 7d TTL and your platform (HubSpot, Wix, Squarespace, Shopify) has no setting to change it
  • You added a caching plugin or rule and the audit did not move at all

What This Audit Actually Measures (and For Whom)

Cache lifetimes only matter on REPEAT visits: a long TTL lets a returning visitor's browser reuse files instead of re-downloading them. The "estimated savings" is what a repeat visitor would not re-download — it does nothing for the first visit, which is where most of your SEO and conversion stakes live. That alone should re-rank this audit below your render-blocking and JavaScript items.

Lighthouse flags any resource whose TTL it considers short relative to the file's weight. It does not know — or care — whether you have any power over the header. That is your job to triage, and it splits cleanly into three buckets.

Bucket 1: Third-Party Scripts — You Cannot Fix Their TTL, Full Stop

Every resource served from a domain you do not control (connect.facebook.net, js.hs-analytics.net, snap.licdn.com, bat.bing.com, scripts.clarity.ms…) gets its Cache-Control header from that vendor's servers. Tracking vendors deliberately use short TTLs — 1 to 20 minutes is normal — so they can ship config and logic changes fast. No caching plugin, CDN page rule, or .htaccess line on your side applies to their domain.

Self-hosting a copy of a tracking script to control its caching is a trap: pixels change frequently, a stale self-hosted copy silently breaks conversion tracking, and some vendor terms prohibit it. Accept the bucket — then shrink it (next section).

The Real Win Hiding Here: Dead And Duplicate Tags

Read the flagged third-party list as an inventory of everything your pages load — because that is exactly what it is. In nearly every audit we run, this list contains tags nobody remembers installing: a trial that ended two years ago, an agency's pixel from a past campaign, or — the classic — the same vendor's tag installed twice through different routes (once hard-coded, once via a tag manager, or an old and new version side by side).

Every tag you delete removes its download, its execution time (which hurts Total Blocking Time far more than caching ever helped), its connection overhead, and often a consent-banner dependency. This is the audit's genuine payoff: it is a de-facto tag audit wearing a caching costume.

  • Look for the same vendor appearing twice with different file names or versions — but VERIFY the initiator chain first: some vendors' current tag loads their own legacy file (LinkedIn's insight.min.js loads insight.old.min.js by itself — one install, two files, nothing to delete)
  • Look for multiple pixel IDs from the same vendor — two Facebook pixel configs usually means one is stale
  • List every vendor and ask the uncomfortable question: who reads this data? No answer = remove the tag
  • Check all three places tags hide: hard-coded in your site header/footer, inside your tag manager container, AND inside platform settings (HubSpot injects connected ad pixels at runtime — they never appear in view-source)

The Workaround That DOES Move Your Score: Defer, Don't Cache

You cannot change a vendor's TTL — but you can control WHEN their script loads, and that is worth far more. Lighthouse measures the initial load window; a tracking script that only loads on the first user interaction (or after a short timer) simply is not there while the metrics are being recorded. Its download, its execution time, its main-thread blocking — all of it drops out of Total Blocking Time and main-thread work, which, unlike cache lifetimes, actually feed the Performance score.

The trade-off is honest and small: visitors who bounce before interacting (and before the timer) are never tracked. For most business sites that is noise — those visitors were not converting anyway. The pattern below fires on the first scroll, tap, or keypress, with a timer fallback so passive readers still get counted.

One caution for hosted platforms: only defer scripts you install yourself. If your platform injects the pixel through its own loader (HubSpot does this via its script loader, which also runs forms, analytics, and the cookie-consent banner), deferring that whole loader delays consent display and data capture. Turn off the platform's auto-injection first, then install the pixel through your own deferred snippet or a tag manager trigger set to "first interaction or 3 seconds after load".

<!-- deferred Meta pixel: loads on first interaction, or after 3.5s -->
<script>
(function () {
  var fired = false;
  function loadPixel() {
    if (fired) return; fired = true;
    !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
    n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
    document,'script','https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', 'YOUR_PIXEL_ID');
    fbq('track', 'PageView');
  }
  ['pointerdown','keydown','scroll','touchstart'].forEach(function (evt) {
    window.addEventListener(evt, loadPixel, { once: true, passive: true });
  });
  setTimeout(loadPixel, 3500);
})();
</script>

How To See This Yourself — And Why No Single Tool Gets It Right

View-source only shows what the server sent. Tags load tags: a loader script injects an analytics module, which injects a pixel, which downloads its config. To see the real chain, open DevTools → Network tab, reload the page, and look at the Initiator column — it names the exact script that requested each file. Filter by a vendor's domain (e.g. "licdn" or "facebook") and you can walk the whole chain in seconds. Vendor helper extensions (Meta Pixel Helper, LinkedIn Insight Tag checker, Google Tag Assistant) go one further and show which account IDs are actually firing.

A candid note from this exact audit: our own AI-assisted analysis initially flagged LinkedIn's two insight files as a duplicate installation. It looked exactly like one — same vendor, old and new file names, both downloading. Only checking the initiator chain proved that LinkedIn's current tag loads its own legacy file on purpose: one install, nothing to delete. That is the lesson worth keeping: every tool — Lighthouse, crawlers, AI assistants, this article — reasons from patterns, and your site is built differently from the pattern. Push back when a finding doesn't match what you see, verify against the primary source (the network panel, the actual header, the actual settings screen), and only then change things. We wrote a whole guide on working with AI this way — it is linked below.

Bucket 2: Your Own Assets On A Hosted Platform

On HubSpot CMS, Wix, Squarespace, and Shopify, the platform sets Cache-Control on your files and does not expose a setting to change it. HubSpot, for example, serves generated theme assets with a 14-day browser TTL plus a 30-day CDN TTL and stale-while-revalidate — a perfectly sound policy that Lighthouse still nags about because it prefers 30+ days in the browser. There is no HubSpot switch to change this. Do not burn hours hunting for one: mark it "platform-controlled, acceptable" and move on. Repeat visitors within two weeks are fully cached anyway.

Bucket 3: Your Own Assets On Hosting You Control

Only here — your own server, VPS, Cloudflare in front of your own origin, or a static host — do you actually set the headers. The standard pattern: fingerprinted assets (files whose name contains a content hash, like app.3f9c2.js) get a one-year immutable TTL, because any change produces a new filename. HTML gets a short or no-store TTL so updates appear immediately. Images and fonts sit in between (30 days to a year depending on how often they change).

# Nginx example — the safe long-cache pattern
location ~* \.(?:js|css|woff2|png|jpg|webp|avif|svg)$ {
  add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.html$ {
  add_header Cache-Control "no-cache";
}

# Cloudflare: Rules → Cache Rules → set Edge + Browser TTL for /assets/*

The Fix, Step By Step

  1. 1

    Split the flagged list into third-party vs first-party

    In the audit, group every resource by domain. Anything not on your domain goes in the "cannot change TTL" bucket — stop trying to cache-fix those and treat them as a tag inventory instead.

  2. 2

    Hunt duplicates and dead tags in the third-party bucket

    Look for the same vendor loading twice (old + new tag versions, two pixel IDs), and for vendors nobody uses anymore. Check both hard-coded snippets and your tag manager. Delete ruthlessly — each removal helps caching, blocking time, and privacy compliance at once.

  3. 3

    Identify who controls your first-party headers

    Run: curl -sI https://yoursite.com/path/to/asset.js | grep -i cache-control. On HubSpot/Wix/Squarespace/Shopify the platform sets it and it cannot be changed — accept values like 14d as fine. On your own hosting, proceed to step 4.

  4. 4

    On self-controlled hosting, apply the long-cache pattern

    Fingerprinted JS/CSS/fonts/images: Cache-Control: public, max-age=31536000, immutable. HTML: no-cache. If assets are not fingerprinted, use 30 days instead of a year so updates are not stranded.

  5. 5

    Retest — and judge the right metric

    Re-run PageSpeed Insights. The audit may still list vendor scripts (their TTLs did not change), but your tag pruning shows up where it matters: fewer requests, lower Total Blocking Time, and a smaller third-party section. That is the win.

From the trenches

How we hit this on a real production site

This week we audited a B2B site hosted on HubSpot CMS whose report opened with "Use efficient cache lifetimes — Est savings of 509 KiB". The flagged list: Facebook pixel scripts at 20-minute TTLs, HubSpot's own analytics/banner/forms scripts at 1–10 minutes, LinkedIn, Bing, Clarity, and four other marketing vendors — plus 423 KiB of first-party assets at HubSpot's platform-set 14-day TTL.

Cache-header changes available to the site owner: zero. Every third-party TTL belongs to the vendor; every first-party TTL belongs to HubSpot. A less honest report would have ended there — but reading the list as a tag inventory surfaced two leads. First: LinkedIn's Insight tag appeared twice (insight.min.js and a legacy insight.old file). Before recommending a deletion we fetched LinkedIn's script and checked the initiator chain — and the "duplicate" turned out to be LinkedIn's own tag loading its legacy file for compatibility. One install, nothing to fix. That verification step matters: deleting it would have broken nothing, but chasing it wastes hours, and in other stacks deleting a "duplicate" that is actually a dependency breaks tracking.

Second lead: two separate Facebook pixel configurations downloading on every page — with zero Facebook code in the page source. The pixels are injected at runtime by HubSpot's ads module, which means the fix lives in HubSpot's Ads settings (two connected pixels, one likely stale), not in any HTML. This is the pattern view-source can never show you: tags load tags, and the audit's network list is the only inventory that tells the truth. Removing the stale pixel cuts weight on every single visit — first visits included — which is more than a perfect cache score would ever have delivered.

That is the pattern we see constantly: the audit points at headers, the payoff lives in the tag stack. If you want a second pair of eyes on yours, send us the report — it takes us about ten minutes to tell you which bucket everything falls in.

Frequently Asked Questions

Can I change the cache TTL of Facebook, HubSpot, or LinkedIn scripts?

No. Cache-Control is set by the server that serves the file, and those files come from the vendors' own domains. Vendors keep TTLs short on purpose so they can push updates quickly. Your options are removing the tag, loading it later, or accepting it.

Should I self-host tracking scripts to control their caching?

Almost never. Pixels update frequently — a stale self-hosted copy silently corrupts your conversion data, and some vendors prohibit it in their terms. The savings are tiny compared to the risk.

My platform sets 14 days on my own files. Is that bad?

No. Fourteen days covers the overwhelming majority of repeat visits, and platforms like HubSpot pair it with longer CDN caching and stale-while-revalidate. Lighthouse prefers 30+ days, so it flags it — but there is no setting to change and no meaningful user impact. Mark it accepted.

Will fixing this audit improve my ranking?

Not directly — Google ranks on Core Web Vitals from real users, not Lighthouse audit line-items. But the tag pruning this audit provokes reduces Total Blocking Time and script weight, which genuinely helps both Core Web Vitals and conversions.

What TTL should I set on assets I do control?

Fingerprinted assets (content hash in the filename): one year with "immutable". Non-fingerprinted assets: 30 days. HTML: no-cache, so deploys show up immediately. That combination passes the audit and never strands an update.

Still stuck? Send us the exact error.

Paste the exact error message you're seeing and where it happens. We'll take a look — if it's quick we'll point you at the fix, and if it's deeper we'll tell you honestly what it takes.

Reach the Summit

Rather have someone just fix it?

This is literally what we do all day — websites, SEO, performance, and the weird errors in between.

Start the Conversation