Rate this page:

Verify Push and Silent Device Approval Best Practices for Production use


Verify Push and Silent Device Approval is designed for global, web-scale use. The Twilio Verify platform that it's built on verifies over 200 million users annually. To fully realize the benefits of Verify Push in your own real-world production implementation, we've compiled a running list of best practices to consider. These best practices are organized as Q&A under these topics:

  1. Conversion Rate

  2. Security

  3. Client App

  4. Performance

  5. Project Management

  6. Testing
  7. Common Issues

Conversion Rate

1. What are methods to ensure that the device receives the challenge?

A critical step in the Verify Push verification sequence is for the app on the registered device and the user to be made aware that a pending challenge has been created by the customer backend/Verify Push API. We recommend starting with the "poll for the challenge" method, and then supplementing with push notifications for a better user experience. Both approaches are described below.

Poll for the Challenge

Once the pending Challenge has been created in the Verify API, your mobile app needs to become aware of it. This can be done by telling your user to open up your mobile app on the registered device, and then having your app check (poll) the Verify API for any pending Challenges whenever it's opened.

Polling implementation tips

Push Notifications

You can set up the Verify Push API (technically Notify) to send a visible push notification to your mobile app whenever a pending Challenge is created. This is a great user experience as the user can see the push notification on their device's lock screen. However, this method might fail in certain scenarios like poor connectivity, the app being in a closed state, or users turning off push notifications. This is why we recommend always implementing the previous "poll for the challenge" method as a backup.

Push notification implementation tips

  1. Configure app to receive push notifications, including background notifications that can still be received by the app even if the user has disabled visible push notifications when the app is in foreground.
  2. If the app is closed when it receives the push notification, it should attempt to store the challenge_sid and factor_sid contained in the push notification's payload, so that it can immediately poll the Verify Push API with that data when it’s next opened.
  3. Give the user the option to request another push notification if they didn't get the first one. Resend for the same Challenge using the Notifications resource.
  4. Nudge the user to enable visible push notifications after they register their device, so that they will see a push notification on the lock screen of their device
  5. Have the app send a confirmation to the customer backend when it receives a push notification from Verify Push (Notify). If the customer backend doesn’t receive a confirmation from the app after an expected latency from when the challenge was created, then the customer backend should assume that the push notification failed and resend.
  6. Customer backend should subscribe to debugger webhooks for the Verify Service. These webhooks contain error codes published by Verify Push, including errors related to push notification failures.

TransferWise example

As shown in the screenshots below, TransferWise's implementation illustrates several of the best practices described earlier, such as instructing the user to "approve this login by opening the TransferWise app" and offering the option to "resend push on phone".

Screen Shot 2020-10-07 at 11.15.27 AM.jpg

Screen Shot 2020-10-07 at 11.15.35 AM.jpg

2. In which countries does it work?

Unlike SMS, which has country-specific constraints due to Carriers being country-specific, Verify Push works whenever there’s an internet/data connection and on any device that runs standard iOS, Android, or a supported web browser. The exceptions to this that we are aware of are:

  • Android devices built by Huawei that don’t support Google Messaging Services, including Firebase Cloud Messaging, won’t be able to receive push notifications. However there are workarounds to this as explained in “what are methods to ensure that the device receives the challenge?
  • Country prohibitions defined in Twilio’s general export control policy (e.g. Iran)


1. If a user installs the app on their device, registers the device, deletes the app, and then reinstalls it on the same device, will the device become registered again?

No, deleting the app from the device completely unregisters the device from Verify Push.

2. How do I support multiple devices per user?

From a technical perspective, a user can register multiple devices as factors. From a security policy perspective, the decision of whether to allow a user to enroll more than one device as a factor is up to you. The benefit of doing so is that it makes it more convenient for the user to respond to a push from multiple devices and it creates redundancy if they were to lose one device. The downside is that it increases the attack surface for a fraudster. Note that querying the SDK on an enrolled device will only return the factor(s) created on the same device, so a fraudster wouldn’t be able to discover all of a user’s registered device.

3. Can the user receive/approve a push if they aren’t logged into our app

You can configure Verify Push such that the user can receive/approve a push in the app on the registered device, even if they aren’t logged into their account on that app. Conversely, you can require that they login first (using a different verification) before approving the push.

Client App

1. How do I know if the user uninstalls my app?


When the app is uninstalled, if you send a challenge to a user, your backend will receive an OK about creating the challenge, but your Twilio debugger will receive an error because the push notification couldn't be sent:

You can add a webhook for Twilio debugger and you will receive an event when this error happens. The event will be sent only one time after the app was installed. After this, push notifications will not be sent.

You can identify the factor, entity and service sid related to the error. The Payload.more_info will contain the values in the correlationIds field:

