Common Onboarding Flow Bugs and How to Catch Them
Common Onboarding Flow Bugs and How to Catch Them are critical to understand before releasing any new user journey. Onboarding is the first impression a product makes; bugs here can cause abandonment,
Common Onboarding Flow Bugs and How to Catch Them are critical to understand before releasing any new user journey. Onboarding is the first impression a product makes; bugs here can cause abandonment, negative reviews, and lost revenue. This guide walks through twelve real‑world bug patterns that frequently appear in sign‑up, login, permission, and tutorial flows. For each pattern we explain the root cause, the user‑visible symptom, reproducible steps, detection techniques (both manual and automated), and concrete fixes. The article also shows how persona‑driven autonomous exploration—like that performed by the SUSATest agent—can surface issues that scripted tests miss, and it ends with a practical checklist you can add to your CI pipeline.
Common Onboarding Flow Bugs and How to Catch Them: Email Verification Issues
Why it happens
Email verification bugs usually stem from timing assumptions. The frontend may hide the “Verify email” button until a backend callback arrives, but the callback can be delayed or lost if the email service throttles requests, if the user’s inbox filters the message, or if the link contains a token that expires too quickly. In addition, some cases where the verification endpoint returns a 200 OK but the user record is not updated, the UI stays stuck in a pending state.
How it looks to users
After submitting their email, the user sees a spinner or a message like “We’ve sent you a verification link.” If the link never arrives, the UI does not change, and there is no way to resend the email. Users may repeatedly tap the submit button, causing duplicate requests, or they may abandon the flow altogether, thinking the app is broken.
How to reproduce and detect it
- Manual – Use a disposable email service (e.g., Mailinator) and monitor the inbox while registering. Turn off network throttling to simulate a slow email provider.
- Automated script – In an Appium test, after clicking “Sign up,” wait for the verification toast, then poll an email API (such as MailSlurp) for the message. Assert that the token in the link is valid and that clicking it updates the user’s verified flag.
- Persona‑driven autonomous exploration – Configure a “curious” persona that attempts to resend verification after a delay, and an “impatient” persona that taps the submit button repeatedly. The autonomous agent will notice that the UI does not provide a resend option and will flag a missing affordance.
How to fix and prevent it
- Add a visible “Resend verification email” button that becomes active after a configurable timeout (e.g., 30 seconds).
- Make the verification endpoint idempotent: resending should not create duplicate records.
- Store the verification token with a longer expiry (at least 24 hours) and return a clear error if the token is expired or already used.
- In unit tests, mock the email service to simulate latency, token expiry, and delivery failure, asserting that the UI gracefully handles each case.
Common Onboarding Flow Bugs and How to Catch Them: Social Login Failures
Why it happens
Social login depends on third‑party OAuth providers. Bugs arise when the redirect URI is misconfigured, when the client secret or API key is rotated without updating the app, or when the provider scopes change (e.g., Facebook removing email access). Additionally, some providers enforce strict SameSite cookie policies that break the flow when the app is embedded in a webview or when the user disables third‑party cookies.
How it looks to users
The user clicks “Sign in with Google” and is taken to the provider’s consent screen. After granting permission, they are redirected back to a blank page or see an error like “redirect_uri_mismatch.” In other cases, the flow loops: the provider redirects back to the app, which immediately redirects again to the provider, creating an infinite loop that the user must break by closing the browser.
How to reproduce and detect it
- Manual – Use a browser devtools network tab to capture the redirect chain. Change the OAuth client ID in the app’s configuration to an invalid value and observe the error message returned by the provider.
- Automated script – With Playwright, navigate to the social login button, click it, and wait for either the provider’s consent dialog or a timeout. After granting permission (using the provider’s test credentials), assert that the final URL matches the expected onboarding screen and that the user object contains the expected fields (e.g., email, name).
- Persona‑driven autonomous exploration – An “adversarial” persona can tamper with the redirect URI query parameters (e.g., injecting
../) to see if the app validates the redirect correctly. The agent will log any validation bypass as a security finding.
How to fix and prevent it
- Keep the redirect URI exactly as registered in the provider’s console, including protocol, host, and path. Use environment‑specific values (staging vs production) and validate them at startup.
- Store client secrets in a secure vault; rotate them with a zero‑downtime strategy that keeps the old secret valid for a short overlap period.
- Request only the scopes you need and handle scope‑change errors gracefully by falling back to alternative data collection (e.g., asking the user to enter their email manually).
- Set the SameSite attribute of auth cookies to
LaxorNonewith Secure flag when using cross‑site redirects, and test the flow in both Chrome and Safari webviews.
Common Onboarding Flow Bugs and How to Catch Them: Permission Prompt Missteps
Why it happens
Mobile apps often request permissions (camera, location, notifications) at launch. Bugs appear when the permission rationale is missing, when the app requests a permission before explaining why it’s needed, or when the flow does not handle the “Don’t ask again” state. On Android, requesting a permission after the user has selected “Deny and don’t ask again” results in a permanent block unless the user manually changes settings.
How it looks to users
The user sees a system dialog asking for access to the microphone. If they deny it, the app may show a vague error like “Feature unavailable” without indicating that permission is required. In worse cases, the app crashes because it tries to access a null camera object after a denial.
How to reproduce and detect it
- Manual – Go to Settings → Apps → YourApp → Permissions and revoke a permission. Relaunch the app and attempt to use the feature that needs it. Observe whether the app explains why the permission is needed and offers a way to re‑enable it.
- Automated script – Using Espresso, revoke runtime permissions via
adb shell pm revoke, launch the activity, and assert that a Snackbar or dialog appears with a rationale and a “Settings” button that redirects to the app’s permission page. - Persona‑driven autonomous exploration – A “novice” persona will tap the feature button immediately after launch without reading any onboarding screens. The agent records whether a permission rationale is shown before the system dialog, and flags missing explanations as a UX friction point.
How to fix and prevent it
- Follow the platform’s best practice: show an in‑app explanatory screen (rationale) before invoking the system permission dialog.
- Store the denial state and, on subsequent launches, present a persistent banner that explains the benefit and provides a shortcut to Settings.
- Guard all API calls that require the permission with a runtime check; if denied, return a graceful fallback or disabled UI rather than throwing an exception.
- Write unit tests that mock the permission manager to return
DENIED,DENIED_DONT_ASK, andGRANTED, verifying the UI response for each.
Common Onboarding Flow Bugs and How to Catch Them: Terms of Service Scroll Trap
Why it happens
Many onboarding flows present a lengthy Terms of Service (TOS) inside a fixed‑height scroll view. Bugs occur when the scroll view does not detect that the user has reached the bottom, when the “Accept” button remains disabled despite scrolling, or when the scroll view’s bounce effect interferes with gesture recognition, causing the user to think they have finished reading when they have not.
How it looks to users
The user scrolls through the TOS, reaches what appears to be the end, but the “I Agree” button stays grayed out. They may scroll back up and down repeatedly, become frustrated, and either abandon the flow or force‑accept by tapping elsewhere, potentially violating legal requirements.
How to reproduce and detect it
- Manual – On a device with a small screen, load the TOS screen and perform a slow scroll to the bottom. Observe whether the Accept button enables. Then try a fast flick; note if the button enables inconsistently.
- Automated script – With UiAutomator, scroll to the bottom of a
RecyclerViewcontaining the TOS text usingscrollToEnd(10). After the scroll, assert that the Accept button is enabled. Add a test that performs a rapid fling and verifies the same outcome. - Persona‑driven autonomous exploration – An “impatient” persona will attempt to tap the Accept button immediately after a single swipe. The agent will detect that the button remains disabled and will log a missing affordance or incorrect scroll‑completion detection.
How to fix and prevent it
- Compute the scrollable height dynamically and enable the Accept button only when
scrollY >= contentHeight - visibleHeight. - Debounce rapid scroll events to avoid race conditions where the button toggles incorrectly.
- Provide a visual indicator (e.g., a progress bar) that shows the percentage read, reinforcing that scrolling to 100 % is required.
- Include an accessibility test that ensures the Accept button is reachable via TalkBack when scrolled to the bottom.
Common Onboarding Flow Bugs and How to Catch Them: Password Complexity Miscommunication
Why it happens
Password rules are often embedded in inline validation messages that appear only after the user types a character. If the rules are not displayed up front, users may submit a password that fails silently, receiving a generic “Invalid password” error without knowing which rule they violated. Additionally, some implementations incorrectly enforce maximum length or disallow certain Unicode characters, causing lockouts for users who rely on non‑ASCII passwords.
How it looks to users
After creating an account, the user taps “Sign up” and sees a toast: “Password must contain at least one number.” They have no idea whether their password also needs a special character or a minimum length, leading to multiple trial‑and‑error attempts.
How to reproduce and detect it
- Manual – Enter a password that satisfies length but lacks a number. Submit and note the error message. Then clear the field and type a password that meets all stated rules but includes an emoji; see if the submission is blocked without explanation.
- Automated script – Using Selenium, fill the password field with a series of test values (e.g.,
abcdef,Abcdefg1,Abcdefg1!,😀😀😀). After each submission, capture the validation message and assert that it mentions every violated rule. - Persona‑driven autonomous exploration – A “power user” persona will try to paste a long passphrase from a password manager. The agent verifies whether the UI accepts or rejects it and whether the reason is clearly communicated.
How to fix and prevent it
- Show the full list of password requirements beside the input field before the user types.
- Use real‑time validation that highlights each satisfied rule with a checkmark and each unsatisfied rule with a cross.
- Avoid arbitrary maximum lengths; if a limit is necessary (e.g., for backend storage), document it and enforce it consistently on both client and server.
- Accept Unicode characters and normalize them (e.g., NFC) before hashing to prevent lockouts due to encoding differences.
Common Onboarding Flow Bugs and How to Catch Them: Stale Session Handling
Why it happens
After a user signs up, the app may automatically log them in and cache a session token. Bugs arise when the token is stored insecurely (e.g., in plain‑text SharedPreferences) or when the app fails to refresh the token before it expires, causing subsequent API calls to return 401 errors that are not handled gracefully.
How it looks to users
The user completes registration, sees a welcome screen, then navigates to the home feed. After a few minutes, the feed stops loading and shows a generic “Something went wrong” message. Logging out and back in temporarily resolves the issue, indicating a token expiry problem.
How to reproduce and detect it
- Manual – Log in, then use the device’s clock to fast‑forward time (or use a tool like
adb shell dateto set the system time ahead) beyond the token’s TTL. Attempt a protected API call and observe whether the app silently fails or prompts for re‑authentication. - Automated script – In a Jest test that mocks the auth service, set the token’s
expiresInto 5 seconds, wait 10 seconds, then call a protected endpoint. Assert that the interceptor catches the 401, triggers a refresh, and retries the request successfully. - Persona‑driven autonomous exploration – A “curious” persona will leave the app idle in the background for an extended period, then return and attempt to use a feature that requires auth. The agent will detect whether the app silently fails or initiates a silent refresh.
How to fix and prevent it
- Store access tokens in the OS‑provided secure storage (Keystore on Android, Keychain on iOS).
- Implement an auth interceptor that checks the token’s expiry time; if it is within a refresh window (e.g., 5 minutes), silently obtain a new token using the refresh token before proceeding with the request.
- On refresh failure, redirect the user to a login screen with a clear message: “Your session has expired. Please sign in again.”
- Write contract tests for the auth endpoint that verify the shape of the refresh response and that the access token’s expiry is correctly set.
Common Onboarding Flow Bugs and How to Catch Them: Incorrect Deep Link Routing
Why it happens
Onboarding often includes deep links from email or SMS that should take the user straight to a specific screen (e.g., “Complete your profile”). Bugs appear when the intent filter does not match the link’s host or path, when the app receives the link but the navigation stack is not reset, or when the link parameters are not parsed correctly, leading to a blank screen.
How it looks to users
The user clicks a link in their verification email that says “Finish setting up your account.” The app opens, but they land on the home screen instead of the profile completion screen, causing confusion and possibly causing them to miss a required step.
How to reproduce and detect it
- Manual – Send yourself an email with a deep link (e.g.,
myapp://complete-profile?token=abc123). Click it on a device where the app is installed. Verify which screen appears. - Automated script – Using ADB, invoke
adb shell am start -W -a android.intent.action.VIEW -d "myapp://complete-profile?token=abc123" com.example.app. Then use UIAutomator to assert that the current activity isProfileCompletionActivity. - Persona‑driven autonomous exploration – An “elderly” persona may tap the link, then immediately press the back button expecting to return to the email. The agent checks whether the back stack behaves correctly (i.e., returns to the email app or shows a suitable confirmation).
How to fix and prevent it
- Declare intent filters with precise
android:hostandandroid:pathPatternattributes, and test them with the Android Studio Deep Link Testing tool. - In the destination activity, call
setIntent(intent)early and extract query parameters usingUri.parse(intent.getDataString()). Provide default values for missing parameters and show an error if required ones are absent. - When handling a deep link, consider clearing the task stack with
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASKif the link should start a fresh onboarding flow. - Add an Espresso test that simulates receiving a deep link via
Intentand asserts the correct fragment is displayed.
Common Onboarding Flow Bugs and How to Catch Them: Toast Overload
Why it happens
Toasts are used for transient feedback, but some teams overuse them, showing a toast for every validation step, network event, or UI change. When multiple toasts queue, they can obscure important information, and on some Android versions, toasts may be dismissed automatically after a short duration, leaving the user unaware of an error.
How it looks to users
After submitting a form, the user sees a series of toasts: “Checking email…”, “Email valid”, “Saving data…”, then a final toast “Error: server unavailable” that disappears after two seconds. The user may miss the error and think the submission succeeded.
How to reproduce and detect it
- Manual – Disable the network or mock a failing API endpoint. Submit the form and watch the toast stream. Note whether any toast persists long enough to be read and whether a critical error is buried.
- Automated script – With Espresso, use
onView(withText(containsString("Error"))).inRoot(isToast())to assert that an error toast appears. Add a test that counts the number of toasts shown within a five‑second window and asserts it does not exceed a reasonable threshold (e.g., two). - Persona‑driven autonomous exploration – A “frustrated” persona will rapidly tap the submit button multiple times. The agent records whether the UI shows a single aggregated error message or a flood of duplicate toasts, flagging the latter as a usability problem.
How to fix and prevent it
- Reserve toasts for non‑critical, short‑lived messages (e.g., “Item saved”). Use snackbars or dialogs for actions that require user acknowledgement (e.g., network failure, validation errors).
- Implement a toast queue that merges duplicate messages and shows the most recent one for a minimum duration (e.g., 4 seconds).
- Provide a persistent inline error indicator (e.g., red border with helper text) alongside the toast so that users who miss the toast still see the problem.
- Write a UI test that verifies that after an error, at least one visible error indicator remains on screen until the user attempts to correct the input.
Common Onboarding Flow Bugs and How to Catch Them: Incorrect Orientation Lock
Why it happens
Some onboarding screens lock orientation to portrait, assuming the user will always hold the device vertically. Bugs arise when the lock is applied too early (e.g., before the splash screen finishes), causing a flash of landscape content, or when the lock is not released after onboarding, preventing the user from rotating to landscape for better readability of long forms.
How it looks to users
During the tutorial swipe carousel, the user rotates the device to landscape to view a wide diagram. The app snaps back to portrait, cutting off the diagram and forcing the user to rotate back, which feels jarring and may cause them to skip the tutorial.
How to reproduce and detect it
- Manual – Launch the app, rotate to landscape while onboarding is in progress, and observe whether the UI respects the rotation or forces portrait. Then complete onboarding, navigate to the home screen, and rotate again to see if the lock persists.
- Automated script – Using UiAutomator, call
setOrientationLeft()on the device object, then checkgetOrientation()after a short delay. Assert that the orientation matches the requested value if the screen is not supposed to be locked. - Persona‑driven autonomous exploration – A “power user” persona will frequently rotate the device while filling a long sign‑up form. The agent logs any instances where the input fields become obscured or clipped due to an unwanted orientation lock.
How to fix and prevent it
- Apply orientation locks only to specific activities that truly require them (e.g., a video tutorial) and declare them in the manifest with
android:screenOrientation="portrait"for those activities only. - Use
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)inonResume()of activities that should follow the device’s orientation after onboarding completes. - Test orientation changes with the Android CTS (Compatibility Test Suite)
android.view.Surface.ROTATIONscenarios to ensure the app responds correctly to 0°, 90°, 180°, and 270° rotations. - Include a visual regression check that screenshots the UI in both orientations and asserts that no critical UI elements are clipped.
Common Onboarding Flow Bugs and How to Catch Them: Accessibility Label Omissions
Why it happens
Developers sometimes rely on visual cues alone, forgetting to add contentDescription for icons or labelFor for input fields. When accessibility services (TalkBack, VoiceOver) encounter an unlabeled element, they announce generic text like “button” or “edit text,” making it impossible for users with visual impairments to understand the purpose of the control.
How it looks to users
A novice user relying on TalkBack swipes through the sign‑up screen. They hear “button, button, edit text” without knowing which button submits the form and which toggles the terms checkbox. Consequently, they may activate the wrong action or become stuck.
How to reproduce and detect it
- Manual – Enable TalkBack, navigate to the onboarding screen, and swipe left/right. Listen for vague announcements and note any elements that lack meaningful descriptions.
- Automated script – With XCTest (iOS) or Espresso (Android), use
onView(withContentDescription(containsString("Submit")))to assert that critical buttons have descriptive content. Add a test that counts the number of views missing acontentDescriptionorlabelForand fails if the count exceeds zero. - Persona‑driven autonomous exploration – An “elderly” persona will attempt to complete the form using only spoken feedback. The agent records whether each action taken matches the intended action (e.g., pressing submit when the user thinks they pressed cancel) and flags mismatches as accessibility defects.
How to fix and prevent it
- Provide a meaningful
contentDescriptionfor every icon button that describes its action (e.g., “Show password”). - For input fields, use the
android:hintattribute and additionally setlabelForon the associated label view so that TalkBack reads the hint when the field gains focus. - Run automated accessibility scans (e.g.,
axe-corefor web,Accessibility Test Frameworkfor Android) as part of your CI pipeline and treat any violations as build failures. - Include a manual accessibility checklist in your QA sign‑off: verify that all interactive elements have a spoken label that matches their visual purpose.
Common Onboarding Flow Bugs and How to Catch Them: Network Timeout Mis‑Handling
Why it happens
Onboarding often makes several sequential network calls (e.g., fetch config, send sign‑up request, retrieve user profile). Bugs appear when the app uses a fixed short timeout (e.g., 2 seconds) for all requests, causing legitimate slower responses (especially on 2G networks or when the backend is under load) to be treated as failures, leading to retry loops or abrupt error screens.
How it looks to users
The user enters their details and taps “Sign up.” After a few seconds, a toast appears: “Request timed out. Please try again.” They retry, only to get the same message repeatedly, eventually giving up.
How to reproduce and detect it
- Manual – Use a network throttling tool (e.g., Chrome DevTools network throttling or
adb shell netcfgto simulate a slow connection). Submit the sign‑up form and observe whether the app shows a specific “slow network” message or simply a generic timeout. - Automated script – With MockWebServer, enqueue a response that delays 5 seconds before returning a 200. Set the client’s timeout to 3 seconds and assert that the app treats the response as a failure. Then increase the timeout to 8 seconds and assert that the request succeeds.
- Persona‑driven autonomous exploration – A “curious” persona will deliberately enable airplane mode for a brief interval during a request, then restore connectivity. The agent checks whether the app gracefully handles the temporary loss and retries with back‑off rather than showing an immediate error.
How to fix and prevent it
- Use configurable, operation‑specific timeouts (e.g., 10 seconds for auth, 30 seconds for config download) based on empirical latency measurements.
- Implement exponential back‑off with jitter for retries, and surface a distinct “slow connection” banner after the first failure, offering the user the option to wait or try again on a different network.
- Cancel pending requests when the user navigates away from the onboarding screen to avoid zombie calls that could interfere with later navigation.
- Add unit tests for the networking layer that simulate latency, timeouts, and partial responses, asserting that the UI shows the appropriate state (loading, error, retry).
Common Onboarding Flow Bugs and How to Catch Them: Inconsistent State After Interruptions
Why it happens
Users may receive a phone call, switch to another app, or lock their device while in the middle of onboarding. Bugs arise when the app does not persist intermediate UI state (e.g., partially filled form, selected options) or when it fails to restore the navigation stack, causing the user to restart from scratch or to land on a confusing screen.
How it looks to users
After filling out half of the registration form, the user receives a call and returns to the app. They find that the form is cleared, forcing them to re‑enter all data, or they see a blank screen with only the app logo, leaving them uncertain whether they need to start over.
How to reproduce and detect it
- Manual – Begin the onboarding flow, fill several fields, then press the home button or lock the screen. Wait a few seconds, then restore the app. Verify whether the previously entered data persists and whether the user is taken back to the exact step they left.
- Automated script – Using Espresso, invoke
pressHome()mid‑flow, then launch the activity viastartActivity(Intent)with a flagFLAG_ACTIVITY_REORDER_TO_FRONT. Assert that theEditTextfields contain the values set before the home press. - Persona‑driven autonomous exploration – An “impatient” persona will background the app after each field entry, then quickly restore it. The agent records whether any field loses its value and whether any progress indicators (e.g., stepper) reset incorrectly.
How to fix and prevent it
- Persist form data to a lightweight store (e.g.,
SharedPreferencesorRoom) after each field change, keyed by a unique onboarding session ID. - On
onCreate()oronNewIntent(), read the persisted state and repopulate the UI; if the session is expired or the user has completed onboarding, redirect to the home screen. - Clear the persisted data only after a successful completion or after an explicit logout/cancel action.
- Write an instrumentation test that simulates
Activity.onPause()→Activity.onResume()cycles and asserts data integrity.
Common Onboarding Flow Bugs and How to Catch Them: Duplicate Submission Race
Why it happens
When a user taps the submit button multiple times quickly (either due to lag or impatience), the app may fire off multiple identical network requests. If the backend is not idempotent, this can create duplicate accounts, double‑charge a payment, or trigger multiple verification emails, confusing both the user and the system.
How it looks to users
The user taps “Sign up” twice in quick succession. They receive two welcome emails, see two entries in the user list, and may be charged twice if a payment is involved. The UI may also show two successive success toasts, making it unclear whether something went wrong.
How to reproduce and detect it
- Manual – Enable “Show taps” in developer options, then rapidly tap the submit button five times. Monitor the network traffic (via
adb logcator a proxy like Charles) to count how many identical requests are sent. - Automated script – With Espresso, perform a
repeat(5) { onView(withId(R.id.btn_submit)).perform(click()) }loop and use IdlingResource to wait for network idle. Assert that the API endpoint receives exactly one call (using a mock server call counter). - Persona‑driven autonomous exploration – A “frustrated” persona will deliberately double‑tap after perceiving a lag. The agent checks whether the UI disables the submit button after the first tap and whether any duplicate requests are logged server‑side.
How to fix and prevent it
- Disable the submit button immediately after the first click and re‑enable it only after the request completes (success or error).
- Use a request‑identifier (e.g., UUID) that the server uses to detect and discard duplicates.
- Show a single, unambiguous progress indicator (spinner + “Creating account…”) that remains visible until the request finishes.
- Add a unit test for the view model that verifies that a second click while a request is in flight is ignored.
Common Onboarding Flow Bugs and How to Catch Them: Mis‑ordered Permission Requests
Why it happens
Some apps request multiple permissions at once (camera, microphone, location) in a single dialog or in rapid succession. When the system groups these requests, users may deny one permission while granting another, leading to a partially‑ e.g., work but missing audio‑ The user may not‑clearly‑explained feature failure later (e.g., video chat works but background location tracking does not).
How it looks to users
After granting camera and microphone, the user attempts to start a video call. The call connects but the video feed is black because the location permission (required for geotagging) was denied earlier, and the app does not indicate why the video is disabled.
How to reproduce and detect it
- Manual – Go to Settings → Apps → YourApp → Permissions and deny location while keeping camera and microphone granted. Launch the video call feature and observe whether the app provides a clear explanation for the missing video or simply shows a frozen frame.
- Automated script – Using UiAutomator, revoke location permission via
adb shell pm revoke, launch the call activity, and assert that a toast or dialog appears stating “Location permission is needed to enable geotagging.”android.permission.ACCESS_FINE_LOCATION
3
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free