Delay JavaScript
Postpone non-critical scripts until after the visitor first interacts with the page.
Metrics
This technique can move up to 33% of LCP's share of the Lighthouse score.
This technique can move up to 100% of TBT's share of the Lighthouse score.
This technique does not move CLS.
This technique can move up to 67% of FCP's share of the Lighthouse score.
This technique can move up to 33% of SI's share of the Lighthouse score.
This technique does not move TTFB.
Overview
Delay JavaScript execution postpones non-critical scripts by marking them with a non-executable custom type attribute. The browser ignores these scripts entirely during page load. Once the visitor first interacts — a click, tap, or keypress — the scripts are re-injected as standard <script> elements and execute normally. The page renders and becomes interactive with zero script overhead.
Impact grade, A+ to D: how much of the Lighthouse score this technique can move. Unaffected: CLS, TTFB.
The Problem
Even with defer, scripts execute synchronously after DOM construction, occupying the main thread and contributing to Total Blocking Time. Third-party analytics, chat widgets, social embeds, and marketing scripts rarely need to run before the user does anything — yet they inflate TBT and delay user input responsiveness on every page load.
Performance Impact
LCP
Moderate
main thread free to paint content without script interference
TBT
50–90%
non-critical scripts removed from the critical load path entirely
FCP
scripts marked with the delay attribute do not block HTML parsing; the browser reaches and renders first content sooner
SI
visual slots fill progressively as HTML renders without script interruption on the main thread
Risk: High
delaying critical scripts breaks functionality — must audit carefully
How it works
01
Scripts are marked with a non-executable type attribute
Target scripts are given
type="text/delayed-javascript"instead oftype="text/javascript". Browsers do not recognise this type and skip these scripts entirely — they are downloaded (if external) but never executed.02
Event listeners wait for first user interaction
A small inline controller script attaches listeners to the
windowfor interaction events:mousedown,click,touchstart,keydown. The listeners are set up synchronously on page load and have negligible overhead.03
On first interaction, delayed scripts are activated
When any interaction event fires, the controller iterates all
script[type="text/delayed-javascript"]elements, creates a new standard<script>with the same content, appends it to the body, and removes the original placeholder.04
Event listeners are removed after first activation
After activating delayed scripts, the interaction listeners are removed to prevent the activation logic from running again. Scripts execute exactly once, as if they had loaded normally — just later.
Controller script + delayed script example
<!-- Mark non-critical scripts as delayed -->
<script type="text/delayed-javascript">
// Analytics, chat widget, social embed — runs only after interaction
initAnalytics();
loadChatWidget();
</script>
<!-- Controller: activates delayed scripts on first interaction -->
<script>
(function () {
var events = ['mousedown','click','touchstart','keydown'];
function activate() {
document.querySelectorAll('script[type="text/delayed-javascript"]')
.forEach(function (orig) {
var s = document.createElement('script');
s.textContent = orig.textContent;
if (orig.src) s.src = orig.src;
document.body.appendChild(s);
orig.parentNode.removeChild(orig);
});
events.forEach(function (e) {
window.removeEventListener(e, activate, true);
});
}
events.forEach(function (e) {
window.addEventListener(e, activate, true);
});
}());
</script>The controller script itself must be standard (not delayed) and small enough to inline. It should appear once per page, before any delayed scripts.
Limitations
- Scripts that control navigation menus, hero sliders, form validation, or any above-the-fold interactive element should not be delayed. If a user tries to interact before a script has executed, the interaction fails silently — creating a broken first impression.
- Delaying analytics scripts means page-view events and scroll depth data before the first interaction are not captured. For analytics that need to record the full session from the first moment, consider alternative strategies like server-side events.
- If a delayed script depends on another delayed script (e.g., a jQuery plugin delayed along with jQuery), the activation order must be preserved. The current implementation activates all delayed scripts in DOM order.
Common Mistakes
Delaying every script indiscriminately
Applying delay to all scripts, including menu toggles, form handlers, and e-commerce checkout logic, breaks site functionality immediately on load. Audit each script’s purpose — delay only scripts that genuinely do not need to run before the first interaction.
Chasing performance scores over actual user experience
Delay JavaScript can produce dramatic Lighthouse score improvements while making the site feel unresponsive — especially on slow touch devices where the first interaction triggers a burst of script execution. Measure real-user INP after enabling, not just lab scores.
Not testing across form fills, checkout flows, and menus
Delayed execution bugs are often subtle and context-specific. A menu that opens on the second click, a form that submits without validation on the first attempt, or a payment form that initialises late — these need explicit test coverage.
Need help applying this to your site?
Targeted fixes, not guesswork. We identify which techniques move the needle for your specific WordPress stack.
Start an Engagement