Skip to content

Browser-based updates getting stuck on the “Confirm your admin email” screen — why Playwright stalls in wp-admin

On hosting environments without SSH access, the fallback is browser automation: Playwright logs into wp-admin and drives the plugin update screen directly. That works fine for months — until one day the script stops dead before it ever reaches the update screen.

Note: Playwright is a browser automation tool. It reproduces clicks a human would make, but as code.

What the “confirm your admin email” screen is

Since WordPress 5.3, wp-admin shows a periodic prompt — roughly every six months — asking the site owner to confirm they still have access to the registered admin email address. It’s a core WordPress feature, not a plugin.

Is this still your address?
[ Yes, this is my address ]  [ I'll wait ]

A human clicking through wp-admin would just click “I’ll wait” and move on. But a Playwright script written for a fixed sequence — log in, then navigate straight to the plugin update screen — has no branch for this extra screen. When it appears, the script stalls right there.

What actually happens

The login itself succeeds. The problem is the page it lands on: instead of wp-admin/index.php, the URL is wp-admin/options-general.php?adminhash=.... Whatever goto() call was supposed to take the script to the update screen next either gets redirected by this confirmation page, or the selectors it’s waiting for never appear, and the script times out.

# Check for the confirmation screen right after login
if "adminhash=" in page.url:
    page.click("text=I'll wait")

Checking whether the post-login URL contains adminhash= is enough to detect that this screen has appeared.

Why the six-month cycle makes this hard to catch

The screen doesn’t show up every time. WordPress core decides to show it only after enough time has passed since the last confirmation. That means automation that has been running cleanly for months can suddenly stop — and because it happens so rarely, tracing the cause back to this specific screen takes longer than it should.

The fix

Detect the “I’ll wait” button and click it automatically as a standing step right after login, regardless of whether the screen actually appears. That way the same code path works whether the confirmation screen shows up or not.

def ensure_past_email_check(page):
    if "adminhash=" in page.url:
        page.click("text=I'll wait")
        page.wait_for_load_state("networkidle")

Calling this function immediately after every login means the twice-yearly surprise stops being a surprise.

Summary

Aspect Detail
When it triggers WordPress core decides enough time has passed since the last confirmation
Symptom Post-login navigation lands on the confirmation screen, later steps time out
Detection Check whether the post-login URL contains adminhash=
Fix Auto-click as a standing step right after every login

Like Playwright strict-mode violations colliding with wp-admin’s repeated selectors, this comes down to the same root issue: wp-admin doesn’t always move in a straight line, and browser automation has to account for the screens it doesn’t expect. As long as SSH isn’t available and browser-driven maintenance is the fallback, detecting and stepping past these unplanned screens isn’t optional. The same distrust of wp-admin also shows up in validating a version number scraped from the page before trusting it.