First Input Delay (FID) measures the time from when a user first interacts with a page to when the browser can respond to that interaction.
In other words, FID aims to capture load responsiveness (interactivity) or how fast a page responds to user interaction.
FID is evolving, but its current definition splits out three critical concepts to understand.
FID only measures discrete events as user interaction, such as clicks, toggling, taps, and key presses. Events that FID measures as user interaction are part of the Response aspect of the RAIL model, precisely the following:
pointerdown (only if it is followed by pointerup)
Other types of user interaction, like zooming or scrolling, won’t impact FID.
FID only considers the first input because:
The first time a user interacts with your page will shape the user’s first impression of your page responsiveness.
The most critical interactivity issues occur during page load.
Slow input delays after page load may require different solutions.
FID measures input delay, not processing. Thus, FID measures the time the browser takes to respond to the user interaction event, not the event processing time itself. The diagram below illustrates this idea.
You can measure FID in the field using any of these tools:
FID is measured in milliseconds (ms), and it should be equal to or less than 100 ms.
FID is all about probabilities because:
Some users will have no FID values (not everyone will interact with your page).
Some users will have low FID values (they interact at good times when the browser’s main thread is idle).
Some users will have high FID values (they interact at bad times when the main thread is busy).
Even though the threshold for all CWV is the 75th percentile, Google recommends looking at the 95th–99th percentiles for FID. That’s because the higher percentiles correspond to the awful first experiences users are having with your page.
Lab and Field Data considerations
Because it requires real user interaction, FID cannot be measured in lab tools. That’s quite a limitation when it comes to debugging FID issues.
However, a helpful lab metric has been around for a while and serves as a proxy for FID: Total Blocking Time (TBT). Generally, improvements in TBT correspond to improvements in FID.
TBT is not exactly FID, though. TBT measures the amount of time during which the main thread was blocked and prevented input responsiveness. TBT adds together the blocking time for each Long Task that blocked the browser’s main thread for more than 50 ms, without considering user interaction.
Additionally, TBT won’t consider the delay produced by the double-tap to zoom user interaction on pages not optimized for mobile viewing. Double-tap to zoom causes a delay of 300 ms after the first tap because the browser is trying to determine whether a second tab will come. This delay is not a Long Task, and thus it won’t count towards TBT. Yet, it will impact FID.
So, there are differences between FID and TBT, but both metrics correlate. Optimizations to TBT in the lab should lead to improvement to FID for your users.
A final consideration to keep in mind is that lab tools will ignore cached resources. Hence, the positive impact that cache and bcache bring on performance may not be visible in lab tools.
Third-party scripts are popular on airline websites and for a reason: they provide valuable functionalities such as analytics, ads, A/B testing, sharing buttons, and so on.
On the next page, click on Total Blocking Time (TBT), the proxy metric for FID.
Then, you will see a table with a list of third-party scripts adding to the TBT.
For example, the table above shows that Google Tag Manager significantly adds to the blocking time.
Identify scripts triggering Long Tasks after the initial content renders
Just because a third-party script is causing high TBT, it does not necessarily mean that it’s the cause of poor FID. The script may be indeed blocking the main thread, but users typically don’t interact with the page when the blocking occurs.
This can give you a hint about which script identified in Step 1 to prioritize.
For example, the WebPageTest filmstrip below shows a possible moment of first user interaction at 4.8 seconds, when the booking mask forms.
Immediately after the booking mask appears, a Long Task (red bars) runs on the main thread. The larger version of the WebTestPage waterfall shows that Google Tag Manager causes this Long Task. Thus, Google Tag Manager scripts can be a starting point for further analysis.
After the test finished running, you can get the same filmstrip for your page by clicking on Filmstrip View on the Performance Results page.
Simply go to https://wpt-compare.app/, enter the original test URL and the URL of the test blocking Google Tag Manager, add relevant Labels, and click on “Generate URLs”.
You will notice two links at the bottom, each taking you to comparison tools. Go to the Graph Page Comparison View, set the Statistical Comparison against the original test, and scroll down to find the TBT section.
You are interested in three aspects specifically:
Whether the results are statistically significant.
The difference TBT values at the 75th percentile.
The range of TBT values for the set of tests.
As you can see, removing Google Tag Manager would bring a significant improvement to TBT. Would it correlate to improvements in FID? It’s likely, but not guaranteed.
Additionally, fixing FID issues is pretty much an iterative process. It can take several tries before you see the desired results.
So, implement improvements, wait for a few weeks, and see how much FID improved after collecting enough Field Data.
When deciding third-party resources, pick those that send the least amount of code while giving you the functionality you need.
Reduce script bloat
Remove redundant third-party scripts. You don’t need different vendors that offer the same functionality (e.g., two A/B testing tools or two analytics platforms).
Additionally, remove any third-party resource that you don’t really need!
Use asyncor defer
Avoid synchronous scripts unless a third-party script needs to run before the page renders. Instead, use asyncand deferattributes to tell the browser to load the script in the background while parsing the HTML. This way, users can see the page without waiting for the scripts to load fully.
Because asyncscripts execute immediately after loading, use it if you need the script to run earlier in the loading process. However, consider that asyncscripts can interrupt the DOM building. Good candidates for the asyncattribute are analytics and A/B testing tags.
Use deferfor less critical resources since deferred scripts won’t block the parser. For example, you can generally defer sharing buttons, chat widgets, videos below the fold.
Use <link rel=”preconnect”> to start a connection with another origin as early as possible. It involves the DNS lookup and TCP handshake, and TLS negotiations. Be mindful of unnecessary preconnecting because it can delay other resources. Thus, only use the preconnecthint for the most critical resources.
On the other hand, <link rel=”dns-prefetch> instructs the browser to resolve the DNS of another origin before it’s called. So, it handles a limited aspect of the connection to an external domain. The dns-prefetch hint is more suited to less critical third-party resources.
Lazy-load third-party resources
Lazy-loading can help to ease the negative performance impact of third-party resources. This is especially true for those resources that are not critical or render below the fold (e.g., ads, embedded videos, etc.).
Lazy-loading third-party scripts in a proper way will help the browser get the main content faster, and your page will deliver a better user experience.
Self-host third-party scripts
Self-hosting third-party scripts is a great way to take control over the loading process of those resources. Although self-hosting comes with some downsides (e.g., they won’t be automatically updated), it can let you take advantage of reduced DNS lookup time, improved HTTP caching, and the benefits of HTTP/2 server push.
Follow best practices for tags and tag managers
Tags are marketing and analytics snippets of code to collect data, set cookies, or integrate third-party content. Mismanaged tags can become a major cause of page performance issues.
To keep third-party tags under control, you must follow a series of best practices.
Legal vetting: whether the tag complies with all legal requirements (e.g., GDPR, CCPA, etc.)
Need: whether a tag is required on a page.
Ownership: who will be the person or team that will take ownership over the tag.
Purpose: it’s essential to create cross-functional communication to understand why the tag is on the page.
Review: tags need periodic revisions to prevent tag bloat on the site.
Not all scripts should be loaded using a tag manager
Tag managers are an excellent solution for implementing non-essential third-party resources (e.g., Facebook pixels, chat widgets below the fold, etc.). That’s because a tag manager will generally delay third-party scripts, which can positively impact FID.
However, tag managers are not great for loading resources that trigger visual or functional aspects on a page. Examples of those functionalities include GDPR notices, hero images, or anything page functionality above the fold. Using tag managers to load those resources can negatively impact LCP and CLS!
Remove duplicate and unused tags
On many occasions, the number of tags created in a tag manager can get out of hand. It can also happen that you have the same tag implemented through a tag manager and hard-coded. This can significantly impact a page’s performance in a negative way.
Audit your tag manager and remove any duplicated or unused tags. Remove or pause the affected tags, not just block them. That’s because blocking a tag through a trigger exception does not remove the tag from the container.
Use Custom Templates when possible
If you are using Google Tag Manager, consider using Custom Templates rather than Custom HTML tags when possible.
Due to greater restrictions, Custom Templates are less impactful on performance than Custom HTML tags. The downside is that Custom Templates may not work for all cases.
If you do have to use a Custom HTML tag, consider the following:
Don’t copy and paste libraries or large third-party scripts into the Custom HTML tag. Instead, inject the third-party script via a script tag that downloads an external resource (for example, <script src=”external-scripts.js”>). Although this strategy adds a separate round-trip to download the script’s contents, the upside is that it decreases the container size and allows the browser to cache the script separately.
Although some third-party vendors recommend placing their script at the top of the <head>, you may not need to do so. That’s because scripts loaded via a tag manager are generally executed once the browser has already finished parsing the <head>.
When debugging performance issues, keep in mind that most synthetic tools will attribute the performance impact of a Custom HTML tag to the tag manager rather than to the tag itself.
Use pixels when possible
Pixels are the most performant tag type, followed by Custom Templates, and Custom HTML tags as the least performant.
The downside to using pixels is that they support less functionality. However, in some cases, third-party scripts can be replaced with pixels. Check with your third-party vendors to see if they support pixels.
As a general rule, the earlier a tag fires, the bigger the impact on performance. Experiment with different triggers to find that that will satisfy your needs and minimize the performance impact at the same time.
Custom Events could be convenient in some cases because they will allow you to fine-tune when a tag fires.
Additionally, choose specific trigger conditions to ensure that tags fire when they are actually needed.
Load the tag manager at the right time
Choosing good triggers for tags is great, but adjusting when your tag manager loads can also positively impact performance. Experiment with the loading times of your tag manager and change it until it balances your needs with the page performance.
Optimize the tag containers
Use separate containers if needed. For example, a website and a mobile app may require different containers because they are structured differently.
However, as a general rule, try to stick to one container per page. Multiple containers on a page can trigger important FID issues and other performance problems. If you need to deploy various containers per page, follow Google’s guidance to do it the right way.
We all have been there. Your SEO agency wants to install its own Google Analytics snippet. The social media marketing team needs to enable the Facebook, Pinterest, and Twitter tracking pixels. Your customer service team wants a chat widget on the site. The CRO people demand the Google Optimize script on the page to start running experiments.
Generally, airlines marketing teams work with multiple vendors, agencies, and cross-departmental teams. When there is no tag governance process, third-party tags can quickly get out of control, and a page can end up with several tag manager containers. This is a widespread source of FID issues for airlines.
Five Google Tag Manager containers!
Avoid multiple tag manager containers whenever possible. You can do that by consolidating all tag managers, establishing a tag vetting process, and removing redundant tags.
Additionally, monitor the container size since a large container will impact your page performance. The container size depends on its tags, triggers, and variables. Google Tag Manager, in particular, limits the container size to 200 KB, but you should aim at way less than that.
Dozens or hundreds of third-party tags usually fill tag managers on airlines’ sites. For example, the waterfall below shows Adobe Tag Manager triggering a Long Task in the browser’s main thread, likely causing input delays.
You probably don’t need a bloated tag manager container like that!
Consider using server-side tagging
Use server-side tagging for third-party scripts that support it. Switching to server-side tagging can give you more control over the data and offloads processing from the browser to the server, positively impacting performance.
Periodically audit tag usage
To avoid the accumulation of unnecessary tags, conduct an audit of your tag manager periodically. This practice will help you detect duplicate and unused tags, monitor the container size, and review complex deployments.
Additionally, PageSpeed Insights and Lighthouse can also flag unused scripts.
Code-split your bundle into multiple chunks
Code-splitting Long Tasks that block the main thread into smaller, asynchronous tasks will significantly reduce input delay on your page.
document.write() is an old known culprit of poor page performance. Because document.write() dynamically injects another script, it can stop the parser for a long time until the resource is downloaded. Thus, document.write() may increase network round-trips, delay the page rendering, and potentially block the main thread.
Using Lighthouse or PageSpeed Insights, you can see whether there are scrips injected via document.write() on your page.
Google’s official recommendation is simply to avoid document.write(). Do not inject scripts using document.write() or replace those that are using it.
Use service workers
Additionally, using service workers to cache third-party scripts is a middle-ground solution that will allow you to benefit from the third-party CDN, while also taking greater control of the loading process. For example, you can define how often third-party resources will be re-fetched from the network.
Idle until urgent
Many browsers allow users to double-tap to zoom content that is not mobile-friendly. This usually happens when the content is on pages without an explicit <meta name=”viewport”>. Because a browser needs to wait up to 300 ms after the first tap to see if a second tap will follow, pages without the viewport will have poor FID.
Therefore, even though setting a viewport has been recommended for a while, it’s worth stressing its importance to achieve good FID. This is now a recommendation in Lighthouse and PageSpeed Insights.