"more_info": {
 "bindingType": "fcm",
 "primaryCorrelationId": "RU1997axxxxxxxxxxxxxxxxxx5eb0cd4cd",
 "bindingSid": "BS35bc1xxxxxxxxxxxxxxxxxxa120437c1",
 "providerMessageId": "RU23c27xxxxxxxxxxxxxxxxxx753723240",
 "requestId": "RQ8202exxxxxxxxxxxxxxxxxx6082c6805",
 "correlationIds": "[VAf510xxxxxxxxxxxxxxxxxxb8ae2e7251, test-identity, YF0314fxxxxxxxxxxxxxxxxxx1349180db, YC03b4fxxxxxxxxxxxxxxxxxx13491tf45]",
 "notificationSid": "NT033xxxxxxxxxxxxxxxxxx487ed02cd34",
 "module": "FCMBA",
 "description": "401 http response from Fcm Service",
 "isPassthrough": "false",
 "deliverySid": "DA3e727xxxxxxxxxxxxxxxxxxa3647a384",
 "fromReference": "CRe07eaxxxxxxxxxxxxxxxxxx59d45351c"

You can get the factor sid from the correlationIds field, and delete the factor in the Verify Push backend from your backend.

Keep in mind

  • There is not a specific order of the correlationIds values. So you will not always receive them in that order.
  • The debugger events cannot be filtered by verify service sid as verify webhooks. The debugger webhooks are configured for your account, but you will receive the verify service in the correlationIds field.


iOS APNs recently stopped in November 2020 sending an error, so this debugger webhook will not work for iOS anymore. An alternative solution is to create logic in your backend that looks at whether your app has been active recently and whether previously created challenges have been verified to determine whether the app is still installed or not. If not, then delete the factor. This logic can also work for Android as an additional app uninstall detection method.

2. How do I handle different dev environments?

We recommend creating different Verify Services for each environment (e.g. one for testing, one for production). Also, take into account that iOS uses different APN environments according to the signing certificate.

  • For development, you should use an 'Apple Push Notification service SSL (Sandbox)' certificate or an 'Apple Push Notification service SSL (Sandbox & Production)' certificate, and your push credential's Sandbox option should be checked.
  • For production, you should use an 'Apple Push Notification service SSL (Sandbox & Production)' certificate, and your push credential's Sandbox option should be unchecked.
  • It is better to use a different push credential for each verify service per environment

3. How do I support user language preferences?

Verify Push receives the message and details that could be shown to the user (depends on your implementation). We recommend using the user language preference for your app to send the message and details in the correct language. For example, if your user language in your app is French, you should send the challenge's message and details in French.

4. How do I handle users who disable push notification for my app?

Some users may choose to disable push notifications from your app in their OS settings. This just means that the user won't see the notification in the OS's notifications drawer/center. However, APNs and FCM will still work behind-the-scenes. Pushes will still be delivered directly to your app, if it's in the foreground. Specifically:

For Android, if notifications are disabled, your user won't see a notification outside of your app, but you will still receive the push in your app if it is in foreground and the push token won't change.

For iOS, if notifications are disabled, the system delivers all remote notifications to your app silently so you will receive the push if it is in foreground in the method userNotificationCenter(_:willPresent:withCompletionHandler:). Getting the device token will depend on your implementation. For example, if you call registerForRemoteNotifications only if notification permission is enabled, you won't get a device token, see sample app.

5. How do I get the push token?

You will need the device push token to create factors.

For Android, you should get the push token before creating a factor and validate your app has a value for it. Getting a registration token can fail, and you will receive an exception.

For iOS, you should get a push token before creating a factor and validate your app has a value for it. Getting a device token can fail, and you will receive a call for the method application(_:didFailToRegisterForRemoteNotificationsWithError:)

Take into account that the device/registration token could change, so the app should identify this case and update all the factors in the device, for reference: updated push token for Android and updated push token for iOS

6. How do I de-duplicate challenges that are approving the same action?

Your backend can generate an action_id that is unique to the verification action that needs to be approved by your user, and provide it in the HiddenDetails property of the Challenge. The HiddenDetails value of a Challenge is visible to the mobile client and can be used to de-dup Challenges with the same action_id without querying the your customer backend.

However, your mobile client will still need to query your backend to find if a given Challenge and associated action_id was approved, especially if the user has the option of simultaneously verifying the same action via another verification method, like SMS OTP.


1. What is the expected latency for API responses?

The overall Verify API SLA for the latency of responses to requests is 300ms. This is measuring the time from when the request is received by the Verify API to when it sends the response. A different latency measure is the round-trip-time (RTT) latency, which is measured from when the request is sent by the requester to when the requester receives the response from the Verify API. RTT latency will be longer than the responses-to-requests latency, and will vary depending on the physical distance of the requester to Verify API’s servers, which are located in the US East Coast by default. If you want to reduce RTT latency, try two things:

  1. Try to reduce the overall number of requests you’re making to the Verify API. While this won’t reduce the RTT of an individual request, it will reduce the overall latency experienced by your users. One example optimization: when you’re registering a new user and device, you don’t need to make a separate Create Entity call, because the Create Factor call will both create an Entity and a Factor at the same time.
  2. Send your requests to a public Edge Location that is physically closer to where you’re requesting from compared to the default US East Coast location. While Verify API does not fully support Edge Locations currently, RTT latency can still be lowered, because the shared Twilio API gateway services that Verify uses supports Edge Locations. Note that using Edge Locations might actually increase latencies when reusing connections, and so you’ll need to try and see if this is acceptable. You can switch to an Edge Location by changing the request URL. For example, to send to the Singapore edge, the request AccessTokens URL should be:

Project Management

1. How much work is it to implement Verify Push?

Your mileage may vary. We’ve consistently heard that understanding Verify Push is the easy part. The complexity level of your existing apps/backend (e.g. how many places in your UX do you need to insert Verify Push?) is the major driver of the overall amount of work. As general guidance, we suggest budgeting the following amount of time based on feedback from customers who’ve done it:

  • Setting up the Verify Push Sample App/Backend and understanding how Verify Push works in general takes 1-3 days.
  • Integrating Verify Push as a prototype into your own app(s), backend, and existing login flows takes 1-2 weeks.
  • Getting to production-grade, including testing, could take an additional couple weeks.


1. Testing your backend

You can create a mock for the Verify API using OpenAPI specification. You should use the twilio_verify_v2 resources.

2. Testing your apps

You can create a mock for your backend and use the Verify API mock you created for testing your backend. You will have a different URL or environment to use in your apps.

The SDKs communicate directly with the Verify API, so you will need to change the URL to be used in the SDKs. For this, you can create your own NetworkProvider to intercept the SDK request and change the URL.


  1. Implement your own NetworkProvider to change the URL, you can use the NetworkProvider SDK implementation, NetworkAdapter, as a guide
  2. Change the URL before executing the request
  3. You can pass your own NetworkProvider when building the TwilioVerify instance using the Builder's networkProvider method


  1. Implement your own NetworkProvider to change the URL, you can use the NetworkProvider SDK implementation, NetworkAdapter, as a guide
  2. Change the URL before executing the request
  3. You can pass your own NetworkProvider when building the TwilioVerify instance using the TwilioVerifyBuilder's setNewtorkProvider method

Change the URL of your app to use the mock or the implementation calling the Verify API mock.

Common Issues

1. Pushes not arriving?

The Challenge will be created, so to troubleshoot the issue, start by checking your Twilio debugger to get the error code. Then visit Twilio error codes to understand the issue and possible solutions, e.g.:

  • Error code 52143: Application device token and certificate subject must have the same bundle id

2. Getting an Invalid APNs device token (Error code 52134) for iOS?

Possible Causes

  • APNs device token format is invalid.
  • Trying to use a development certificate for a production application or vice-versa.

For development signing certificates, e.g. running your app from xcode with debug build configuration or debugging application, you will need to enable the Sandbox option for your push credential

For distribution signing certificates, e.g. archiving app or running the release build configuration, you will need to disable the Sandbox option for your push credential

3. How do I get notified when a challenge was received by my app?

As the push notification implementation is handled by your app, only your app will know when the push notification is received. Your Verify webhook will only receive challenge.approved and challenge.denied events for Challenges, so your backend should provide a way to be notified that a notification for a challenge was received from your app.

4. Using test credentials?

Test credentials are not supported for Verify Push.

5. Getting fewer factors than expected for a user from the SDK?

The SDK will return the factors stored in the device, so if you call getAllFactors method, you will get only the factors in the device (e.g. 2 factors), and if you have another device (e.g. 3 factors), the user will have 5 factors, but each device will return only the factors stored in the device.

6. Factor deletion or TwilioVerify initialization throwing an error?

The SDK uses Keychain to save the information in a secure way, so Keychain operations could throw an error, for example when deleting a factor (Keychain delete operation) and TwilioVerify initialization (migrating information from one version to a new one). You should implement an alternative flow in case of an error.

Rate this page:

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.

Loading Code Sample...

        Thank you for your feedback!

        Please select the reason(s) for your feedback. The additional information you provide helps us improve our documentation:

        Sending your feedback...
        🎉 Thank you for your feedback!
        Something went wrong. Please try again.

        Thanks for your feedback!