Best Practices for OTP Input Forms in HTML

July 30, 2025
Written by
Alvin Lee
Contributor
Opinions expressed by Twilio contributors are their own
Reviewed by

Illustration on best practices for OTP input forms in HTML with a red background and arrow graphic.

 

One-time passwords (OTPs) are a standard way to confirm a user’s contact information and to allow secure login, either with or without a password. An OTP can be sent via multiple pathways including SMS and email.

A good OTP experience streamlines the user's experience of logging into your app, lowering the barrier to entry while providing contact information verification. We’ll show you best practices for OTP on the web. It’s not complicated, but there are a few key details that you need to be aware of.

OTP workflows and use cases

The basic flow for OTP verification looks like this:

  1. The user enters their phone number or email and submits the form to the app.
  2. The app generates a token (for example: 123456) and sends the token to the user’s phone number or email.
  3. The user enters the token into the OTP verification form.
  4. The app verifies the token.

This simple workflow has become nearly ubiquitous. The use cases for OTP verification include:

  1. Contact information verification: Whether it is with email, SMS, voice, or WhatsApp, OTP can be used to authenticate the user’s identity via their contact information.
  2. Two-factor authentication: OTP can also be used as a second authentication factor in combination with another—such as username and password—proving that the person logging in is the person who owns the account.
  3. Account recovery: OTP verification is a common method to provide users a way to restore access in case of lost passwords or other account recovery situations.

OTP has several advantages over other authentication methods. For example:

  • OTP verification is passwordless and does not require the user to remember yet another password.
  • OTP verification does not require a separate app, reducing friction.
  • When implemented well, OTP verification has a streamlined UX, as the OTP token will be auto-filled and submitted for the user. They do not need to exit the current app.

However, even with these advantages, keep in mind that no mechanism is perfectly secure. The security of OTP verification depends on the security of the underlying phone number or email account. Additionally, phishing and recycled phone numbers can present issues.

Let’s look at how we can streamline the process and secure it.

Best practices for OTP verification on web

To streamline and secure the OTP verification process, follow these best practices:

  1. Use an <input> HTML element with appropriate attributes.
  2. Send the user a domain-bound OTP.
  3. Use the WebOTP API to fill the input.

Use an <input> HTML element with recommended attributes

To begin, make sure the input for your OTP token is an <input> element. This ensures accessibility and compatibility with all browsers, that it works even without JavaScript, and that it allows the user to manually enter the code if necessary.

Add the following attributes to the <input> element, for additional ease of use and security:

  • type="text" — Ensures that the input field allows the token to be input properly. Using type="number" causes increment/decrement buttons to appear in the input. Additionally, the input must allow for preceding zeroes.
  • inputmode="numeric" — Enables the use of the numbers-only keyboard on mobile devices.
  • autocomplete="one-time-code" — Allows mobile browsers to provide auto-complete assistance, further streamlining the OTP verification process.
  • pattern="\d{6}" — Enables regular-expression validation of the input (for example: requires 6 digits).
  • required — Makes the field required for submission.

A single input field allows for easy copy and paste and also enables autofill. It is possible to achieve this with multiple input fields, but the implementation is more complex.

Here’s an example of what a single input OTP verification form could look like:

<form action="/verify-otp-token" method="POST">
  <input type="text"
         inputmode="numeric"
         autocomplete="one-time-code"
         pattern="\d{6}"
         required>
</form>

Now that we have our input set up, we need to look at the OTP message itself.

Send the user a domain-bound OTP

To protect against phishing with SMS OTP, use a domain-bound OTP. By providing the OTP in a specific format along with the domain, we tell mobile systems to only autofill that OTP to our authorized domain. This prevents the OTP from being entered on a fake domain, as autofill will no longer happen on unauthorized domains.

Here is an example of the proper format for a domain-bound OTP:

text

123456 is your Example code.

@example.com #123456

You can set up domain-bound OTPs via Twilio Verify through the use of a custom template. See this resource for more information.

When used in combination with an appropriately configured <input> element, this approach allows for OTP autofill on Safari in iOS. To support other browsers and platforms, use the WebOTP API.

Use the WebOTP API

The WebOTP API provides access to the OTP received through a JavaScript call. By calling navigator.credentials.get and providing the sms transport, the OTP token can be accessed and then provided to the form. See this example for a simple JavaScript implementation.

Using the WebOTP API enables autofill of the OTP token for the user and automatic form submission, streamlining the experience and reducing friction for the user.

For more information, check out the WebOTP API documentation.

Testing and tips

With your input field and SMS configured, it's time to test your OTP verification setup.

If you're looking to test a prebuilt setup, Twilio Verify has a quick deploy template which can be used to test OTP verification. Alternatively, if you are testing your own setup, here are a few things to keep in mind.

Troubleshooting domain-bound OTP

If you’re having trouble with getting your domain-bound message recognized, keep in mind that the format is quite strict. The last line must begin with @, followed by the domain, a single space, #, and then the OTP — nothing more, nothing less. See these formatting examples for detailed guidance.

Testing and rate limiting

Keep in mind when testing that you are receiving real SMS and will be subject to the protective rate limits of the Verify API. Twilio Verify provides workarounds for testing, including completing or canceling the verification by calling specific endpoints.

Working with the WebOTP API

For the WebOTP API, keep in mind that you must call navigator.credentials.get before the SMS is received by the user. It then waits for the SMS to arrive, at which point the OTP will be passed to the browser.

The API is not supported on iOS or most desktop browsers, so it should be used as a progressive enhancement alongside other best practices like domain-bound OTPs and a well-configured input field. The API also requires a user action—such as clicking a button or focusing the input field—before you can call navigator.credentials.get. This is a built-in security measure that prevents the API from running silently in the background.

Handling errors

Don’t forget to handle error cases. Your form should allow the user to resend and retry the OTP, but with a timeout to prevent bad behavior. You can also provide alternate channels such as voice calls after the user has tried other methods first.

Conclusion

In addition to protecting accounts, a secure OTP process builds trust with your users. Simple things like a well-configured input field, a domain-bound OTP, and autofill via the WebOTP API make a big difference in creating a smooth, low-friction experience. They help prevent phishing, reduce drop-offs, and make verification feel effortless.

At the end of the day, OTP is about striking the right balance between security and usability. Whether you’re verifying contact info or helping users recover accounts, getting these details right gives your users a safer app and a better experience.

Additional Resources