After a phone confirmation, the PC login page is still spinning: should I check the polling interval or the QR code status first?
Conclusion first: when the PC login page is stuck at waiting, it is usually not that the polling interval is too long, but that the QR code status was not written, or that the channel for fetching status is broken in the customer network. QR code login breaks down into just two things: a ticket with four states (pending scan, scanned pending confirmation, confirmed, and used or expired), plus a channel that sends state changes back to the browser. Based on common 2026 delivery experience, when a single endpoint is waiting and second-level latency is acceptable, short polling at 1.5–3 seconds with backoff plus a status version number can keep “phone confirmation to web page redirect” within the 1–3 second experience range. Only when multiple endpoints wait at the same time, or sub-second feedback is required, is it worth switching to long polling, SSE, or WebSocket. The troubleshooting order is therefore fixed: first check whether the server-side status is correct, then whether the channel works, and only then discuss how to adjust the interval.
1. When stuck on the waiting page, first distinguish whether the status was not written or the channel is broken
The two kinds of stalls look exactly the same, but they are handled completely differently. In delivery, the former is more common: the confirmation API is rejected by a conditional update, ticket issuance fails, or the phone never sends the confirmation request at all. Channel problems tend to concentrate in a few fixed environments—reverse proxies cutting idle connections, upgrade requests being blocked by intermediary devices, or cross-origin requests not carrying credentials.
A crude but effective way to tell them apart: look up the server-side record for this ticket directly. If it is already “confirmed”, the status was written, and the problem is in the channel or the front-end ticket exchange step; if it is still “scanned pending confirmation”, the confirmation request did not take effect; if it shows “used”, it is most likely that the same person opened multiple pages, or the QR code was screenshotted and forwarded and someone else used it first.
- Confirmed but the page does not move: check whether polling is still being sent, whether the long connection has already been downgraded, and whether the login-state exchange is blocked by cross-origin credentials.
- Still pending scan: check the conditional update conditions and return code of the confirmation API; do not just look at whether the front end showed a success toast.
- Used: check multiple tabs or QR code racing; adjusting the interval is meaningless at this point.
2. If the four-state state machine is not fixed, no amount of channel tuning will help
The writer for each of the four states must be clearly defined, and only one entry point is allowed to push a given state: when generating the code, write “pending scan”; only the phone scan API can push it to “scanned pending confirmation”; only the phone confirmation API can push it to “confirmed” after verifying that the current state is still “scanned”; only when the browser exchanges a one-time ticket for a login state can it be pushed to “used”. Once the writers are messy, no interval tuning later will help.
- Pending scan: the ticket is persisted with an expiration time, commonly a 60–120 second experience range; it becomes invalid once expired, and the front end must be able to switch to a new code with one click.
- Scanned pending confirmation: the update is conditional (the current state is still pending scan), to avoid concurrent overwrites and to prevent an old request from pushing a new state back.
- Confirmed: issue a one-time login ticket bound to the ticket, allowed to be consumed only once.
- Used or expired: set to used immediately after consumption; reject repeated consumption outright, blocking screenshot forwarding and replay.
Add an auto-incrementing version number to the state, return it together with the status-fetch API, and have the front end redirect only when the version changes; this avoids quite a few strange duplicate-redirect issues.
3. Four status-fetch channels: the difference is not speed, but cost and environment
Many designs win on latency in the meeting room, but after launch they discover that the customer data center's reverse proxy cuts idle connections after thirty seconds, SSE is buffered and not delivered, or WebSocket upgrades are blocked by intermediary devices—and in the end they fall back to polling. A fixed decision order is recommended: first look at how many waiting endpoints there are (one tab or multiple endpoints), then whether second-level latency is acceptable or sub-second is required, and finally whether the deployment environment can guarantee stable long connections. If any one of these three steps does not hold, there is no need to force a long connection just for technical preference.
- Short polling: interval of 1.5–3 seconds; front-end plus API changes commonly take 0.5–1 person-day; best network traversal and easiest troubleshooting; the cost is many empty requests, and as waiting endpoints increase, the QPS on the status-fetch API grows linearly.
- Long polling: the server holds for 20–30 seconds before returning; latency is one level lower, and changes commonly take 1–2 person-days; you must check idle timeouts layer by layer across gateways, proxies, and load balancers, otherwise 504s are likely.
- SSE: one-way push is sufficient and still uses ordinary HTTP; changes commonly take 1.5–3 person-days; confirm that the proxy has not enabled response buffering.
- WebSocket: bidirectional and low latency; implementing heartbeats, reconnection, and disconnect compensation fully commonly takes 3–5 person-days; troubleshooting cost is also one level higher.
These numbers are typical ranges, used only for order-of-magnitude trade-offs; the specifics also depend on which channel the team knows better and whether the existing framework has ready-made wrappers.
4. Delivery reality: what gets stuck is often not the interval, but proxies and multiple tabs
A very typical stall: there is a proxy at the customer intranet egress, and it drops the connection after about thirty seconds of idleness. The front end built the waiting page on WebSocket, and tests in the office area were always normal, but as soon as it was demonstrated in the meeting room, it stopped at “waiting for phone confirmation”. The constraints were that the proxy could not be changed and only one week remained before the demo. The approach was to keep WebSocket but add heartbeats, and automatically switch back to short polling a few seconds after disconnection; both channels share the same state machine. The cost was an extra set of switching logic on the front end and two extra days of integration testing; the benefit was that several later customer data centers reused this fallback path, and after switching, confirmation-to-redirect still returned to the 1–3 second experience range.
Another type is more hidden: the user opens three tabs waiting for the same QR code, whichever gets the ticket first pushes the state to “used”, and the other two pages wait until expiration; what the user sees is “I confirmed but nothing happened”. A common approach is to coordinate a single channel within the same browser using storage events or BroadcastChannel, letting only one page fetch status while the others subscribe to the result; the cost is handling re-election after a page is frozen or a tab is closed.
- After confirmation, the login state is written to a cookie, but the cross-origin request does not carry credentials, so even if the ticket is exchanged, login still fails.
- The QR code is not bound to a random value from the initiating endpoint, so after it is screenshotted and forwarded, someone else can also confirm it.
- Polling has no backoff, and after the code expires the front end still calls the API at a fixed interval.
5. Applicable boundaries and acceptance criteria
Suitable for: internal admin back offices, enterprise systems, low login frequency (a few to a few dozen times per person per day), waiting endpoints that are basically a single browser, and deployment environments with proxy devices that cannot be changed. In these scenarios, the cost and benefit of short polling match best; making the state machine, expiration, and fallback solid first is more worthwhile than chasing low latency.
Cases where it is unnecessary: daily login volume is very small and users are already on the same device, so direct username/password or passwordless login via WeCom or DingTalk is simpler; if there is already a stable long-connection system (such as an in-site message channel), reusing it is more cost-effective than building a new QR code channel yourself.
For acceptance, tick items off according to common 2026 project delivery practice: for confirmation-to-redirect, short polling commonly takes 1–3 seconds and long connections are generally within 1 second; if it clearly exceeds this, check whether it has silently fallen back; exchanging the same ticket repeatedly must fail and return an identifiable error code; expiration must have a clear prompt and support one-click code replacement; keep logs for state transitions, channel type, and fallback count; the ticket must be one-time, bound between the initiating endpoint and the confirming endpoint, and when confirming, the phone must show which account is currently logging in.
Common questions
The phone confirmed, but the web page is still spinning—which side should I check first?
First check what state this code has on the server. If it is already “confirmed”, check the channel and cross-origin credentials; if it is still “scanned pending confirmation”, the confirmation request most likely did not take effect or was rejected by a conditional update.
If I change the polling interval from 3 seconds to 1 second, will the experience improve noticeably?
In most scenarios, no. Cutting the interval in half doubles empty requests, and with more waiting endpoints it drives up QPS on the status-fetch API; with 1.5–3 seconds plus an immediate redirect after confirmation, the perceived difference is very small.
What is a suitable expiration time for a login QR code?
A common 60–120 second experience range. Too short and users do not have time to scan it; too long and the risk window for the old code becomes larger. The key is that after expiration the front end can switch to a new code with one click, and the server truly invalidates it.
We already use WebSocket—should we still keep polling?
It is recommended to keep a fallback path. Proxies cutting connections, upgrades being blocked, and weak-network disconnections can all make the long connection fail; automatically switching to short polling after disconnection is more stable than making users refresh the page and start over.
After confirmation, the login state cannot be written—what are the common causes?
Most often it comes down to missing cross-origin credentials, a cookie SameSite mismatch with the domain scope, or the ticket being stored in the wrong place by the front end; look at retrieval and persistence logs separately.
If your QR code login is stuck at “confirmed but the page does not move”, check the writers one by one according to the four-state state machine, then confirm that the channel really works in the customer network. In scenarios where polling can serve as a fallback, launch first and make expiration, code replacement, and fallback solid; when sub-second requirements or simultaneous multi-endpoint waiting actually appear, it is not too late to switch to long connections. When Xiyue Company handles this kind of login rework according to delivery practice, it usually also ensures connectivity first and discusses latency second.
-
Two Machines Are Running the Same Scheduled Job and Month-End Produces Two Reconciliation Statements—What Part Can a Distributed Lock Actually Block?
Date: Nov 2, 2026 Read: 4
-
Customer portal embeds our system in an iframe and users are bounced back to the login page after signing in: should we check cookies or the session first?
Date: Nov 1, 2026 Read: 10
-
Why do morning peak timeouts get worse after raising the connection pool limit from 20 to 50, and who is holding the connections?
Date: Oct 31, 2026 Read: 13
-
Can Snowflake ID worker IDs be manually configured when scaling from two to six servers and order numbers occasionally collide?
Date: Oct 29, 2026 Read: 19
-
Operations changed “Pending Shipment” to “Awaiting Shipment” and the admin buttons all disappeared at once—who should own status copy?
Date: Oct 28, 2026 Read: 23




