# WebOTP API

> How WebOTP reads a domain-bound SMS code with user consent, including message format, feature detection, cancellation, and manual-entry fallback.

The WebOTP API extends Credential Management so a site can request an SMS one-time code that is bound to its domain. After the user consents, `navigator.credentials.get()` returns an `OTPCredential` whose `code` can fill a verification form ([WebOTP API](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API), MDN).

## Support

MDN marks WebOTP as limited availability and restricted to secure contexts. Its compatibility data records `OTPCredential` from Chrome 93 on desktop and Chrome 84 on Android, with support mirrored to Edge, Opera, Samsung Internet, and Meta Quest Browser; it records no support in Firefox, Safari, or Android WebView ([WebOTP API](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API), MDN). A field with `autocomplete="one-time-code"` preserves manual entry and lets Safari offer its separate SMS-code autofill ([Verify phone numbers on the web with the WebOTP API](https://developer.chrome.com/docs/identity/web-apis/web-otp), Chrome for Developers).

## Syntax

```js
const credential = await navigator.credentials.get({
  otp: { transport: ['sms'] },
  signal,
});
```

The SMS must end with the calling domain and code. The domain has no scheme or port, and the domain-bound line is the last line ([WebOTP API](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API#sms_message_format), MDN).

## Parameters

Pass an `otp` option whose `transport` contains `"sms"`. An optional `AbortSignal` cancels a pending request. When the request succeeds, the returned `OTPCredential` exposes the received value through `code` ([WebOTP API](https://wicg.github.io/web-otp/), WICG).

## Exceptions

A policy can disable the API with the `otp-credentials` Permissions Policy directive. Its default allowlist is `self`; a request blocked by policy rejects with `SecurityError` ([WebOTP API](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API#controlling_access_to_the_api), MDN). The request can also reject when its abort signal is triggered, so keep the input and submit button usable.

:::caution
Chrome's Android instructions for Chrome 84 or later show a bottom sheet with a **Verify** button after a matching SMS arrives. The same instructions use `@chrome.dev #123456` as the final SMS line ([Verify phone numbers on the web with the WebOTP API](https://developer.chrome.com/docs/identity/web-apis/web-otp), Chrome for Developers).
:::

## Examples

The first example shows the server-produced SMS shape; the second keeps a manual verification path while requesting the code.

### Format a domain-bound SMS

For `https://www.example.com`, MDN gives this message shape:

```text
Your verification code is 123456.

@www.example.com #123456
```

The blank line separates the explanatory text from the final domain-bound line.

### Fill the code while retaining manual entry

This form keeps the standard input available whether or not WebOTP exists. Submitting manually aborts the pending credential request.

```html
<form id="otp-form" action="/verify" method="post">
  <label>Verification code <input name="code" autocomplete="one-time-code" inputmode="numeric" required></label>
  <button>Verify</button>
</form>
<script>
  const form = document.querySelector('#otp-form');
  const input = form.elements.code;

  if ('OTPCredential' in window) {
    const controller = new AbortController();
    form.addEventListener('submit', () => controller.abort(), { once: true });

    navigator.credentials.get({
      otp: { transport: ['sms'] },
      signal: controller.signal,
    }).then((otp) => {
      input.value = otp.code;
      form.requestSubmit();
    }).catch(() => {
      input.focus();
    });
  } else {
    input.focus();
  }
</script>
```

The fallback focuses the same field, so unsupported browsers retain the manual verification path.

## See also

- [Credential Management API](/reference/capabilities/credential-management/)
- [WebAuthn and passkeys](/reference/capabilities/webauthn-passkeys/)
- [WebOTP API](https://wicg.github.io/web-otp/) (wicg.github.io)
- [WebOTP API](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API) (MDN)