CINXE.COM
Migrate to User-Agent Client Hints | Articles | web.dev
<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="157101835696-ooapojlodmuabs2do2vuhhnf90bccmoi.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="web.dev"> <meta property="og:type" content="website"><meta name="theme-color" content="#3740ff"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/web/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/css/app.css"> <link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/css/dark-theme.css" disabled> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/favicon.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/touchicon-180.png"><link rel="canonical" href="https://web.dev/articles/migrate-to-ua-ch"><link rel="search" type="application/opensearchdescription+xml" title="web.dev" href="https://web.dev/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://web.dev/articles/migrate-to-ua-ch" /><link rel="alternate" hreflang="x-default" href="https://web.dev/articles/migrate-to-ua-ch" /><link rel="alternate" hreflang="ar" href="https://web.dev/articles/migrate-to-ua-ch?hl=ar" /><link rel="alternate" hreflang="bn" href="https://web.dev/articles/migrate-to-ua-ch?hl=bn" /><link rel="alternate" hreflang="zh-Hans" href="https://web.dev/articles/migrate-to-ua-ch?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://web.dev/articles/migrate-to-ua-ch?hl=zh-tw" /><link rel="alternate" hreflang="fa" href="https://web.dev/articles/migrate-to-ua-ch?hl=fa" /><link rel="alternate" hreflang="fr" href="https://web.dev/articles/migrate-to-ua-ch?hl=fr" /><link rel="alternate" hreflang="de" href="https://web.dev/articles/migrate-to-ua-ch?hl=de" /><link rel="alternate" hreflang="he" href="https://web.dev/articles/migrate-to-ua-ch?hl=he" /><link rel="alternate" hreflang="hi" href="https://web.dev/articles/migrate-to-ua-ch?hl=hi" /><link rel="alternate" hreflang="id" href="https://web.dev/articles/migrate-to-ua-ch?hl=id" /><link rel="alternate" hreflang="it" href="https://web.dev/articles/migrate-to-ua-ch?hl=it" /><link rel="alternate" hreflang="ja" href="https://web.dev/articles/migrate-to-ua-ch?hl=ja" /><link rel="alternate" hreflang="ko" href="https://web.dev/articles/migrate-to-ua-ch?hl=ko" /><link rel="alternate" hreflang="pl" href="https://web.dev/articles/migrate-to-ua-ch?hl=pl" /><link rel="alternate" hreflang="pt-BR" href="https://web.dev/articles/migrate-to-ua-ch?hl=pt-br" /><link rel="alternate" hreflang="ru" href="https://web.dev/articles/migrate-to-ua-ch?hl=ru" /><link rel="alternate" hreflang="es" href="https://web.dev/articles/migrate-to-ua-ch?hl=es" /><link rel="alternate" hreflang="es-419" href="https://web.dev/articles/migrate-to-ua-ch?hl=es-419" /><link rel="alternate" hreflang="th" href="https://web.dev/articles/migrate-to-ua-ch?hl=th" /><link rel="alternate" hreflang="tr" href="https://web.dev/articles/migrate-to-ua-ch?hl=tr" /><link rel="alternate" hreflang="vi" href="https://web.dev/articles/migrate-to-ua-ch?hl=vi" /><link rel="alternate" hreflang="en-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch" /><link rel="alternate" hreflang="x-default" href="https://web.developers.google.cn/articles/migrate-to-ua-ch" /><link rel="alternate" hreflang="ar-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=ar" /><link rel="alternate" hreflang="bn-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=bn" /><link rel="alternate" hreflang="zh-Hans-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=zh-tw" /><link rel="alternate" hreflang="fa-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=fa" /><link rel="alternate" hreflang="fr-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=fr" /><link rel="alternate" hreflang="de-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=de" /><link rel="alternate" hreflang="he-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=he" /><link rel="alternate" hreflang="hi-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=hi" /><link rel="alternate" hreflang="id-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=id" /><link rel="alternate" hreflang="it-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=it" /><link rel="alternate" hreflang="ja-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=ja" /><link rel="alternate" hreflang="ko-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=ko" /><link rel="alternate" hreflang="pl-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=pl" /><link rel="alternate" hreflang="pt-BR-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=pt-br" /><link rel="alternate" hreflang="ru-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=ru" /><link rel="alternate" hreflang="es-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=es" /><link rel="alternate" hreflang="es-419-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=es-419" /><link rel="alternate" hreflang="th-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=th" /><link rel="alternate" hreflang="tr-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=tr" /><link rel="alternate" hreflang="vi-cn" href="https://web.developers.google.cn/articles/migrate-to-ua-ch?hl=vi" /><title>Migrate to User-Agent Client Hints | Articles | web.dev</title> <meta property="og:title" content="Migrate to User-Agent Client Hints | Articles | web.dev"><meta name="description" content="Strategies to migrate your site from relying on the user-agent string to the new User-Agent Client Hints."> <meta property="og:description" content="Strategies to migrate your site from relying on the user-agent string to the new User-Agent Client Hints."><meta property="og:url" content="https://web.dev/articles/migrate-to-ua-ch"><meta property="og:locale" content="en"><script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "dateModified": "2021-05-19", "headline": "Migrate to User-Agent Client Hints" } </script><script type="application/ld+json"> { "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{ "@type": "ListItem", "position": 1, "name": "Articles", "item": "https://web.dev/articles" },{ "@type": "ListItem", "position": 2, "name": "Migrate to User-Agent Client Hints", "item": "https://web.dev/articles/migrate-to-ua-ch" }] } </script> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="page" theme="web-theme" type="article" appearance layout="docs" display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner"> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="webDev" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup-dark-theme.svg" media="(prefers-color-scheme: dark)" class="devsite-dark-theme" alt="web.dev"> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup.svg" class="devsite-site-logo" alt="web.dev"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> </li> </ul> </span> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> <devsite-tabs class="upper-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Upper tabs"> <tab > <a href="https://web.dev/about" track-metadata-eventdetail="https://web.dev/about" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - about" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: About" track-name="about" > About </a> </tab> <tab > <a href="https://web.dev/html" track-metadata-eventdetail="https://web.dev/html" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - html" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: HTML" track-name="html" > HTML </a> </tab> <tab > <a href="https://web.dev/css" track-metadata-eventdetail="https://web.dev/css" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - css" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: CSS" track-name="css" > CSS </a> </tab> <tab > <a href="https://web.dev/javascript" track-metadata-eventdetail="https://web.dev/javascript" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - javascript" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: JavaScript" track-name="javascript" > JavaScript </a> </tab> <tab > <a href="https://web.dev/blog" track-metadata-eventdetail="https://web.dev/blog" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - blog" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Blog" track-name="blog" > Blog </a> </tab> <tab > <a href="https://web.dev/learn" track-metadata-eventdetail="https://web.dev/learn" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - learn" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Learn" track-name="learn" > Learn </a> </tab> <tab > <a href="https://web.dev/explore" track-metadata-eventdetail="https://web.dev/explore" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - explore" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Explore" track-name="explore" > Explore </a> </tab> <tab > <a href="https://web.dev/patterns" track-metadata-eventdetail="https://web.dev/patterns" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - patterns" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Patterns" track-name="patterns" > Patterns </a> </tab> <tab > <a href="https://web.dev/case-studies" track-metadata-eventdetail="https://web.dev/case-studies" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - case studies" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Case studies" track-name="case studies" > Case studies </a> </tab> </nav> </devsite-tabs> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion project-name="Articles" tenant-name="web.dev" > <form class="devsite-search-form" action="https://web.dev/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-appearance-selector></devsite-appearance-selector> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <devsite-user enable-profiles id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> <div class="devsite-collapsible-section devsite-header-no-lower-tabs "> <div class="devsite-header-background"> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars hidden> <div class="devsite-book-nav-filter" hidden> <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="webDev" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <source srcset="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup-dark-theme.svg" media="(prefers-color-scheme: dark)" class="devsite-dark-theme" alt="web.dev"> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup.svg" class="devsite-site-logo" alt="web.dev"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> </li> </ul> </span> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> <li class="devsite-nav-item"> <a href="/about" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: About" track-name="about" data-category="Site-Wide Custom Events" data-label="Responsive Tab: About" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > About </span> </a> </li> <li class="devsite-nav-item"> <a href="/html" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: HTML" track-name="html" data-category="Site-Wide Custom Events" data-label="Responsive Tab: HTML" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > HTML </span> </a> </li> <li class="devsite-nav-item"> <a href="/css" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: CSS" track-name="css" data-category="Site-Wide Custom Events" data-label="Responsive Tab: CSS" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > CSS </span> </a> </li> <li class="devsite-nav-item"> <a href="/javascript" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: JavaScript" track-name="javascript" data-category="Site-Wide Custom Events" data-label="Responsive Tab: JavaScript" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > JavaScript </span> </a> </li> <li class="devsite-nav-item"> <a href="/blog" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Blog" track-name="blog" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Blog" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Blog </span> </a> </li> <li class="devsite-nav-item"> <a href="/learn" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Learn" track-name="learn" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Learn" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Learn </span> </a> </li> <li class="devsite-nav-item"> <a href="/explore" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Explore" track-name="explore" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Explore" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Explore </span> </a> </li> <li class="devsite-nav-item"> <a href="/patterns" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Patterns" track-name="patterns" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Patterns" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Patterns </span> </a> </li> <li class="devsite-nav-item"> <a href="/case-studies" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Case studies" track-name="case studies" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Case studies" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Case studies </span> </a> </li> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" has-sidebar > <div class="devsite-sidebar"> <div class="devsite-sidebar-content"> <devsite-toc class="devsite-nav" role="navigation" aria-label="On this page" depth="2" scrollbars ></devsite-toc> <devsite-recommendations-sidebar class="nocontent devsite-nav"> </devsite-recommendations-sidebar> </div> </div> <devsite-content> <article class="devsite-article"> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" aria-label="Breadcrumb"> <li class="devsite-breadcrumb-item "> <a href="https://web.dev/" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="" > Home </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://web.dev/articles" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="2" track-type="globalNav" track-name="breadcrumb" track-metadata-position="2" track-metadata-eventdetail="Articles" > Articles </a> </li> </ul> <devsite-thumb-rating position="header"> </devsite-thumb-rating> </div> <h1 class="devsite-page-title" tabindex="-1"> Migrate to User-Agent Client Hints </h1> <devsite-feature-tooltip ack-key="AckCollectionsBookmarkTooltipDismiss" analytics-category="Site-Wide Custom Events" analytics-action-show="Callout Profile displayed" analytics-action-close="Callout Profile dismissed" analytics-label="Create Collection Callout" class="devsite-page-bookmark-tooltip nocontent" dismiss-button="true" id="devsite-collections-dropdown" dismiss-button-text="Dismiss" close-button-text="Got it"> <devsite-bookmark></devsite-bookmark> <span slot="popout-heading"> Stay organized with collections </span> <span slot="popout-contents"> Save and categorize content based on your preferences. </span> </devsite-feature-tooltip> <div class="devsite-page-title-meta"><devsite-view-release-notes></devsite-view-release-notes></div> <devsite-toc class="devsite-nav" depth="2" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <p>Strategies to migrate your site from relying on the user-agent string to the new User-Agent Client Hints.</p> <p> <div class="wd-authors" translate="no"> <div class="wd-author"> <img class="devsite-landing-row-item-icon" alt="Rowan Merewood" src="https://web.dev/images/authors/rowan_m.jpg" decoding="async" height="64" loading="lazy" width="64"> <div> <span> Rowan Merewood </span> <div class="wd-author__links"> <a href="https://twitter.com/rowan_m" aria-label="Rowan Merewood on X" rel="me"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 300 271"> <title>X</title> <path fill="currentColor" d="m236 0h46l-101 115 118 156h-92.6l-72.5-94.8-83 94.8h-46l107-123-113-148h94.9l65.5 86.6zm-16.1 244h25.5l-165-218h-27.4z"></path> </svg></a> <a href="https://github.com/rowan-m" aria-label="Rowan Merewood on GitHub" rel="me"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 32.6 31.8"> <title>GitHub</title> <path d="M16.3 0C7.3 0 0 7.3 0 16.3c0 7.2 4.7 13.3 11.1 15.5.8.1 1.1-.4 1.1-.8v-2.8c-4.5 1-5.5-2.2-5.5-2.2-.7-1.9-1.8-2.4-1.8-2.4-1.5-1 .1-1 .1-1 1.6.1 2.5 1.7 2.5 1.7 1.5 2.5 3.8 1.8 4.7 1.4.1-1.1.6-1.8 1-2.2-3.6-.4-7.4-1.8-7.4-8.1 0-1.8.6-3.2 1.7-4.4-.1-.3-.7-2 .2-4.2 0 0 1.4-.4 4.5 1.7 1.3-.4 2.7-.5 4.1-.5 1.4 0 2.8.2 4.1.5 3.1-2.1 4.5-1.7 4.5-1.7.9 2.2.3 3.9.2 4.3 1 1.1 1.7 2.6 1.7 4.4 0 6.3-3.8 7.6-7.4 8 .6.5 1.1 1.5 1.1 3V31c0 .4.3.9 1.1.8 6.5-2.2 11.1-8.3 11.1-15.5C32.6 7.3 25.3 0 16.3 0z" fill-rule="evenodd" clip-rule="evenodd" fill="currentColor" /> </svg></a> <a href="https://glitch.com/@rowan-m" aria-label="Rowan Merewood on Glitch" rel="me"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 32 32"> <title>Glitch</title> <path fill="currentColor" d="M31.734 16.76c-.385-.198-4.536 1.865-5.427 1.693-2.24-.401-1.828-.667-4.839-1.359-1.203-.266-1.031-.109-1.297-.307-.172-.135-.344-.161-.599-.401 4-.719 6.026-1.693 6.734-1.839.76-.146 5.161 1.958 5.427 1.469.266-.495-.964-1.578-.401-3.031.589-1.464-.693-2.422.016-3.583.719-1.161.573-2.932.396-3.026-.396-.203-4.531 1.865-5.438 1.693-2.24-.417-1.828-.682-4.839-1.359-1.203-.271-1.031-.12-1.297-.323-.266-.198-.521-.13-1.036-.974-.521-.839-6.51-2.13-6.906-2.13-.828 0-2.375 2.13-2.375 2.13s-.599 0-2.401.094c-1.802.094-3.375.896-5.495 2.563C-.173 9.737.134 11.414.134 11.414s1.969.667 1.969 1.042c0 .359-1.729.802-1.729.802 1.12 1.411 4.583 2.745 5.464 2.745h.693c-1.438.281-2.823 1.068-4.583 2.438-2.12 1.698-1.813 3.375-1.813 3.375s1.969.667 1.969 1.026-1.729.802-1.729.802c1.12 1.427 4.583 2.76 5.464 2.76.844 0 1.427.026 2.495-.172.078.172.906 1.932 2.599 2.292 1.786.385 2.776.078 2.776.078s.094-.786-.323-1.573c1.547.161 3.307.203 5.026-.068 4.76-.719 7.12-1.865 7.896-2.01.76-.161 5.161 1.948 5.427 1.464.266-.505-.964-1.583-.385-3.036.573-1.469-.708-2.417 0-3.589.719-1.161.573-2.932.396-3.026zM4.615 11.828a1.446 1.446 0 0 1-.297-.042h-.052c-.026-.01-.052-.026-.078-.042l-.052-.01-.083-.042h-.052a.418.418 0 0 1-.068-.042l-.068-.052-.063-.036-.057-.042c-.021-.016-.042-.036-.063-.052l-.042-.042c-.026-.026-.047-.052-.068-.078l-.026-.031a1.954 1.954 0 0 1-.094-.104l-.026-.026c-.021-.036-.036-.073-.052-.109l-.026-.036-.057-.083c-.005-.021-.016-.042-.026-.063l-.026-.083-.026-.052-.016-.094-.01-.068c-.01-.026-.021-.052-.026-.078v-.068c.094.573.557 1.016 1.104 1.016.63 0 1.146-.573 1.146-1.297 0-.719-.505-1.307-1.146-1.307-.625 0-1.13.573-1.146 1.281 0-.932.667-1.693 1.495-1.693.823 0 1.479.745 1.479 1.682 0 .932-.667 1.693-1.479 1.693zm-1-1.265c0-.203.13-.365.318-.365s.307.161.307.365c0 .198-.135.344-.307.344s-.318-.161-.318-.344zm1 11.651a.712.712 0 0 1-.146 0l-.057-.016a.6.6 0 0 1-.094-.01l-.052-.016-.078-.026-.052-.026c-.031-.005-.057-.016-.083-.026l-.052-.026c-.021-.016-.047-.026-.068-.042L3.881 22l-.068-.052-.052-.042-.068-.052-.042-.042c-.031-.031-.063-.057-.089-.094a.671.671 0 0 1-.094-.12l-.031-.026c-.016-.031-.036-.063-.052-.094l-.026-.052c-.016-.026-.036-.052-.052-.078l-.026-.057-.026-.094-.026-.052-.031-.094-.01-.052c-.01-.031-.021-.063-.026-.094v-.068c.094.573.557 1.016 1.104 1.016.63 0 1.146-.573 1.146-1.292 0-.724-.505-1.297-1.146-1.297-.625 0-1.13.563-1.146 1.266 0-.932.667-1.693 1.495-1.693.823 0 1.479.76 1.479 1.682 0 .917-.667 1.693-1.479 1.693zm-1-1.266c0-.188.13-.349.318-.349s.307.161.307.349c0 .188-.135.344-.307.344s-.318-.146-.318-.344zm6.77-7.333v-.042l.042-.078.078-.297c.182-.583.344-1.172.479-1.771.161-.708.229-1.281.203-1.599-.016-.12-.031-.245-.052-.359a8.276 8.276 0 0 0-.521-1.724l-.083-.172-.026-.068c-.12-.266.057-.573.323-.557h.188l.531.036 2.104.109 1.151.078a28.24 28.24 0 0 1 10.573 2.828l.891.401c.172.078.266.307.188.505-.068.188-.266.292-.438.214l-.896-.401a27.695 27.695 0 0 0-10.359-2.786l-1.146-.068-.51-.026-1.599-.094h-.156c.188.51.339 1.031.453 1.562l.063.427c.042.453-.036 1.078-.224 1.88l-.203.823a23.62 23.62 0 0 1-.385 1.323l-.026.078v.042c-.068.188-.266.292-.438.214-.177-.068-.271-.292-.203-.495zm-2-6.349a.307.307 0 0 1 .479.026c.208.26.396.536.563.828.292.531.495 1.068.547 1.615.026.307 0 .651-.052 1.026a8.718 8.718 0 0 1-.271 1.104c-.094.313-.208.62-.333.922-.078.188-.276.266-.453.172-.172-.094-.24-.318-.156-.521l.026-.052.068-.172c.073-.198.146-.396.214-.599.099-.328.182-.661.24-1 .052-.307.063-.573.052-.802a3.47 3.47 0 0 0-.453-1.292 4.794 4.794 0 0 0-.443-.667l-.036-.042a.417.417 0 0 1 .026-.531zm1.537 13.869c-.063.38-.151.76-.271 1.13a9.549 9.549 0 0 1-.333.906c-.078.188-.276.266-.453.177-.172-.094-.24-.323-.156-.521l.026-.057.068-.172c.073-.198.146-.396.214-.599.099-.328.182-.661.24-1 .052-.307.063-.573.036-.802a3.365 3.365 0 0 0-.438-1.276 4.794 4.794 0 0 0-.443-.667l-.036-.057a.417.417 0 0 1 .026-.531.3.3 0 0 1 .464 0c.214.266.396.547.563.839.292.536.495 1.083.547 1.615.026.307 0 .651-.052 1.026zm16.531.157c-.068.188-.266.297-.438.214l-.896-.401a27.695 27.695 0 0 0-10.359-2.786l-1.135-.063h-.063l-.458-.026c-.583-.036-1.172-.068-1.755-.094l.036.078c.234.615.396 1.255.479 1.906.042.453-.036 1.078-.224 1.88l-.203.828a24.99 24.99 0 0 1-.385 1.333l-.026.068v.036c-.068.203-.266.297-.438.229a.42.42 0 0 1-.203-.51v-.026l.042-.078.078-.292c.182-.589.344-1.177.479-1.776.161-.708.229-1.281.203-1.599-.016-.12-.031-.24-.052-.359a7.996 7.996 0 0 0-.521-1.708l-.052-.12-.031-.068-.026-.063c-.12-.271.057-.578.323-.563h.188l.531.042 2.12.104 1.135.083a28.14 28.14 0 0 1 10.573 2.823l.891.401c.172.078.266.307.188.505z"/> </svg></a> <a href="https://mastodon.social/@rowan_m" aria-label="Rowan Merewood on Mastodon" rel="me"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 16 16"> <title>Mastodon</title> <path fill="currentColor" d="M 15.659 9.592 C 15.424 10.72 13.553 11.956 11.404 12.195 C 10.283 12.32 9.18 12.434 8.003 12.384 C 6.079 12.302 4.56 11.956 4.56 11.956 C 4.56 12.13 4.572 12.297 4.595 12.452 C 4.845 14.224 6.478 14.33 8.025 14.379 C 9.586 14.429 10.976 14.02 10.976 14.02 L 11.04 15.337 C 11.04 15.337 9.948 15.884 8.003 15.984 C 6.93 16.039 5.598 15.959 4.047 15.576 C 0.683 14.746 0.104 11.4 0.015 8.006 C -0.012 6.998 0.005 6.048 0.005 5.253 C 0.005 1.782 2.443 0.765 2.443 0.765 C 3.672 0.238 5.782 0.017 7.975 0 L 8.029 0 C 10.221 0.017 12.332 0.238 13.561 0.765 C 13.561 0.765 15.999 1.782 15.999 5.253 C 15.999 5.253 16.03 7.814 15.659 9.592 Z M 13.124 5.522 L 13.124 9.725 L 11.339 9.725 L 11.339 5.646 C 11.339 4.786 10.951 4.35 10.175 4.35 C 9.317 4.35 8.887 4.867 8.887 5.891 L 8.887 8.124 L 7.113 8.124 L 7.113 5.891 C 7.113 4.867 6.683 4.35 5.825 4.35 C 5.049 4.35 4.661 4.786 4.661 5.646 L 4.661 9.725 L 2.876 9.725 L 2.876 5.522 C 2.876 4.663 3.111 3.981 3.582 3.476 C 4.067 2.971 4.703 2.712 5.493 2.712 C 6.406 2.712 7.098 3.039 7.555 3.695 L 8 4.39 L 8.445 3.695 C 8.902 3.039 9.594 2.712 10.507 2.712 C 11.297 2.712 11.933 2.971 12.418 3.476 C 12.889 3.981 13.124 4.663 13.124 5.522 Z" style="stroke:none;stroke-miterlimit:10;fill-rule:evenodd;"></path> </svg></a> </div> </div> </div> </div></p> <p>The <a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/User-Agent">User-Agent string</a> is a significant <a href="https://w3c.github.io/fingerprinting-guidance/#passive">passive fingerprinting surface</a> in browsers, as well as being difficult to process. However, there are all kinds of valid reasons for collecting and processing user-agent data, so what's needed is a path to a better solution. User-Agent Client Hints provide both an explicit way to declare your need for user-agent data and methods to return the data in an easy-to-use format.</p> <aside class="note"><b>Note: </b> For more information on Client Hints and expanding them with user-agent data, read the <a href="/articles/user-agent-client-hints">introductory article on User-Agent Client Hints</a>. </aside> <p>This article will take you through auditing your access to user-agent data and migrating user-agent string usage to User-Agent Client Hints.</p> <h2 id="audit_collection_and_use_of_user-agent_data" data-text="Audit collection and use of user-agent data" tabindex="-1">Audit collection and use of user-agent data</h2> <p>As with any form of data collection, you should always understand <strong>why</strong> you are collecting it. The first step, regardless of whether or not you will be taking any action, is to understand where and why you are using user-agent data.</p> <p>If you don't know if or where user-agent data is being used, consider searching your front-end code for use of <code translate="no" dir="ltr">navigator.userAgent</code> and your back-end code for use of the <code translate="no" dir="ltr">User-Agent</code> HTTP header. You should also check your front-end code for use of already deprecated features, such as <code translate="no" dir="ltr">navigator.platform</code> and <code translate="no" dir="ltr">navigator.appVersion</code>.</p> <p>From a functional point of view, think about anywhere in your code where you are recording or processing:</p> <ul> <li>Browser name or version</li> <li>Operating system name or version</li> <li>Device make or model</li> <li>CPU type, architecture, or bitness (for example, 64-bit)</li> </ul> <p>It's also likely that you may be using a third-party library or service to process the user-agent. In this case, check to see if they are updating to support User-Agent Client Hints.</p> <h3 id="are_you_only_using_basic_user-agent_data" data-text="Are you only using basic user-agent data?" tabindex="-1">Are you only using basic user-agent data?</h3> <p>The default set of User-Agent Client Hints includes:</p> <ul> <li><code translate="no" dir="ltr">Sec-CH-UA</code>: browser name and major/significant version</li> <li><code translate="no" dir="ltr">Sec-CH-UA-Mobile</code>: boolean value indicating a mobile device</li> <li><code translate="no" dir="ltr">Sec-CH-UA-Platform</code>: operating system name <ul> <li><em>Note that this has been updated in the spec and will be <a href="https://groups.google.com/a/chromium.org/g/blink-dev/c/dafizBGwWMw/m/72l-1zm6AAAJ">reflected in Chrome</a> and other Chromium-based browsers shortly.</em></li> </ul></li> </ul> <p>The reduced version of the user-agent string that is proposed will also retain this basic information in a backwards-compatible way. For example, instead of <code translate="no" dir="ltr">Chrome/90.0.4430.85</code> the string would include <code translate="no" dir="ltr">Chrome/90.0.0.0</code>.</p> <p>If you are only checking the user-agent string for browser name, major version, or operating system, then your code will continue to work though you are likely to see deprecation warnings.</p> <p>While you can and should migrate to User-Agent Client Hints, you may have legacy code or resource constraints that prevent this. The reduction of information in the user-agent string in this backwards-compatible way is intended to ensure that while existing code will receive less detailed information, it should still retain basic functionality.</p> <h2 id="strategy_on-demand_client-side_javascript_api" data-text="Strategy: On-demand client-side JavaScript API" tabindex="-1">Strategy: On-demand client-side JavaScript API</h2> <p>If you are currently using <code translate="no" dir="ltr">navigator.userAgent</code> you should transition to preferring <code translate="no" dir="ltr">navigator.userAgentData</code> before falling back to parsing the user-agent string.</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">navigator</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">userAgentData</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// use new hints</span> <span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// fall back to user-agent string parsing</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>If you are checking for mobile or desktop, use the boolean <code translate="no" dir="ltr">mobile</code> value:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">isMobile</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">navigator</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">userAgentData</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">mobile</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> <p><code translate="no" dir="ltr">userAgentData.brands</code> is an array of objects with <code translate="no" dir="ltr">brand</code> and <code translate="no" dir="ltr">version</code> properties where the browser is able to list its compatibility with those brands. You can access it directly as an array or you may want to use a <code translate="no" dir="ltr">some()</code> call to check if a specific entry is present:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-kd">function</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">isCompatible</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">item</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// In real life you most likely have more complex rules here</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s1">'Chromium'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'Google Chrome'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'NewBrowser'</span><span class="devsite-syntax-p">].</span><span class="devsite-syntax-nx">includes</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">item</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">brand</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">navigator</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">userAgentData</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">brands</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">some</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">isCompatible</span><span class="devsite-syntax-p">))</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// browser reports as compatible</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <aside class="tip"> <code translate="no" dir="ltr">userAgentData.brands</code> will contain varying values in a varying order, so don't rely on something appearing at a certain index. </aside> <p>If you need one of the more detailed, high-entropy user-agent values, you will need to specify it and check for the result in the returned <code translate="no" dir="ltr">Promise</code>:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-nx">navigator</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">userAgentData</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">getHighEntropyValues</span><span class="devsite-syntax-p">([</span><span class="devsite-syntax-s1">'model'</span><span class="devsite-syntax-p">])</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">then</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">ua</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// requested hints available as attributes</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-kd">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">model</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">ua</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">model</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> </code></pre></devsite-code> <p>You may also want to use this strategy if you would like to move from server-side processing to client-side processing. The JavaScript API does not require access to HTTP request headers, so user-agent values can be requested at any point.</p> <aside class="note"><b>Note: </b> Try the <a href="https://user-agent-client-hints.glitch.me/javascript.html">User-Agent Client Hints JavaScript API demo</a>. </aside> <h2 id="strategy_static_server-side_header" data-text="Strategy: Static server-side header" tabindex="-1">Strategy: Static server-side header</h2> <p>If you are using the <code translate="no" dir="ltr">User-Agent</code> request header on the server and your needs for that data are relatively consistent across your entire site, then you can specify the desired client hints as a static set in your responses. This is a relatively simple approach since you generally only need to configure it in one location. For example, it may be in your web server configuration if you already add headers there, your hosting configuration, or top-level configuration of the framework or platform you use for your site.</p> <p>Consider this strategy if you are transforming or customizing the responses served based on the user-agent data.</p> <aside class="note"><b>Note: </b> You can also consider migrating to the <a href="#strategy_on-demand_client-side_javascript_api">On-demand client-side JavaScript API</a> strategy instead of sending additional headers. </aside> <p>Browsers or other clients may choose to supply different default hints, so it's good practice to specify everything you need, even if it's generally provided by default.</p> <p>For example, the current defaults for Chrome would be represented as:</p> <p>⬇️ Response headers</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA </code></pre></devsite-code> <p>If you also wanted to receive the device model in responses, then you would send:</p> <p>⬇️ Response headers</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA </code></pre></devsite-code> <aside class="tip"> Ordering is not important, the example is listed alphabetically. </aside> <p>When processing this on the server-side you should first check if the desired <code translate="no" dir="ltr">Sec-CH-UA</code> header has been sent and then fallback to the <code translate="no" dir="ltr">User-Agent</code> header parsing if it is not available.</p> <aside class="note"><b>Note: </b> Try the <a href="https://user-agent-client-hints.glitch.me/">User-Agent Client Hints HTTP header demo</a>. </aside> <h2 id="strategy_delegating_hints_to_cross-origin_requests" data-text="Strategy: Delegating hints to cross-origin requests" tabindex="-1">Strategy: Delegating hints to cross-origin requests</h2> <p>If you are requesting cross-origin or cross-site subresources that require User-Agent Client Hints to be sent on their requests then you will need to explicitly specify the desired hints using a Permissions Policy.</p> <aside class="note"><b>Note: </b> <a href="https://developer.chrome.com/docs/privacy-sandbox/permissions-policy">Permissions Policy</a> is the new form of Feature Policy </aside> <p>For example, let's say that <code translate="no" dir="ltr">https://blog.site</code> hosts resources on <code translate="no" dir="ltr">https://cdn.site</code> which can return resources optimized for a specific device. <code translate="no" dir="ltr">https://blog.site</code> can ask for the <code translate="no" dir="ltr">Sec-CH-UA-Model</code> hint, but needs to explicitly delegate it to <code translate="no" dir="ltr">https://cdn.site</code> using the <code translate="no" dir="ltr">Permissions-Policy</code> header. The list of policy-controlled hints is available in the <a href="https://wicg.github.io/client-hints-infrastructure/#policy-controlled-client-hints-features">Clients Hints Infrastructure draft</a></p> <p>⬇️ Response from <code translate="no" dir="ltr">blog.site</code> delegating the hint</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Model Permissions-Policy: ch-ua-model=(self "https://cdn.site") </code></pre></devsite-code> <p>⬆️ Request to subresources on <code translate="no" dir="ltr">cdn.site</code> include the delegated hint</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Sec-CH-UA-Model: "Pixel 5" </code></pre></devsite-code> <p>You can specify multiple hints for multiple origins, and not just from the <code translate="no" dir="ltr">ch-ua</code> range:</p> <p>⬇️ Response from <code translate="no" dir="ltr">blog.site</code> delegating multiple hints to multiple origins</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Model, DPR Permissions-Policy: ch-ua-model=(self "https://cdn.site"), ch-dpr=(self "https://cdn.site" "https://img.site") </code></pre></devsite-code> <aside class="tip"> You do <strong>not</strong> need to include each delegated hint in <code translate="no" dir="ltr">Accept-CH</code>, but you <strong>do</strong> need to include <code translate="no" dir="ltr">self</code> for each hint, even if you are not using it directly at the top-level. </aside> <h2 id="strategy_delegating_hints_to_iframes" data-text="Strategy: Delegating hints to iframes" tabindex="-1">Strategy: Delegating hints to iframes</h2> <p>Cross-origin iframes work in a similar way to cross-origin resources, but you specify the hints you would like to delegate in the <code translate="no" dir="ltr">allow</code> attribute.</p> <p>⬇️ Response from <code translate="no" dir="ltr">blog.site</code></p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Model </code></pre></devsite-code> <p>↪️ HTML for <code translate="no" dir="ltr">blog.site</code></p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="HTML"><code translate="no" dir="ltr"><iframe src="https://widget.site" allow="ch-ua-model"></iframe> </code></pre></devsite-code> <p>⬆️ Request to <code translate="no" dir="ltr">widget.site</code></p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Sec-CH-UA-Model: "Pixel 5" </code></pre></devsite-code> <p>The <code translate="no" dir="ltr">allow</code> attribute in the iframe will override any <code translate="no" dir="ltr">Accept-CH</code> header that <code translate="no" dir="ltr">widget.site</code> may send itself, so make sure you've specified everything the iframe'd site will need.</p> <h2 id="strategy_dynamic_server-side_hints" data-text="Strategy: Dynamic server-side hints" tabindex="-1">Strategy: Dynamic server-side hints</h2> <p>If you have specific parts of the user journey where you need a larger selection of hints than across the rest of the site, you may choose to request those hints on demand rather than statically across the entire site. This is more complex to manage, but if you already set different headers on a per route basis it may be feasible.</p> <p>The important thing to remember here is that each instance of the <code translate="no" dir="ltr">Accept-CH</code> header will effectively overwrite the existing set. So, if you are dynamically setting the header then each page must request the full set of hints required.</p> <p>For example, you may have one section on your site where you want to provide icons and controls that match the user's operating system. For this, you may want to additionally pull in <code translate="no" dir="ltr">Sec-CH-UA-Platform-Version</code> to serve appropriate subresources.</p> <p>⬇️ Response headers for <code translate="no" dir="ltr">/blog</code></p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA </code></pre></devsite-code> <p>⬇️ Response headers for <code translate="no" dir="ltr">/app</code></p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA </code></pre></devsite-code> <h2 id="strategy_server-side_hints_required_on_first_request" data-text="Strategy: Server-side hints required on first request" tabindex="-1">Strategy: Server-side hints required on first request</h2> <p>There may be cases where you require more than the default set of hints on the very first request, however this is likely to be rare so make sure you've reviewed the reasoning.</p> <p>The first request really means the very first top-level request for that origin sent in that browsing session. The default set of hints includes the browser name with major version, the platform, and the mobile indicator. So the question to ask here is, do you require extended data on the initial page load?</p> <aside class="note"><b>Note: </b> Also consider making use of the <a href="#strategy_on-demand_client-side_javascript_api">On-demand client-side JavaScript API strategy</a> to alter content within the page as opposed to server-side. </aside> <p>For additional hints on the first request there are two options. First, you can make use of the <code translate="no" dir="ltr">Critical-CH</code> header. This takes the same format as <code translate="no" dir="ltr">Accept-CH</code> but tells the browser that it should immediately retry the request if the first one was sent without the critical hint.</p> <p>⬆️ Initial request</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">[With default headers] </code></pre></devsite-code> <p>⬇️ Response headers</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Accept-CH: Sec-CH-UA-Model Critical-CH: Sec-CH-UA-Model </code></pre></devsite-code> <p>🔃 Browser retries initial request with the extra header</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">[With default headers + …] Sec-CH-UA-Model: Pixel 5 </code></pre></devsite-code> <p>This will incur the overhead of the retry on the very first request, but the implementation cost is relatively low. Send the extra header and the browser will do the rest.</p> <aside class="tip"> Any <code translate="no" dir="ltr">Critical-CH</code> values must be a subset of the values in <code translate="no" dir="ltr">Accept-CH</code>. <code translate="no" dir="ltr">Accept-CH</code> is all the values you would like for the page, <code translate="no" dir="ltr">Critical-CH</code> is the subset of those values you <strong>must</strong> have or you cannot load the page properly. </aside> <p>For situations where you require really do require additional hints on the very first page load, the <a href="https://github.com/WICG/client-hints-infrastructure/blob/main/reliability.md#connection-level-settings">Client Hints Reliability proposal</a> is laying out a route to specify hints in the connection-level settings. This makes use of the <a href="https://tools.ietf.org/html/draft-vvv-tls-alps">Application-Layer Protocol Settings(ALPS)</a> extension to TLS 1.3 to enable this early passing of hints on HTTP/2 and HTTP/3 connections. This is still at a very early stage, but if you actively manage your own TLS and connection settings then this is an ideal time to contribute.</p> <h2 id="strategy_legacy_support" data-text="Strategy: Legacy support" tabindex="-1">Strategy: Legacy support</h2> <p>You may have legacy or third-party code on your site that depends on <code translate="no" dir="ltr">navigator.userAgent</code>, including portions of the user-agent string that will be reduced. Long-term you should plan to move to the equivalent <code translate="no" dir="ltr">navigator.userAgentData</code> calls, but there is an interim solution.</p> <aside class="warning"><b>Warning: </b> This is not recommended and not supported in any way. This solution is included for completeness but if you spend any time attempting to fix bugs in it, that time would be better spent doing the actual migration. </aside> <p><a href="https://github.com/GoogleChromeLabs/uach-retrofill">UA-CH retrofill</a> is a small library that allows you to overwrite <code translate="no" dir="ltr">navigator.userAgent</code> with a new string built from the requested <code translate="no" dir="ltr">navigator.userAgentData</code> values.</p> <p>For example, this code will generate a user-agent string that additionally includes the "model" hint:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="JavaScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">import</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">overrideUserAgentUsingClientHints</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-kr">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'./uach-retrofill.js'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-nx">overrideUserAgentUsingClientHints</span><span class="devsite-syntax-p">([</span><span class="devsite-syntax-s1">'model'</span><span class="devsite-syntax-p">])</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">then</span><span class="devsite-syntax-p">(()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">console</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">log</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">navigator</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">userAgent</span><span class="devsite-syntax-p">);</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> </code></pre></devsite-code> <p>The resulting string would show the <code translate="no" dir="ltr">Pixel 5</code> model, but still shows the reduced <code translate="no" dir="ltr">92.0.0.0</code> as the <code translate="no" dir="ltr">uaFullVersion</code> hint was not requested:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Text only"><code translate="no" dir="ltr">Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36 </code></pre></devsite-code> <h2 id="further_support" data-text="Further support" tabindex="-1">Further support</h2> <p>If these strategies do not cover your use case, please start a <a href="https://github.com/GoogleChromeLabs/privacy-sandbox-dev-support/discussions">Discussion in privacy-sandbox-dev-support repo</a> and we can explore your issue together.</p> <p><em>Photo by <a href="https://unsplash.com/@rcrazy?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Ricardo Rocha</a> on <a href="https://unsplash.com/photos/nj1bqRzClq8">Unsplash</a></em></p> </div> <devsite-thumb-rating position="footer"> </devsite-thumb-rating> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> <p>Last updated 2021-05-19 UTC.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2021-05-19 UTC."],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox wd-footer-promo"> <h3 class="devsite-footer-linkbox-heading no-link">web.dev</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <h3 class="devsite-footer-linkbox-heading no-link"> web.dev </h3> <div class="devsite-footer-linkbox-description">We want to help you build beautiful, accessible, fast, and secure websites that work cross-browser, and for all of your users. This site is our home for content to help you on that journey, written by members of the Chrome team, and external experts.</div> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Contribute</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="https://issuetracker.google.com/issues/new?component=1400680&template=1857359" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > File a bug </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://issuetracker.google.com/issues?q=status:open%20componentid:1400680&s=created_time:desc" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > See open issues </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Related Content</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="https://developer.chrome.com/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Chrome for Developers </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://blog.chromium.org/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Chromium updates </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/case-studies" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Case studies </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/shows" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Podcasts & shows </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Follow</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="https://twitter.com/ChromiumDev" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > @ChromiumDev on X </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://www.youtube.com/user/ChromeDevelopers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > YouTube </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://www.linkedin.com/showcase/chrome-for-developers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Chrome for Developers on LinkedIn </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/static/blog/feed.xml" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > RSS </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/terms" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[]</script> <script type="application/json" tag-management>{"at": "True", "ga4": [], "ga4p": [], "gtm": [{"id": "GTM-MZWCJPP", "purpose": 0}], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "article", "projectName": "Articles", "signedIn": "False", "tenant": "web", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="vADaiF6f/mvT8fA9DIUtp8MT7kXszq"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/js/app_loader.js', '[27,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web","https://web-dot-devsite-v2-prod-3p.appspot.com",null,null,["/_pwa/web/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/favicon.png","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/web/images/lockup.svg","https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,116,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyCNm9YxQumEXwGJgTDjxoxXK6m1F-9720Q","AIzaSyCc76DZePGtoyUjqKrLdsMGk_ry7sljLbY","web.dev","AIzaSyB9bqgQ2t11WJsOX8qNsCQ6U-w91mmqF-I","AIzaSyAdYnStPdzjcJJtQ0mvIaeaMKj7_t6J_Fg",null,null,null,["Cloud__enable_cloudx_ping","Profiles__require_profile_eligibility_for_signin","MiscFeatureFlags__enable_project_variables","DevPro__enable_developer_subscriptions","Search__enable_suggestions_from_borg","Cloud__enable_cloud_facet_chat","EngEduTelemetry__enable_engedu_telemetry","CloudShell__cloud_shell_button","Cloud__enable_cloud_shell","Profiles__enable_complete_playlist_endpoint","Profiles__enable_developer_profiles_callout","Profiles__enable_dashboard_curated_recommendations","MiscFeatureFlags__emergency_css","Cloud__enable_legacy_calculator_redirect","Profiles__enable_release_notes_notifications","Search__enable_ai_eligibility_checks","Analytics__enable_clearcut_logging","Profiles__enable_awarding_url","DevPro__enable_cloud_innovators_plus","CloudShell__cloud_code_overflow_menu","MiscFeatureFlags__enable_view_transitions","MiscFeatureFlags__enable_firebase_utm","Cloud__enable_cloud_dlp_service","BookNav__enable_tenant_cache_key","Cloud__enable_cloud_shell_fte_user_flow","Profiles__enable_profile_collections","Search__enable_dynamic_content_confidential_banner","Cloud__enable_cloudx_experiment_ids","Cloud__enable_llm_concierge_chat","Cloud__enable_free_trial_server_call","MiscFeatureFlags__enable_explain_this_code","Profiles__enable_page_saving","Profiles__enable_completecodelab_endpoint","Profiles__enable_recognition_badges","TpcFeatures__enable_required_headers","MiscFeatureFlags__enable_variable_operator","Profiles__enable_public_developer_profiles","Search__enable_page_map","Concierge__enable_pushui","OnSwitch__enable","MiscFeatureFlags__developers_footer_dark_image","MiscFeatureFlags__developers_footer_image","TpcFeatures__enable_mirror_tenant_redirects","Experiments__reqs_query_experiments"],null,null,"AIzaSyA58TaKli1DculwmAmbpzLVGuWc8eCQgQc","https://developerscontentserving-pa.googleapis.com","AIzaSyDWBU60w0P9hEkr29kkksYs8Z7gvZ8u_wc","https://developerscontentsearch-pa.googleapis.com",2,4,null,"https://developerprofiles-pa.googleapis.com",[27,"web","web.dev","web.dev",null,"web-dot-devsite-v2-prod-3p.appspot.com",null,null,[null,null,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],null,null,null,null,[1,null,1],[1,1,null,1,1]],null,[38,null,null,null,null,null,"/images/lockup.svg","/images/touchicon-180.png",null,null,null,1,1,null,null,null,null,null,null,null,null,2,null,null,null,"/images/lockup-dark-theme.svg",[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[],[1,1]],[[null,null,null,null,null,["GTM-MZWCJPP"],null,null,null,null,null,[["GTM-MZWCJPP",1]],1]],null,4]]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>