CINXE.COM

SMS OTP form best practices  |  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/sms-otp-form"><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/sms-otp-form" /><link rel="alternate" hreflang="x-default" href="https://web.dev/articles/sms-otp-form" /><link rel="alternate" hreflang="ar" href="https://web.dev/articles/sms-otp-form?hl=ar" /><link rel="alternate" hreflang="bn" href="https://web.dev/articles/sms-otp-form?hl=bn" /><link rel="alternate" hreflang="zh-Hans" href="https://web.dev/articles/sms-otp-form?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://web.dev/articles/sms-otp-form?hl=zh-tw" /><link rel="alternate" hreflang="fa" href="https://web.dev/articles/sms-otp-form?hl=fa" /><link rel="alternate" hreflang="fr" href="https://web.dev/articles/sms-otp-form?hl=fr" /><link rel="alternate" hreflang="de" href="https://web.dev/articles/sms-otp-form?hl=de" /><link rel="alternate" hreflang="he" href="https://web.dev/articles/sms-otp-form?hl=he" /><link rel="alternate" hreflang="hi" href="https://web.dev/articles/sms-otp-form?hl=hi" /><link rel="alternate" hreflang="id" href="https://web.dev/articles/sms-otp-form?hl=id" /><link rel="alternate" hreflang="it" href="https://web.dev/articles/sms-otp-form?hl=it" /><link rel="alternate" hreflang="ja" href="https://web.dev/articles/sms-otp-form?hl=ja" /><link rel="alternate" hreflang="ko" href="https://web.dev/articles/sms-otp-form?hl=ko" /><link rel="alternate" hreflang="pl" href="https://web.dev/articles/sms-otp-form?hl=pl" /><link rel="alternate" hreflang="pt-BR" href="https://web.dev/articles/sms-otp-form?hl=pt-br" /><link rel="alternate" hreflang="ru" href="https://web.dev/articles/sms-otp-form?hl=ru" /><link rel="alternate" hreflang="es" href="https://web.dev/articles/sms-otp-form?hl=es" /><link rel="alternate" hreflang="es-419" href="https://web.dev/articles/sms-otp-form?hl=es-419" /><link rel="alternate" hreflang="th" href="https://web.dev/articles/sms-otp-form?hl=th" /><link rel="alternate" hreflang="tr" href="https://web.dev/articles/sms-otp-form?hl=tr" /><link rel="alternate" hreflang="vi" href="https://web.dev/articles/sms-otp-form?hl=vi" /><link rel="alternate" hreflang="en-cn" href="https://web.developers.google.cn/articles/sms-otp-form" /><link rel="alternate" hreflang="x-default" href="https://web.developers.google.cn/articles/sms-otp-form" /><link rel="alternate" hreflang="ar-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=ar" /><link rel="alternate" hreflang="bn-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=bn" /><link rel="alternate" hreflang="zh-Hans-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=zh-tw" /><link rel="alternate" hreflang="fa-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=fa" /><link rel="alternate" hreflang="fr-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=fr" /><link rel="alternate" hreflang="de-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=de" /><link rel="alternate" hreflang="he-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=he" /><link rel="alternate" hreflang="hi-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=hi" /><link rel="alternate" hreflang="id-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=id" /><link rel="alternate" hreflang="it-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=it" /><link rel="alternate" hreflang="ja-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=ja" /><link rel="alternate" hreflang="ko-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=ko" /><link rel="alternate" hreflang="pl-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=pl" /><link rel="alternate" hreflang="pt-BR-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=pt-br" /><link rel="alternate" hreflang="ru-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=ru" /><link rel="alternate" hreflang="es-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=es" /><link rel="alternate" hreflang="es-419-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=es-419" /><link rel="alternate" hreflang="th-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=th" /><link rel="alternate" hreflang="tr-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=tr" /><link rel="alternate" hreflang="vi-cn" href="https://web.developers.google.cn/articles/sms-otp-form?hl=vi" /><title>SMS OTP form best practices &nbsp;|&nbsp; Articles &nbsp;|&nbsp; web.dev</title> <meta property="og:title" content="SMS OTP form best practices &nbsp;|&nbsp; Articles &nbsp;|&nbsp; web.dev"><meta name="description" content="Asking a user to provide an OTP (one-time password) delivered via SMS is a common way to confirm a user&amp;#39;s phone number. This post provides you with the best practices to build an SMS OTP form with great user experience."> <meta property="og:description" content="Asking a user to provide an OTP (one-time password) delivered via SMS is a common way to confirm a user&amp;#39;s phone number. This post provides you with the best practices to build an SMS OTP form with great user experience."><meta property="og:url" content="https://web.dev/articles/sms-otp-form"><meta property="og:locale" content="en"><script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "dateModified": "2020-12-09", "headline": "SMS OTP form best practices" } </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": "SMS OTP form best practices", "item": "https://web.dev/articles/sms-otp-form" }] } </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"> SMS OTP form best practices </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>Learn how to optimize your SMS OTP form and improve user experience.</p> <p> <div class="wd-authors" translate="no"> <div class="wd-author"> <img class="devsite-landing-row-item-icon" alt="Eiji Kitamura" src="https://web.dev/images/authors/agektmr.jpg" decoding="async" height="64" loading="lazy" width="64"> <div> <span> Eiji Kitamura </span> <div class="wd-author__links"> <a href="https://twitter.com/agektmr" aria-label="Eiji Kitamura 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/agektmr" aria-label="Eiji Kitamura 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/@agektmr" aria-label="Eiji Kitamura 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://infosec.exchange/@agektmr" aria-label="Eiji Kitamura 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><devsite-video video-id="sU4MpWYrGSI"></devsite-video></p> <p>Asking a user to provide the OTP (one time password) delivered via SMS is a common way to confirm a user&#39;s phone number. There are a few use cases for SMS OTP:</p> <ul> <li><strong>Two-factor authentication.</strong> In addition to username and password, SMS OTP can be used as a strong signal that the account is owned by the person who received the SMS OTP.</li> <li><strong>Phone number verification.</strong> Some services use a phone number as the user&#39;s primary identifier. In such services, users can enter their phone number and the OTP received via SMS to prove their identity. Sometimes it&#39;s combined with a PIN to constitute a two-factor authentication.</li> <li><strong>Account recovery.</strong> When a user loses access to their account, there needs to be a way to recover it. Sending an email to their registered email address or an SMS OTP to their phone number are common account recovery methods.</li> <li><strong>Payment confirmation</strong> In payment systems, some banks or credit card issuers request additional authentication from the payer for security reasons. SMS OTP is commonly used for that purpose.</li> </ul> <p>This post explains best practices to build an SMS OTP form for the above use cases.</p> <aside class="caution"><b>Caution: </b> While this post discusses SMS OTP form best practices, be aware that SMS OTP is not the most secure method of authentication by itself because phone numbers can be recycled and sometimes hijacked. And <a href="https://youtu.be/kGGMgEfSzMw?t=1133">the concept of OTP itself is not phishing resistant</a>. If you are looking for better security, consider using <a href="https://www.w3.org/TR/webauthn-2/">WebAuthn</a>. Learn more about it from the talk &quot;<a href="https://goo.gle/webauthn-video">What's new in sign-up &amp; sign-in</a>&quot; at the Chrome Dev Summit 2019 and build a reauthentication experience using a biometric sensor with &quot;<a href="https://goo.gle/WebAuthnReauthCodelab">Build your first WebAuthn app</a>&quot; codelab. </aside> <h2 id="checklist" data-text="Checklist" tabindex="-1">Checklist</h2> <p>To provide the best user experience with the SMS OTP, follow these steps:</p> <ul> <li>Use the <code translate="no" dir="ltr">&lt;input&gt;</code> element with: <ul> <li><code translate="no" dir="ltr">type=&quot;text&quot;</code></li> <li><code translate="no" dir="ltr">inputmode=&quot;numeric&quot;</code></li> <li><code translate="no" dir="ltr">autocomplete=&quot;one-time-code&quot;</code></li> </ul></li> <li>Use <code translate="no" dir="ltr">@BOUND_DOMAIN #OTP_CODE</code> as the last line of the OTP SMS message.</li> <li>Use the <a href="/web-otp">WebOTP API</a>.</li> </ul> <h2 id="use_the_input_element" data-text="Use the &lt;input&gt; element" tabindex="-1">Use the <code translate="no" dir="ltr">&lt;input&gt;</code> element</h2> <p>Using a form with an <code translate="no" dir="ltr">&lt;input&gt;</code> element is the most important best practice you can follow because it works in all browsers. Even if other suggestions from this post don&#39;t work in some browser, the user will still be able to enter and submit the OTP manually.</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="HTML"><code translate="no" dir="ltr">&lt;form action="/verify-otp" method="POST"&gt; &lt;input type="text" inputmode="numeric" autocomplete="one-time-code" pattern="\d{6}" required&gt; &lt;/form&gt; </code></pre></devsite-code> <p>The following are a few ideas to ensure an input field gets the best out of browser functionality.</p> <h3 id="typetext" data-text='type="text"' tabindex="-1"><code translate="no" dir="ltr">type="text"</code></h3> <p>Since OTPs are usually five or six digit numbers, using <code translate="no" dir="ltr">type=&quot;number&quot;</code> for an input field might seem intuitive because it changes the mobile keyboard to numbers only. This is not recommended because the browser expects an input field to be a countable number rather than a sequence of multiple numbers, which can cause unexpected behavior. Using <code translate="no" dir="ltr">type=&quot;number&quot;</code> causes up and down buttons to be displayed beside the input field; pressing these buttons increments or decrements the number and may remove preceding zeros.</p> <p>Use <code translate="no" dir="ltr">type=&quot;text&quot;</code> instead. This won&#39;t turn the mobile keyboard into numbers only, but that is fine because the next tip for using <code translate="no" dir="ltr">inputmode=&quot;numeric&quot;</code> does that job.</p> <h3 id="inputmodenumeric" data-text='inputmode="numeric"' tabindex="-1"><code translate="no" dir="ltr">inputmode="numeric"</code></h3> <p>Use <a href="https://developer.mozilla.org/docs/Web/HTML/Global_attributes/inputmode"><code translate="no" dir="ltr">inputmode=&quot;numeric&quot;</code></a> to change the mobile keyboard to numbers only.</p> <p>Some websites use <code translate="no" dir="ltr">type=&quot;tel&quot;</code> for OTP input fields since it also turns the mobile keyboard to numbers only (including <code translate="no" dir="ltr">*</code> and <code translate="no" dir="ltr">#</code>) when focused. This hack was used in the past when <code translate="no" dir="ltr">inputmode=&quot;numeric&quot;</code> wasn&#39;t widely supported. Since <a href="https://github.com/mdn/browser-compat-data/pull/6782">Firefox started supporting <code translate="no" dir="ltr">inputmode=&quot;numeric&quot;</code></a>, there&#39;s no need to use the semantically incorrect <code translate="no" dir="ltr">type=&quot;tel&quot;</code> hack.</p> <h3 id="autocompleteone-time-code" data-text='autocomplete="one-time-code"' tabindex="-1"><code translate="no" dir="ltr">autocomplete="one-time-code"</code></h3> <p><a href="https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete"><code translate="no" dir="ltr">autocomplete</code></a> attribute lets developers specify what permission the browser has to provide autocomplete assistance and informs the browser about the type of information expected in the field.</p> <p>With <code translate="no" dir="ltr">autocomplete=&quot;one-time-code&quot;</code> whenever a user receives an SMS message while a form is open, the operating system will parse the OTP in the SMS heuristically and the keyboard will suggest the OTP for the user to enter. It works only on Safari 12 and later on iOS, iPadOS, and macOS, but we strongly recommend using it, because it is an easy way to improve the SMS OTP experience on those platforms.</p> <figure style="width:300px; margin:auto;"> <video controls playsinline autoplay loop muted> <source src="/static/articles/sms-otp-form/video/web-dev-assets/sms-otp-form/ios-safari.webm" type="video/webm"> <source src="/static/articles/sms-otp-form/video/web-dev-assets/sms-otp-form/ios-safari.mp4" type="video/mp4"> </video> <figcaption class="wd-caption"> `autocomplete="one-time-code"` in action. </figcaption> </figure> <p><code translate="no" dir="ltr">autocomplete=&quot;one-time-code&quot;</code> improves the user experience, but there&#39;s more you can do by <a href="#format">ensuring that the SMS message complies with the origin-bound message format</a>.</p> <aside class="note"><b>Note: </b> Optional attributes: <ul><li> <a href="https://developer.mozilla.org/docs/Web/HTML/Attributes/pattern"><code translate="no" dir="ltr">pattern</code></a> specifies the format that the entered OTP must match. Use regular expressions to specify the matching pattern, for example, <code translate="no" dir="ltr">\d{6}</code> constrains the OTP to a six digit string. Learn more about the <code translate="no" dir="ltr">pattern</code> attribute in <a href="/learn/forms/javascript#ensure_users_are_notified_about_errors_in_real_time">Use JavaScript for more complex real-time validation</a> <li><a href="https://developer.mozilla.org/docs/Web/HTML/Attributes/required"><code translate="no" dir="ltr">required</code></a> indicates that a field is required.</ul> For more general form best practices, <a href="/authors/samdutton">Sam Dutton</a>'s <a href="/articles/sign-in-form-best-practices">Sign-in form best practices</a> is a great starting point. </aside> <h2 id="format" data-text="Format the SMS text" tabindex="-1">Format the SMS text</h2> <p>Enhance the user experience of entering an OTP by aligning with <a href="https://wicg.github.io/sms-one-time-codes/">the origin-bound one-time codes delivered via SMS</a> specification.</p> <p>The format rule is simple: Finish the SMS message with the receiver domain preceded with <code translate="no" dir="ltr">@</code> and the OTP preceded with <code translate="no" dir="ltr">#</code>.</p> <p>For example:</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">Your OTP is 123456 @web-otp.glitch.me #123456 </code></pre></devsite-code> <p>Using a standard format for OTP messages makes extraction of codes from them easier and more reliable. Associating OTP codes with websites makes it harder to trick users into providing a code to malicious sites.</p> <aside class="note"><b>Note: </b> The precise rules are: * The message begins with (optional) human-readable text that contains a four to ten character alphanumeric string with at least one number, leaving the last line for the URL and the OTP. * The domain part of the URL of the website that invoked the API must be preceded by <code translate="no" dir="ltr">@</code>. * The URL must contain a pound sign (&quot;<code translate="no" dir="ltr">#</code>&quot;) followed by the OTP. Make sure the number of characters doesn't exceed 140 in total. To learn more about Chrome specific rules, read <a href="https://developer.chrome.com/articles/web-otp">Format the SMS message section of WebOTP API post</a>. </aside> <p>Using this format provides a couple of benefits:</p> <ul> <li>The OTP will be bound to the domain. If the user is on domains other than the one specified in the SMS message, the OTP suggestion won&#39;t appear. This also mitigates the risk of phishing attacks and potential account hijacks.</li> <li>Browser will now be able to reliably extract the OTP without depending on mysterious and flaky heuristics.</li> </ul> <p>When a website uses <code translate="no" dir="ltr">autocomplete=&quot;one-time-code&quot;</code>, Safari with iOS 14 or later will suggest the OTP following the above rules.</p> <aside class="note"><b>Note: </b> If the user is on a desktop with macOS Big Sur with the same iCloud account set up as on iOS, the OTP received on the iOS device will be available on the desktop Safari as well. To learn more about other benefits and nuances of the availability on Apple platforms, read <a href="https://developer.apple.com/news/?id=z0i801mg">Enhance SMS-delivered code security with domain-bound codes</a>. </aside> <p>This SMS message format also benefits browsers other than Safari. Chrome, Opera, and Vivaldi on Android also support the origin-bound one-time codes rule with the WebOTP API, though not through <code translate="no" dir="ltr">autocomplete=&quot;one-time-code&quot;</code>.</p> <h2 id="use_the_webotp_api" data-text="Use the WebOTP API" tabindex="-1">Use the WebOTP API</h2> <p><a href="https://wicg.github.io/web-otp/">The WebOTP API</a> provides access to the OTP received in an SMS message. By calling <a href="https://developer.mozilla.org/docs/Web/API/CredentialsContainer/get"><code translate="no" dir="ltr">navigator.credentials.get()</code></a> with <code translate="no" dir="ltr">otp</code> type (<code translate="no" dir="ltr">OTPCredential</code>) where <code translate="no" dir="ltr">transport</code> includes <code translate="no" dir="ltr">sms</code>, the website will wait for an SMS that complies with the origin-bound one-time codes to be delivered and granted access by the user. Once the OTP is passed to JavaScript, the website can use it in a form or POST it directly to the server.</p> <aside class="caution"><b>Caution: </b> The WebOTP API requires a secure origin (HTTPS). </aside> <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">credentials</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">get</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">otp</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-nx">transport</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s1">'sms'</span><span class="devsite-syntax-p">]}</span> <span class="devsite-syntax-p">})</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">otp</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">input</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">value</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">otp</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">code</span><span class="devsite-syntax-p">);</span> </code></pre></devsite-code> <figure style="width:300px; margin:auto;"> <video controls playsinline autoplay loop muted> <source src="/static/articles/sms-otp-form/video/web-dev-assets/sms-otp-form/android-chrome.webm" type="video/webm"> <source src="/static/articles/sms-otp-form/video/web-dev-assets/sms-otp-form/android-chrome.mp4" type="video/mp4"> </video> <figcaption class="wd-caption"> WebOTP API in action. </figcaption> </figure> <p>Learn how to use the WebOTP API in detail in <a href="/web-otp">Verify phone numbers on the web with the WebOTP API</a> or copy and paste the following snippet. (Make sure the <code translate="no" dir="ltr">&lt;form&gt;</code> element has an <code translate="no" dir="ltr">action</code> and <code translate="no" dir="ltr">method</code> attribute properly set.)</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-c1">// Feature detection</span> <span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'OTPCredential'</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">window</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-nb">window</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">addEventListener</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'DOMContentLoaded'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">e</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</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">input</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">document</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">querySelector</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'input[autocomplete="one-time-code"]'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-o">!</span><span class="devsite-syntax-nx">input</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Cancel the WebOTP API if the form is submitted manually.</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">ac</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">new</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">AbortController</span><span class="devsite-syntax-p">();</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">form</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">input</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">closest</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'form'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </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">form</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-nx">form</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">addEventListener</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'submit'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">e</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Cancel the WebOTP API.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">ac</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">abort</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-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Invoke the WebOTP API</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">credentials</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">get</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">otp</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">transport</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s1">'sms'</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-nx">signal</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">ac</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">signal</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">otp</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">input</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">value</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">otp</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">code</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// Automatically submit the form when an OTP is obtained.</span> <span class="devsite-syntax-w"> </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">form</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nx">form</span><span class="devsite-syntax-p">.</span><span class="devsite-syntax-nx">submit</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}).</span><span class="devsite-syntax-k">catch</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nx">err</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>&gt;<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">err</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-p">});</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>Photo by <a href="https://unsplash.com/photos/mZNRsYE9Qi4">Jason Leung</a> on <a href="https://unsplash.com">Unsplash</a>.</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 2020-12-09 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 2020-12-09 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&amp;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&amp;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 &amp; 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>{&#34;at&#34;: &#34;True&#34;, &#34;ga4&#34;: [], &#34;ga4p&#34;: [], &#34;gtm&#34;: [{&#34;id&#34;: &#34;GTM-MZWCJPP&#34;, &#34;purpose&#34;: 0}], &#34;parameters&#34;: {&#34;internalUser&#34;: &#34;False&#34;, &#34;language&#34;: {&#34;machineTranslated&#34;: &#34;False&#34;, &#34;requested&#34;: &#34;en&#34;, &#34;served&#34;: &#34;en&#34;}, &#34;pageType&#34;: &#34;article&#34;, &#34;projectName&#34;: &#34;Articles&#34;, &#34;signedIn&#34;: &#34;False&#34;, &#34;tenant&#34;: &#34;web&#34;, &#34;recommendations&#34;: {&#34;sourcePage&#34;: &#34;&#34;, &#34;sourceType&#34;: 0, &#34;sourceRank&#34;: 0, &#34;sourceIdenticalDescriptions&#34;: 0, &#34;sourceTitleWords&#34;: 0, &#34;sourceDescriptionWords&#34;: 0, &#34;experiment&#34;: &#34;&#34;}, &#34;experiment&#34;: {&#34;ids&#34;: &#34;&#34;}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="/ORryt2jy6uqM2ZGiThw3VZ2mOGxvq"> (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",1,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,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_llm_concierge_chat","Search__enable_page_map","BookNav__enable_tenant_cache_key","TpcFeatures__enable_required_headers","DevPro__enable_cloud_innovators_plus","MiscFeatureFlags__enable_firebase_utm","DevPro__enable_developer_subscriptions","Profiles__enable_profile_collections","Cloud__enable_cloud_shell_fte_user_flow","MiscFeatureFlags__enable_explain_this_code","Search__enable_dynamic_content_confidential_banner","Profiles__enable_release_notes_notifications","CloudShell__cloud_shell_button","MiscFeatureFlags__enable_view_transitions","Search__enable_suggestions_from_borg","Experiments__reqs_query_experiments","TpcFeatures__enable_mirror_tenant_redirects","Cloud__enable_legacy_calculator_redirect","MiscFeatureFlags__enable_variable_operator","Profiles__enable_public_developer_profiles","MiscFeatureFlags__developers_footer_dark_image","Cloud__enable_cloudx_ping","Profiles__require_profile_eligibility_for_signin","EngEduTelemetry__enable_engedu_telemetry","Cloud__enable_cloud_shell","Cloud__enable_cloud_facet_chat","Profiles__enable_page_saving","Cloud__enable_free_trial_server_call","Profiles__enable_completecodelab_endpoint","Concierge__enable_pushui","Cloud__enable_cloudx_experiment_ids","Profiles__enable_recognition_badges","OnSwitch__enable","Profiles__enable_complete_playlist_endpoint","Analytics__enable_clearcut_logging","CloudShell__cloud_code_overflow_menu","Cloud__enable_cloud_dlp_service","MiscFeatureFlags__enable_project_variables","Profiles__enable_dashboard_curated_recommendations","Profiles__enable_awarding_url","MiscFeatureFlags__emergency_css","MiscFeatureFlags__developers_footer_image","Profiles__enable_developer_profiles_callout","Search__enable_ai_eligibility_checks"],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>

Pages: 1 2 3 4 5 6 7 8 9 10