Why You Shouldn’t Use page.waitForTimeout() in Playwright
On This Page What page.waitForTimeout () DoesJune 19, 2026 · 11 min read · Tool Comparison
Ever had a Playwright exam that work perfectly once, then neglect the next run without any changes? I went through the same inconsistencies and worn-out hour debugging CI settings, browser versions, and network throttling before I plant the existent cause. I had scattered page.waitForTimeout () everywhere, hoping fixed delays would keep things stable. The problem is that hard waits do not wait for the covering to be ready. They slow test down and still separate in real device environment where execution varies. After switching to event-driven waits, my test go became faster, repeatable, and far more aligned with real user interactions. Why is page.waitForTimeout () not always ideal? page.waitForTimeout () feels convenient because it simply pauses the test for a rigid duration. However, rely on hard holdup introduces more issues than it solves. Hard wait often make flaky behavior because they are found on assumptions about speed. If the app loads slower than wait, the test fails. If it loads quicker, time is unnecessarily wasted. This also leads to longer execution times, especially when hold are scatter throughout the suite. Playwright already provides smarter waiting that respond to existent app weather. For example: These alternatives adapt to actual behaviour, which keep tests stable across different browsers, meshing speed, and gimmick performance. When Can page.waitForTimeout () Still Be Used? It is not all forbidden, but it should be treated as alast option, reserved for cases like: In this guide, I will explain why page.waitForTimeout () leads to fragile automation, the rare moments when it may still be useful, and the reliable option that improve Playwright test stability across any environment. page.waitForTimeout () is a mere postponement mapping in. It hesitate the examination for a set act of milliseconds and then preserve execution. It is an easy way to make sure the UI has enough time to update before interacting with it. The issue is that this delay has no awareness of what is happening in the browser. It does not await for element to render, API name to complete, or animations to finish. It just waits for a predefined continuance, whether the coating is ready or not. That simplicity go a problem as tests grow and environments turn less predictable. The Risks of Using Fixed Waits in Playwright Tests When I relied on fixed delays, my trial became unreliable without me discover at first. Hard waits lead to issues like: Read More: Read More: A fixed code assumes that every scheme the test run on behaves exactly like the machine it was write on. However, modern application render content through asynchronous processes: network shout, lazy-loaded components, client-side hydration, GPU-driven animations, and background tasks. These events complete at different fastness based on the surround. Hard waits ignore all of this. Here is how they miscarry in existent employment: Read More: Also Read: Read More: These timing mismatches cause: These timing failure remain invisible until the test suite scat someplace dense, busier, or basically different from your local machine. Different browsers, operating systems, hardware profiles, and network conditions introduce new timing behaviors that hard waits simply can not handle. Pro tip: Tools like SUSA can handle this autonomously — upload your app and get results without writing a single test script. This is where BrowserStack helps. It allows you to in parallel across a wide compass of real environments and ply detailed logs, video, and screenshots so timing issues are easy to detect and fix before they affect users. There are rare cases where a hard wait can be helpful, usually when there is no specific UI state or event that can be observed. I yet use page.waitForTimeout () sometimes, but only with clear intent. Read More: Read More: I supplant almost every hard waiting in my codebase with the postdate techniques. These coming make examination faster, more stable, and adaptive to real-world surround. There are a few patterns that consistently eradicate flakiness: One thing that storm me when I first move to Playwright was that I didn & # 8217; t need to write explicit waits for common UI activity. Playwright already includesauto-waitingas part of every interaction. When I click a button or fill an input, Playwright monitors the DOM and wait for the element to gain an actionable province before action the stride. That means Playwright mechanically checks whether the constituent: So rather of this: I simply write: Playwright waits under the hood until the button is truly ready & # 8211; whether that guide 200ms or 2 seconds. Read More: If I care about something becoming visible, attached to the DOM, or enable, I directly wait for that stipulation instead of await one second hoping it complete. This works especially well after actions that require fetching data or do establishment. Another example: wait for the & # 8220; Save & # 8221; button to turn enabled after field establishment completes. The trial no longer wish if the server responds in 10ms or 3 seconds. It wait only as long as postulate. Also Read: If a push triggers an API call, I wait for the network event rather of hoping the UI last in time. This is the most reliable way to validate async stream. await page.click (& # 8216; # buyNow & # 8217;); await expect (page.locator (& # 8216; .order-confirm & # 8217;)) .toBeVisible (); This gives me airtight synchronization between fetching data and checking what the UI perform next. are naturally retry-driven in Playwright. They continue trying until the status is true or a timeout occurs, so I use them as synchronization point. Instead of passive waiting, the test actively check the UI until state matches expectations. It is a best version of waiting because it knowswhyit is waiting. Sometimes new constituent seem only after transitions or route changes. I explicitly wait for the selector only when auto-waits are not involved. Still no fixed timing. It adapts to fast and slow device. There are edge cases where UI state, network events, and visual readiness must line up together. Instead of stacking multiple hard wait, I combine waiting in a structured way. Whether the environment is blazing fast on a MacBook or sluggish on a cheap Android device, the tryout adapts. Even when my local tests walk, clock behaves differently in production-like environments. Real devices have slower CPUs and different rendering pipelines. Browsers handle animations, script performance, and meshing schedule differently. That is where BrowserStack becomes essential. I run the like Playwright suite across: Here is an example of fulfil these examination on: I specifically watch for: When something does miscarry, I rely on: This helps me uncover timing issuesbeforecustomers feel them. Hard expect feel like a quick fix, but they inclose hidden instability into test suites. By replace page.waitForTimeout () with state-aware synchronization like auto-wait interactions, locater assertion, and network-aware waits, tests adjust to real application behavior. With features like examination insights dashboards, performance profiling for every session, network and geolocation simulation, and integrations with CI systems, BrowserStack shew exactly where tests slow down or break due to poor waiting strategies. That visibility do it easier to name which run still bank on fragile timing and to fix them permanently. Tool Comparisons: On This Page # Ask-and-Contributeabout this topic with our Discord community. Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed. Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.Why You Shouldn ’ t Use page.waitForTimeout () in Playwright
Overview
(and yet then, revisiting the app or tryout logic is recommended)What page.waitForTimeout () Does
How Difficult Waits Break on Real Environments and Device Conditions
When Using a Fixed Delay Might Be Acceptable and How To Use It Safely
Better Alternatives to Fixed Waits in Playwright
1. Relying on Built-In Auto-Waits for Interactions
await page.waitForTimeout (2000); look page.click (& # 8216; # submit-btn & # 8217;);
await page.getByRole (& # 8216; button & # 8217;, {name: & # 8216; Submit & # 8217;}) .click ();2. Waiting for UI State Instead of Time
await page.locator (& # 8216; # spinner & # 8217;) .waitFor ({state: & # 8216; detached & # 8217;}); await expect (page.locator (& # 8216; # results & # 8217;)) .toBeVisible ();await page.fill (& # 8216; # email & # 8217;, & # 8216; valid @ mail.com & # 8217;); await expect (page.locator (& # 8216; # save & # 8217;)) .toBeEnabled ();
await page.click (& # 8216; # save & # 8217;);3. Using Network Events When the UI Depends on Requests
const responsePromise = page.waitForResponse (res = & gt; res.url () .includes (& # 8216; /checkout & # 8217;) & amp; & amp; res.status () === 200
);
await responsePromise;4. Using Assertions as Smart Waits
await expect (page.locator (& # 8216; # profile & # 8217;)) .toContainText (& # 8216; John Doe & # 8217;);
5. Using waitForSelector () When Working With Dynamic Elements
await page.goto (& # 8216; /notifications & # 8217;); expect page.waitForSelector (& # 8216; .notification-item & # 8217;);
await expect (page.locator (& # 8216; .notification-item & # 8217;)) .toHaveCount (5);6. Combining Multiple Signals for Complex UIs
await Promise.all ([page.waitForSelector (& # 8216; .chart-loaded & # 8217;),
page.waitForResponse (res = & gt; res.url () .includes (& # 8216; /data & # 8217;) & amp; & amp; res.ok ())
]);
await look (page.locator (& # 8216; .chart & # 8217;)) .toBeVisible ();Validating Dynamic Wait Behavior on Real Devices and Browsers With BrowserStack
// playwright.config.tsimport {devices} from & # 8216; @ playwright/test & # 8217;;
exportation nonremittal {
projects: [
{
gens: & # 8216; Chrome on Pixel 7 & # 8217;,
use: {
browserName: & # 8216; chromium & # 8217;,
& # 8230; device [& # 8216; Pixel 7 & # 8217;],
browserstack: {
username: process.env.BSTACK_USERNAME,
accessKey: process.env.BSTACK_ACCESS_KEY,
},
},
},
{
name: & # 8216; Safari on iPhone 14 & # 8217;,
use: {
browserName: & # 8216; webkit & # 8217;,
& # 8230; devices [& # 8216; iPhone 14 & # 8217;],
browserstack: {
username: process.env.BSTACK_USERNAME,
accessKey: process.env.BSTACK_ACCESS_KEY,
},
},
},
],
};Conclusion
Useful Resources for Playwright
Related Guides
Automate This With SUSA
Test Your App Autonomously