Best Practices for OTP Input Forms in Android
Time to read:
Best Practices for OTP Input Forms in Android
One-time passwords (OTPs) are a standard method for confirming a user’s contact information and enabling secure login, with or without a password. An OTP can be sent via multiple pathways, including SMS and email.
Using an OTP helps verify a user’s contact information while keeping the login experience simple. For Android apps, implementing OTP is straightforward—as long as you pay attention to a few critical details. In this post, we’ll cover practical tips for creating a smooth, secure OTP flow in your Android app.
Need OTP for other platforms? Check out our companion web HTML and iOS articles.
OTP workflows and use cases
The basic flow for OTP verification looks like this:
- The user enters their phone number or email and submits the form to the app.
- The app generates a token (for example:
123456
) and sends the token to the user’s phone number or email. - The user enters the token into the OTP verification form.
- The app verifies the token.
This simple workflow has become nearly ubiquitous. The use cases for OTP verification include:
- 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.
- 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.
- 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 Android
To streamline and secure the OTP Verification process, follow these best practices:
- Decide on the design of the OTP input field
- Create a proper input field using either a native Android View or Jetpack Compose.
- Use an SMS API to handle autofill and send an appropriately formatted SMS.
Decide on the design of the input field
For the input field of the OTP, you can either use a single input field or multiple input fields (one for each digit). Many design teams opt for the multiple input field solution. This approach makes it clear to users how many digits they must input, and it uses all of the available screen space. It also provides a way to highlight to the user which digit they are currently entering.
However, multiple input fields add complexity regarding handling cursor movement between fields. Additionally, you must also handle autofill or pasting the OTP code into the fields. These problems are solvable, but require some extra effort.
Using a single input field is generally simpler, as it simplifies the implementation of autofilling and or pasting. A single input field does not need any additional logic to handle cursor management.
A hybrid solution is also possible, where a single input field is styled as multiple inputs. Visually, the user will see multiple inputs, but under the hood, your app treats this as a single input. This solution is possible when using Jetpack Compose.
With an awareness of the tradeoffs involved, any of the above approaches can yield an effective OTP input field that provides a smooth user experience.
To create the input field, you can use either a native Android View or Jetpack Compose. We’ll give examples for both.
Create the OTP input field using Jetpack Compose
With Jetpack Compose, you can implement a hybrid solution, where a single input field is styled to appear visually as multiple input fields. For example:


To do this, use a single BasicTextField
. For example:
Note the following key points from this example:
- The keyboard type is
KeyboardType.NumberPassword
, providing your user with a numeric keyboard that only displays digits. - The length of the input is restricted through the use of
onValueChange
. - Styling is handled through the
decorationBox
property, which creates aCharView
for each character.
You can implement CharView
to align with specific stylistic and UX requirements. For example:
This implementation adds some basic logic to indicate to the user when a digit currently has focus.
Create the OTP input field using a native Android View
Here is an example of a multiple input OTP field using native Android Views.
Note the following key points from this example:
inputType
is set tonumber
.importantForAutofill
is set toyes
.
Remember that while inputType="number"
provides a numeric keyboard, OTP codes should always be treated as strings, not numbers. This preserves leading zeros (like in 012345
) and trailing zeros (like in 120000
) that would be lost if you convert the input to an integer and back to a string. Be especially careful when extracting codes from SMS messages or sending them to your server for verification.
To set the autofill hints for a multiple input field, use generateSmsOtpHintForCharacterPosition()
. Here is sample code that uses the library function:
Implementing cursor management is also recommended, though not required. This way, if the user manually types in the OTP, the cursor automatically moves from one field to the next. This can be implemented via addTextChangedListener
.
Use the SMS Retriever API
Autofill helps you streamline the OTP process, eliminating the need for users to exit the app and manually enter the code. Google Play services provides two different APIs that you can use to accomplish this. The first is the SMS Retriever API.
If we have control over the contents of the SMS message, the SMS Retriever API is the preferred option. To use the SMS Retriever API, follow these instructions install the required Google Play services dependencies then call startSmsRetriever()
before the SMS is received.
Once the listening has begun, your app can send a verification SMS. The SMS must meet the following requirements:
- Be no longer than 140 bytes
- Contain the OTP code
- Include an 11-character hash string that identifies your app. Refer to this resource for details on calculating your app's hash string.
Here is an example of the proper format:
You can set up custom OTP formats via Twilio Verify by using a custom template.
Next, use a BroadcastReceiver
to handle the SmsRetriever.SMS_RETRIEVED_ACTION
intent. This will give the text of the message.
With the above example implementation, the app can parse the message for the code and then submit it to the server for the user. No manual typing is needed.
Use the SMS User Consent API
The other option is to use the SMS User Consent API. This option prompts the user to give your app access to the contents of a single SMS for the purpose of autofill. To use the SMS User Consent API, you must call startSmsUserConsent()
before the SMS is received.
Once the listening has begun, the app can send a verification SMS. This SMS must meet the following criteria:
- The message contains the OTP code, which is 4-10 alphanumeric characters and includes at least one number.
- The message must be sent within the next 5 minutes.
- The SMS sender cannot be in the user’s contact list.
In contrast to the SMS Retriever API, this method does not require an app-specific hash code.
Next, use a BroadcastReceiver
that has the SEND_PERMISSION
permission and responds to SMS_RETRIEVED_ACTION
intents. This will give the text of the message.
The user will be prompted for permission to read the message contents. From there, the app can parse the message for the code, submitting it to the server on behalf of the user without any manual typing needed.
Testing and Tips
After configuring your input field and SMS delivery, thorough testing is vital. Whether you are using a prebuilt solution and testing with a template from Twilio Verify or testing a custom OTP flow, the following guidance will help you along the way.
Troubleshooting cursor management or autofill issues
If you are using multiple input fields and having trouble with cursor management, remember that you must implement cursor management separately; this functionality is not built-in. Alternatively, consider switching to a single input field or using the hybrid approach with Jetpack Compose.
If you’re having trouble with autofill, first confirm whether you are using the SMS Retriever API or the SMS User Consent API.
- For the SMS Retriever API, make sure that you have correctly computed your app’s hash string and are including this string in your SMS message.
- For the SMS User Consent API, ensure that your code meets the length and content criteria outlined above and that the sender is not included in the user’s contact list.
- For both API cases, ensure that you have started listening for the SMS before it is sent.
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.
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 deter bad actors. You can also provide alternative channels, such as voice calls, after the user has tried other methods first.
Conclusion
A reliable OTP flow does more than authenticate users—it shapes their experience with your Android app. By combining thoughtful input design with the right autofill API, you can protect your users' accounts while streamlining the verification process. And all of this without forcing users to leave your app.
Following design and implementation best practices ensures your OTP process feels seamless and secure. Getting these details right strengthens both your app’s security and your users’ trust.
Additional Resources
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.