<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Gilberto Cocchi on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Gilberto Cocchi</name>
  </author>
  <link href="https://web.dev/authors/gilbertococchi/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/4CxwBoPk1E2KKHDkdY1s.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Gilberto Cocchi.</subtitle>
  
  
  <entry>
    <title>Automating audits with AutoWebPerf</title>
    <link href="https://web.dev/autowebperf/"/>
    <updated>2020-12-09T00:00:00Z</updated>
    <id>https://web.dev/autowebperf/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;what-is-autowebperf-awp&quot;&gt;What is AutoWebPerf (AWP)? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#what-is-autowebperf-awp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/AutoWebPerf&quot; rel=&quot;noopener&quot;&gt;AutoWebPerf&lt;/a&gt; (AWP) is a
modular tool that enables automatic gathering of performance data from multiple
sources. Currently there are &lt;a href=&quot;https://web.dev/vitals-tools/&quot;&gt;many tools
available&lt;/a&gt; to measure website performance for
different scopes (&lt;a href=&quot;https://web.dev/how-to-measure-speed/#lab-data-vs-field-data&quot;&gt;lab and
field&lt;/a&gt;), such as
Chrome UX Report, PageSpeed Insights, or WebPageTest. AWP offers integration
with various audit tools with a simple setup so you can continuously monitor the
site performance in one place.&lt;/p&gt;
&lt;p&gt;The release of &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Web Vitals&lt;/a&gt; guidance means that close
and active monitoring of web pages is becoming increasingly important. The
engineers behind this tool have been doing performance audits for years and they
created AWP to automate a manual, recurring, and time consuming part of their
daily activities. Today, AWP has reached a level of maturity and it&#39;s ready to
be shared broadly so anyone can benefit from the automation it brings.&lt;/p&gt;
&lt;p&gt;The tool is accessible on the
&lt;a href=&quot;https://github.com/GoogleChromeLabs/AutoWebPerf&quot; rel=&quot;noopener&quot;&gt;AutoWebPerf&lt;/a&gt; public repository
on GitHub.&lt;/p&gt;
&lt;h2 id=&quot;what-is-awp-for&quot;&gt;What is AWP for? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#what-is-awp-for&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although several tools and APIs are available to monitor the performance of web
pages, most of them expose data measured at a specific time. To adequately
monitor a website and maintain good performance of key pages, it&#39;s recommended
to continuously take measurements of &lt;a href=&quot;https://web.dev/vitals/#core-web-vitals&quot;&gt;Core Web
Vitals&lt;/a&gt; over time and observe trends.&lt;/p&gt;
&lt;p&gt;AWP makes that easier by providing an engine and pre-built API integrations
which can be programmatically configured to automate recurrent queries to
various performance monitoring APIs.&lt;/p&gt;
&lt;p&gt;For example, with AWP, you can set a daily test on your home page to capture the
field data from &lt;a href=&quot;https://developer.chrome.com/blog/chrome-ux-report-api/&quot; rel=&quot;noopener&quot;&gt;CrUX API&lt;/a&gt; and lab data
from a
&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;Lighthouse report from PageSpeed Insights&lt;/a&gt;.
This data can be written and stored over time, for example, in &lt;a href=&quot;https://www.google.co.uk/sheets/about/&quot; rel=&quot;noopener&quot;&gt;Google
Sheets&lt;/a&gt; and then visualised in the
&lt;a href=&quot;https://datastudio.google.com/c/u/0/navigation/reporting&quot; rel=&quot;noopener&quot;&gt;Data Studio dashboard&lt;/a&gt;.
AWP automates the heavy-lifting part of the entire process, making it a great
solution to follow lab and field trends over time. See &lt;a href=&quot;https://web.dev/autowebperf/#data-studio&quot;&gt;Visualising audit
results in Data Studio&lt;/a&gt; below for more details).&lt;/p&gt;
&lt;h2 id=&quot;architecture-overview&quot;&gt;Architecture overview &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#architecture-overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AWP is a modular-based library with three different types of modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;engine&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;connector&lt;/strong&gt; modules&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;gatherer&lt;/strong&gt; modules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The engine takes a list of tests from a connector (for example, from a
local CSV file), runs performance audits through selected gatherers (such as
PageSpeed Insights), and writes results to the output connector (for example,
Google Sheets).&lt;/p&gt;
&lt;img alt=&quot;A diagram of AWP&amp;#x27;s architecture.&quot; decoding=&quot;async&quot; height=&quot;439&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/GqufPfzbuslrT4st1FmP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;AWP comes with a number of pre-implemented gatherers and connectors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pre-implemented gatherers:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/chrome-ux-report-api/&quot; rel=&quot;noopener&quot;&gt;CrUX API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/chrome-ux-report-bigquery/&quot; rel=&quot;noopener&quot;&gt;CrUX BigQuery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/speed/docs/insights/v5/get-started&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.webpagetest.org/getkey.php&quot; rel=&quot;noopener&quot;&gt;WebPageTest API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pre-implemented connectors:
&lt;ul&gt;
&lt;li&gt;Google Sheets&lt;/li&gt;
&lt;li&gt;JSON&lt;/li&gt;
&lt;li&gt;CSV&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;automating-audits-with-awp&quot;&gt;Automating audits with AWP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#automating-audits-with-awp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AWP automates the performance audits via your preferred audit platforms such as
&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt;,
&lt;a href=&quot;https://webpagetest.org/&quot; rel=&quot;noopener&quot;&gt;WebPageTest&lt;/a&gt;, or
&lt;a href=&quot;https://developer.chrome.com/docs/crux/api/&quot; rel=&quot;noopener&quot;&gt;CrUX API&lt;/a&gt;.
AWP offers the flexibility to choose where to load the list of tests, and where
to write the results to.&lt;/p&gt;
&lt;p&gt;For example, you can run audits for a list of tests stored in a Google Sheet,
and write the results to a CSV file, with the command below:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;PSI_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;SHEETS_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ./awp run sheets:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SheetID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; csv:output.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;recurring-audits&quot;&gt;Recurring audits &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#recurring-audits&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can run recurring audits in daily, weekly, or monthly frequency. For
example, you can run daily audits for a list of tests defined in a local JSON
like below:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;tests&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;web.dev&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://web.dev&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;gatherer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;psi&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The command below reads the list of audit tests from the local JSON file, runs
audits on a local machine, then outputs results to a local CSV file:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;PSI_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ./awp run json:tests.json csv:output.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To run audits every day as a background service continuously, you can use the
command below instead:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;PSI_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ./awp &lt;span class=&quot;token builtin class-name&quot;&gt;continue&lt;/span&gt; json:tests.json csv:output.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Alternatively, you can set up the
&lt;a href=&quot;https://www.geeksforgeeks.org/how-to-setup-cron-jobs-in-ubuntu/&quot; rel=&quot;noopener&quot;&gt;crontab&lt;/a&gt; in a
Unix-like environment to run AWP as a daily cron job:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; * * * &lt;span class=&quot;token assign-left variable&quot;&gt;PSI_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ./awp run json:tests.json csv:output.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can find more ways to automate daily audits and result collection in the
&lt;a href=&quot;https://github.com/GoogleChromeLabs/AutoWebPerf&quot; rel=&quot;noopener&quot;&gt;AWP GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;data-studio&quot;&gt;Visualising audit results in Data Studio &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#data-studio&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Along with continuously measuring Core Web Vitals, it is important to be able to
evaluate the trends and discover potential regressions with real user metrics
(RUM) or the Chrome UX Report (CrUX) data collected by AWP. Note that
Chrome UX Report (CrUX) is a 28-day moving aggregation, hence it is recommended
to also use your own RUM data along with CrUX so you can spot regressions
sooner.&lt;/p&gt;
&lt;p&gt;Data Studio is a free visualization tool that you can easily load performance
metrics into and draw trends as charts. For example, the time series charts
below show Core Web Vitals based on Chrome UX Report data. One of the charts
shows increasing Cumulative Layout Shift in recent weeks, which means
regressions in the layout stability for certain pages. In this scenario, you
would want to prioritize the efforts to analyze the underlying issues of these
pages.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of Core Web Vitals results in Data Studio.&quot; decoding=&quot;async&quot; height=&quot;904&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Cpi7NkLvKyvf2xYzFwAn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;To simplify the end-to-end process from data collection to visualization, you
can run AWP with a list of URLs to automatically export results to Google Sheets
with the following command:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;PSI_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;SHEETS_APIKEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_KEY&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ./awp run sheets:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SheetID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; csv:output.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After collecting daily metrics in a spreadsheet, you can create a Data Studio
dashboard that loads the data directly from the spreadsheet, and plots the
trends into a time series chart. Check out &lt;a href=&quot;https://github.com/GoogleChromeLabs/AutoWebPerf/blob/stable/docs/sheets-connector.md&quot; rel=&quot;noopener&quot;&gt;Google Spreadsheets API
Connector&lt;/a&gt;
for detailed steps about how to set up AWP with spreadsheets as a data source to
visualize on Data Studio.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What&#39;s next? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/autowebperf/#whats-next&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AWP provides a simple and integrated way to minimize the efforts to set up a
continuous monitoring pipeline to measure Core Web Vitals and other performance
metrics. As for now, AWP covers the most common use cases and will continue to
provide more features to address other use cases in the future.&lt;/p&gt;
&lt;p&gt;Learn more in the &lt;a href=&quot;https://github.com/GoogleChromeLabs/AutoWebPerf&quot; rel=&quot;noopener&quot;&gt;AutoWebPerf&lt;/a&gt; repository.&lt;/p&gt;
</content>
    <author>
      <name>Jonathan Chen</name>
    </author><author>
      <name>Gilberto Cocchi</name>
    </author><author>
      <name>Antoine Bisch</name>
    </author>
  </entry>
  
  <entry>
    <title>Instant navigation experiences</title>
    <link href="https://web.dev/instant-navigation-experiences/"/>
    <updated>2020-06-23T00:00:00Z</updated>
    <id>https://web.dev/instant-navigation-experiences/</id>
    <content type="html" mode="escaped">&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;fhqCwDP69PI&quot; videoStartAt=&quot;285&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;Performing a task on a site commonly involves several steps. For example, purchasing a product in an e-commerce website might involve searching for a product, picking an item from the list of results, adding the item to the cart, and completing the operation by checking out.&lt;/p&gt;
