Web3auth otp resend timer pauses when app goes to background

Description:

The OTP resend timer on the Web3Auth “Enter OTP” screen does not continue running when the app goes to the background. If the device screen times out the timer pauses instead of continuing in the background.

When the user returns to the app, the timer resumes from the same point where the screen was blacked out instead of reflecting the real elapsed time.

This creates an inconsistent experience because the resend cooldown should be based on real time, not active screen time.


Steps to Reproduce:

  1. Open the app and go to the login screen.

  2. Enter an email and tap Continue.

  3. Web3Auth Enter OTP screen appears with the 60-second resend timer.

  4. Leave the app in the background or allow the screen to time out after ~30 seconds.

  5. Reopen the app.


Expected Behavior:

The OTP resend timer should continue counting down while the app is in the background.

When the user returns to the app, the timer should reflect the actual remaining time.

Example:

If the timer started at 60 seconds and the user returns after 30 seconds, the timer should show ~30 seconds remaining.


Actual Behavior:

The timer pauses while the app is in the background.

When the user returns, the timer resumes from the same point where it stopped.

Thanks — this matches a common issue: timers using setInterval pause in the background. Quick checklist and fix:

Cause

  • The OTP UI is likely using runtime timers (setInterval) instead of an absolute timestamp, so backgrounding freezes the countdown.

Fix (recommended)

  • When OTP is sent, save an absolute timestamp (issuedAt from server or Date.now()).
  • On mount (and each tick), compute remaining = max(0, COOLDOWN_MS - (Date.now() - issuedAt)).
  • Use that computed remaining to render/disable the resend button and to drive the visible countdown. This way the timer reflects real elapsed time even after backgrounding.

Minimal JS example:
const COOLDOWN = 60000; // ms
// on OTP send: store issuedAt (prefer server time)
const issuedAt = Date.now();
// on mount/tick:
const remainingMs = Math.max(0, COOLDOWN - (Date.now() - issuedAt));
// disable resend if remainingMs > 0; display Math.ceil(remainingMs/1000)

If you’re using the Embedded Wallets prebuilt OTP screen and can’t override this logic, file a bug/feature request at https://github.com/MetaMask/embedded-wallets-sdk/issues or check whether your SDK version exposes an OTP-sent event to capture issuedAt.

Can you confirm: SDK version and platform (iOS/Android/web) and whether you’re using the prebuilt OTP UI or a custom screen? If you want, I can give a ready React Native snippet using AppState to persist issuedAt.

Note: This response was generated by an AI bot and may require further verification. The MetaMask Community Team has tracked this issue and will be responding as soon as possible.

Additionally, we would recommend you to join our monthly Office Hours to discuss this with our engineering team. MetaMask Developer Office Hours

1 Like

Hi @accounts1 Would you mind if you can also attach a video recording that showing this issue? Thank you!

Hey @accounts1

This issue is happening since the app’s browser instance is getting crashed when you are switch to a different application. You need to optimise the memory management of your application for fixing this. One of the users mentioned upgrading to Expo v55 fixed it for them.