&lt;p&gt;In technical terms, moving through different pages means making a &lt;strong&gt;navigation request&lt;/strong&gt;. As a general rule, you &lt;strong&gt;don&#39;t&lt;/strong&gt; want to use long-lived &lt;code&gt;Cache-Control&lt;/code&gt; headers to cache the HTML response for a navigation request. They should normally be satisfied via the network, with &lt;code&gt;Cache-Control: no-cache&lt;/code&gt;, to ensure that the HTML, along with the chain of subsequent network requests, is (reasonably) fresh.
Having to go against the network each time the user navigates to a new page unfortunately means that each navigation might be slow—at the very least, it means that it won&#39;t be &lt;em&gt;reliably&lt;/em&gt; fast.&lt;/p&gt;
&lt;p&gt;To speed up these requests, if you can anticipate the user&#39;s action, you can request these pages and assets beforehand and keep them in the cache for a short period of time until the user clicks on these links. This technique is called &lt;a href=&quot;https://web.dev/link-prefetch/&quot;&gt;prefetching&lt;/a&gt; and it&#39;s commonly implemented by adding &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tags to pages, indicating the resource to prefetch.&lt;/p&gt;
&lt;p&gt;In this guide we&#39;ll explore different ways in which &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Service_Worker_API&quot; rel=&quot;noopener&quot;&gt;service workers&lt;/a&gt; can be used as a complement of traditional prefetching techniques.&lt;/p&gt;
&lt;h2 id=&quot;production-cases&quot;&gt;Production cases &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#production-cases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.mercadolibre.com.ar/&quot; rel=&quot;noopener&quot;&gt;MercadoLibre&lt;/a&gt; is the biggest e-commerce site in Latin America. To speed up navigations, they dynamically inject &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tags in some parts of the flow. For example, in listing pages, they fetch the next result page as soon as the user scrolls to the bottom of the listing:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Screenshot of MercadoLibre&amp;#x27;s listing pages one and two and a Link Prefetch tag connecting both.&quot; decoding=&quot;async&quot; height=&quot;397&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 682px) 682px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/80D6QavdktSNb6xnhXE0.png?auto=format&amp;w=1364 1364w&quot; width=&quot;682&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Prefetched files are requested at the &amp;quot;Lowest&amp;quot; priority and stored in the &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;HTTP cache&lt;/a&gt; or the &lt;a href=&quot;https://calendar.perfplanet.com/2016/a-tale-of-four-caches/&quot; rel=&quot;noopener&quot;&gt;memory cache&lt;/a&gt; (depending on whether the resource is cacheable or not), for an amount of time that varies by browsers. For example, as of Chrome 85, this value is 5 minutes. Resources are kept around for five minutes, after which the normal &lt;code&gt;Cache-Control&lt;/code&gt; rules for the resource apply.&lt;/p&gt;
&lt;p&gt;Using service worker caching can help you extend the lifetime of prefetch resources beyond the five-minute window.&lt;/p&gt;
&lt;p&gt;For example, Italian sports portal &lt;a href=&quot;https://sport.virgilio.it/&quot; rel=&quot;noopener&quot;&gt;Virgilio Sport&lt;/a&gt; uses service workers to prefetch the most popular posts in their home page. They also use the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Network_Information_API&quot; rel=&quot;noopener&quot;&gt;Network Information API&lt;/a&gt; to avoid prefetching for users that are on a 2G connection.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Virgilio Sport logo.&quot; decoding=&quot;async&quot; height=&quot;100&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 340px) 340px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bqiSoliDKZ9SR1NX2Ek3.png?auto=format&amp;w=680 680w&quot; width=&quot;340&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;As a result of this, over 3 weeks of observation Virgilio Sport witnessed load times for navigation to articles improve &lt;strong&gt;78%&lt;/strong&gt;, and the number of article impressions increase &lt;strong&gt;45%&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of Virgilio Sport home and article pages, with impact metrics after prefetching.&quot; decoding=&quot;async&quot; height=&quot;442&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 536px) 536px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/wn7OR4CA21QJUYhs8OUu.png?auto=format&amp;w=1072 1072w&quot; width=&quot;536&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;implement-precaching-with-workbox&quot;&gt;Implement precaching with Workbox &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#implement-precaching-with-workbox&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the following section we&#39;ll use &lt;a href=&quot;https://web.dev/workbox/&quot;&gt;Workbox&lt;/a&gt; to show how to implement different caching techniques in the service worker that can be used as a complement to &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt;, or even a replacement for it, by delegating this task completely to the service worker.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; You must take steps to ensure that adding a service worker to your site doesn&#39;t end up actually slowing down your navigations. Starting up the service worker without using it to respond to a navigation request will introduce a small amount of latency (as explained in &lt;a href=&quot;https://www.youtube.com/watch?v=25aCD5XL1Jk&quot;&gt;Building Faster, More Resilient Apps with Service Workers&lt;/a&gt;). You can mitigate this overhead by enabling a feature called &lt;a href=&quot;https://developer.chrome.com/blog/navigation-preload/&quot;&gt;navigation preload&lt;/a&gt;, and then using the &lt;a href=&quot;https://developer.chrome.com/blog/navigation-preload/#using-the-preloaded-response&quot;&gt;network response&lt;/a&gt; that&#39;s been preloaded inside of your fetch event handler. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;1-precache-static-pages-and-page-subresources&quot;&gt;1. Precache static pages and page subresources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#1-precache-static-pages-and-page-subresources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/precache-with-workbox/&quot;&gt;Precaching&lt;/a&gt; is the ability of the service worker to save files to the cache while it&#39;s installing.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Precaching sounds similar to prefetching, but it&#39;s a different technique. In the first one, the service worker fetches and stores resources (typically static files) while it&#39;s installing and keeps them in the cache until a new version of the file is available. In the second, resources are requested ahead of time to have it in the cache for brief periods of time in order to speed up subsequent navigations. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;In the following cases precaching is used to achieve a similar goal as prefetching: making navigations faster.&lt;/p&gt;
&lt;h4 id=&quot;precaching-static-pages&quot;&gt;Precaching static pages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#precaching-static-pages&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For pages that are generated at build time (e.g. &lt;code&gt;about.html&lt;/code&gt;, &lt;code&gt;contact.html&lt;/code&gt;), or in completely static sites, one can just add the site&#39;s documents to the precache list, so they are already available in the cache every time the user accesses them:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;workbox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;precaching&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;precacheAndRoute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/about.html&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;revision&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;abcd1234&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ... other entries ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;precaching-page-subresources&quot;&gt;Precaching page subresources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#precaching-page-subresources&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Precaching static assets that the different sections of the site might use (e.g. JavaScript, CSS, etc.), is a general best practice and can give an extra boost in prefetching scenarios.&lt;/p&gt;
&lt;p&gt;To speed up navigations in an e-commerce site, you can use  &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tags in listing pages to prefetch product detail pages for the first few products of a listing page. If you have already precached the product page subresources, this can make the navigation even faster.&lt;/p&gt;
&lt;p&gt;To implement this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tag to the page:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;prefetch&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/phones/smartphone-5x.html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Add the page subresources to the precache list in the service worker:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;workbox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;precaching&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;precacheAndRoute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&#39;/styles/product-page.ac29.css&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ... other entries ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;2-extend-the-lifetime-of-prefetch-resources&quot;&gt;2. Extend the lifetime of prefetch resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#2-extend-the-lifetime-of-prefetch-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; fetches and keeps resources in the HTTP cache for a limited amount of time, after which point the &lt;code&gt;Cache-Control&lt;/code&gt; rules for a resource apply. As of Chrome 85, this value is 5 minutes.&lt;/p&gt;
&lt;p&gt;Service workers allow you to extend the lifetime of the prefetch pages, while providing the added benefit of making those resources available for offline usage.&lt;/p&gt;
&lt;p&gt;In the previous example, one could complement the &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; used to prefetch a product page with a &lt;a href=&quot;https://web.dev/runtime-caching-with-workbox/&quot;&gt;Workbox runtime caching strategy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To implement that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tag to the page:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;prefetch&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/phones/smartphone-5x.html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Implement a runtime caching strategy in the service worker for these types of requests:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;workbox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;strategies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StaleWhileRevalidate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;cacheName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;document-cache&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;workbox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;expiration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Plugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;maxAgeSeconds&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 30 Days&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this case, we have opted to use a &lt;a href=&quot;https://developer.chrome.com/docs/workbox/modules/workbox-strategies/#stale-while-revalidate&quot; rel=&quot;noopener&quot;&gt;stale-while-revalidate strategy&lt;/a&gt;. In this strategy, pages can be requested from both the cache and the network, in parallel. The response comes from the cache if available, otherwise from the network. The cache is always kept up to date with the network response with each successful request.&lt;/p&gt;
&lt;h3 id=&quot;3-delegate-prefetching-to-the-service-worker&quot;&gt;3. Delegate prefetching to the service worker &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/instant-navigation-experiences/#3-delegate-prefetching-to-the-service-worker&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In most cases the best approach is to use &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt;. The tag is a &lt;a href=&quot;https://www.w3.org/TR/resource-hints/&quot; rel=&quot;noopener&quot;&gt;resource hint&lt;/a&gt; designed to make prefetching as efficient as possible.&lt;/p&gt;
&lt;p&gt;In some cases, though, it might be better to delegate this task completely to the service worker.
For example: to prefetch the first few products in a client-side rendered product listing page, one might need to inject several &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; tags dynamically in the page, based on an API response. This can momentarily consume time on the page&#39;s main thread and make the implementation more difficult.&lt;/p&gt;
&lt;p&gt;In cases like this, use a &amp;quot;page to service worker communication strategy&amp;quot;, to delegate the task of prefetching completely to the service worker. This type of communication can be achieved by using &lt;a href=&quot;https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage&quot; rel=&quot;noopener&quot;&gt;worker.postMessage()&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;An icon of a page making two way communication with a service worker.&quot; decoding=&quot;async&quot; height=&quot;205&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 626px) 626px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/vokHySREOo6Y3PpxzxRC.png?auto=format&amp;w=1252 1252w&quot; width=&quot;626&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/workbox/modules/workbox-window/&quot; rel=&quot;noopener&quot;&gt;Workbox Window package&lt;/a&gt; simplifies this type of communication, abstracting many details of the underlying call being done.&lt;/p&gt;
&lt;p&gt;Prefetching with Workbox Window can be implemented in the following way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the page: call the service worker passing it the type of message, and the list of URLs to prefetch:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Workbox&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/sw.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;wb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prefetchResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; wb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;messageSW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;PREFETCH_URLS&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;In the service worker: implement a message handler to issue a &lt;code&gt;fetch()&lt;/code&gt; request for each URL to prefetch:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;PREFETCH_URLS&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Fetch URLs and store them in the cache&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
    <author>
      <name>Demian Renzulli</name>
    </author><author>
      <name>Jeff Posnick</name>
    </author><author>
      <name>Gilberto Cocchi</name>
    </author>
  </entry>
</feed>
