Applitools Eyes Timeout Error in Playwright Tests: Fix
Find which timeout expired before changing settings. Then wait for the right page state or adjust the specific Playwright or Eyes timeout.
A timeout near eyes.check() does not automatically mean Applitools Eyes’ MatchTimeout expired. Playwright Test has separate test, assertion, action, navigation, fixture, and hook timeouts; Eyes MatchTimeout governs visual stabilization and comparison. Read the complete error and stack trace, identify the operation that was waiting, then change that layer’s wait or timeout.
If the checkpoint is being captured before the application is ready, wait for a meaningful UI condition—such as a loading spinner becoming hidden or detached—before calling eyes.check(). Increase a timeout only when the relevant operation is correct but needs more time.
1. Identify which timeout expired
Start with the exact error text, call log, stack trace, and the last operation before failure. “Timeout of 30000ms exceeded” commonly identifies the Playwright Test budget; a locator call log points toward an assertion or action; a failure during visual matching may involve Eyes synchronization. The line mentioning Eyes alone is not enough to distinguish them.
| Failure surface | What it means | First place to inspect |
|---|---|---|
Timeout of 30000ms exceeded at the test level |
The test body, fixture setup, or beforeEach exceeded its test budget. |
Playwright test timeout, fixture setup, and hook duration. |
| Assertion call log waits for a locator or text | An auto-retrying assertion did not pass within its own budget. | expect.timeout or the assertion’s timeout option. |
| Click, fill, or another locator action times out | The action could not proceed within its action budget, often because the target was not actionable. | Locator state, action timeout, overlays, and the locator itself. |
page.goto() or navigation times out |
The navigation did not meet its completion condition within the navigation budget. | Navigation timeout, chosen wait condition, and network/page behavior. |
| Failure during fixture setup, hook, or teardown | A fixture or hook scope may have its own timing constraints or may consume the test budget. | Playwright report, fixture and hook timing, and teardown output. |
Failure at eyes.check() |
The app may still be loading, checkpoint capture may be waiting, or Eyes visual matching may be slow. | Wait for app readiness, then inspect the Eyes SDK version and MatchTimeout API. |
Playwright documents a 30,000 ms default per-test timeout and a separate 5,000 ms default for auto-retrying assertions. Test time includes the test function, fixture setup, and beforeEach; action and navigation timeouts are separately configurable. These are defaults, not a diagnosis of your failure. See the Playwright timeout guide.
2. Wait for the application state before the Eyes checkpoint
The strongest fix for a screenshot captured during loading is usually to wait for the condition that means the relevant content is ready. Prefer an application signal over a guessed delay. Playwright’s locator and page waits can express those conditions directly.
import { test, expect } from '@playwright/test';
import { Eyes } from '@applitools/eyes-playwright';
test('dashboard visual check', async ({ page }) => {
const eyes = new Eyes();
await eyes.open(page, 'Example app', 'Dashboard');
try {
await page.goto('https://example.com/dashboard');
await page.locator('[data-testid="dashboard-ready"]').waitFor({ state: 'visible' });
await page.locator('.loading-spinner').waitFor({ state: 'detached' });
await eyes.check('Dashboard');
} finally {
await eyes.close();
}
});
This is an illustrative standard-SDK shape; use the initialization and lifecycle required by your installed Eyes SDK. If your app has no readiness marker, use a stable observable condition such as a loading indicator disappearing, a known heading appearing, or required content reaching its expected state. Avoid waiting for “network idle” as a proxy for correctness when the app maintains long-lived connections or background requests.
Applitools documents a waitBeforeCapture callback for Playwright synchronization. A callback can wait for a spinner or other application condition immediately before capture. Check the API shape for your installed SDK because package generations differ. The Applitools guidance favors framework-native waits over fixed sleeps: Handling Animations and Loading Artifacts in Visual Testing.
// Illustrative option shape; confirm the exact signature for your Eyes SDK version.
await eyes.check({
name: 'Dashboard',
waitBeforeCapture: async () => {
await page.locator('.loading-spinner').waitFor({ state: 'hidden' });
}
});
Do not copy that option signature blindly across SDK versions. If the installed integration exposes a different check API, retain the same principle: wait for the app’s ready state before the visual checkpoint.
3. Adjust the timeout that owns the failure
Once the failure is classified, make the narrowest useful change. Playwright’s timeout settings are not interchangeable: extending the test budget will not fix an assertion that is waiting on the wrong state, and increasing an Eyes visual-match setting does not extend a page.goto() timeout.
Playwright test timeout
Use a scoped test timeout when one test legitimately needs longer for its body, setup, or beforeEach. The documented default is 30 seconds.
import { test } from '@playwright/test';
test('slow integration visual check', async ({ page }) => {
// Test steps...
}).timeout(60_000);
Alternatively, set a project or suite default in playwright.config.ts when the same budget is appropriate for that scope:
import { defineConfig } from '@playwright/test';
export default defineConfig({
timeout: 60_000
});
Use a local increase to establish whether a genuinely slow test has adequate budget. Avoid raising every test’s limit to hide a readiness race; longer budgets can make failures take longer to report.
Assertion timeout
Auto-retrying assertions have their own timeout, documented as 5 seconds by default. Set it globally or on the one assertion that reasonably needs more time.
import { defineConfig } from '@playwright/test';
export default defineConfig({
expect: { timeout: 10_000 }
});
await expect(page.getByRole('heading', { name: 'Dashboard' }))
.toBeVisible({ timeout: 10_000 });
Action and navigation timeouts
When a click or navigation itself is the pending operation, inspect its own timeout and completion condition. Playwright supports action and navigation timeout configuration; use the matching option or per-call timeout supported by your installed Playwright version. A navigation that never reaches load because of persistent activity may be better expressed with an earlier lifecycle condition plus a separate readiness wait.
await page.goto('https://example.com/dashboard', {
waitUntil: 'domcontentloaded',
timeout: 30_000
});
await page.locator('[data-testid="dashboard-ready"]').waitFor({ state: 'visible' });
Use a lifecycle event that matches the site, then explicitly wait for the content needed by the screenshot. Consult the Playwright documentation for the setting names and scope in your version.
Eyes MatchTimeout
MatchTimeout is an Eyes visual synchronization/comparison setting: it controls how long Eyes waits for an image to stabilize toward a baseline match. Applitools Support documents a two-second default in its Match Timeout article, which dates to 2021. The article notes that syntax and units depend on SDK. Confirm the setting and units for the exact installed package before changing it. MatchTimeout is not the Playwright test timeout.
If the app is still changing, first fix the capture readiness condition. Increase MatchTimeout only when the page is ready and the visual stabilization or comparison genuinely needs a longer window. Applitools describes retry behavior and per-step overrides in its Match Timeout support article; treat its example as version-specific guidance.
4. Use the integration that matches your installed SDK
Applitools’ current integration documentation includes fixture-based Playwright setup, with an enhanced test import from @applitools/eyes-playwright/fixture and an eyes fixture. A newer integration can manage opening and closing Eyes and collect results; existing projects may use a standard or earlier SDK instead. Check package.json, lockfile, and the import path in the failing test before applying lifecycle or configuration examples.
// Fixture-based integration shape; verify the API against your package version.
import { test, expect } from '@applitools/eyes-playwright/fixture';
test('dashboard visual check', async ({ page, eyes }) => {
await page.goto('https://example.com/dashboard');
await page.locator('[data-testid="dashboard-ready"]').waitFor({ state: 'visible' });
await eyes.check('Dashboard');
});
Applitools’ Playwright integration documentation describes the setup, while its 2026 integration article covers the updated SDK approach and gradual migration: Updated Applitools Playwright SDK. Confirm package compatibility and current signatures against the installed version rather than combining fixture and manual lifecycle examples.
5. Diagnose environmental delays and flaky checkpoints
After confirming the timeout owner and application wait, look for repeatable environmental causes. Applitools identifies unstable networks, delayed application servers, third-party components, and CPU or memory bottlenecks as possible sources of synchronization difficulty.
- Record the failing operation and full stack trace; preserve the Playwright report and trace if enabled.
- Compare local and CI behavior, including browser version, workers, machine load, and network-dependent dependencies.
- Check whether ads, analytics, chat, or other third-party widgets keep the page changing after the application content is ready.
- Make the checkpoint wait for the portion of the page under test rather than for unrelated activity to stop.
- Re-run with the same inputs and inspect whether the same operation is slow, or whether a race moves between steps.
Applitools’ flaky-test guidance explains that fixed sleeps are rigid: they waste time when the page is fast and can remain too short when the page is slow. Prefer a condition-based wait. If no reliable condition exists, a bounded delay can be a temporary fallback, but it should not become a substitute for finding the readiness signal. See Applitools’ flaky visual test guidance.
6. Quick troubleshooting checklist
| Symptom | Likely cause | Fix to try |
|---|---|---|
| “Timeout of 30000ms exceeded” before the checkpoint | Test body, fixture setup, or beforeEach used the test budget. |
Find the slow operation; wait on the needed app state and scope a higher test timeout only if the work legitimately requires it. |
An expect(...) call times out |
Expected state did not appear within the independent assertion budget. | Check selector and app state; increase that assertion’s timeout only for legitimate latency. |
| Click times out even though the selector matches | Element may be covered, moving, disabled, or not actionable. | Inspect the call log and overlays; wait for the real actionable state instead of extending Eyes MatchTimeout. |
page.goto() times out on a page that appears loaded |
The selected navigation lifecycle condition may not occur, or the page/network is slow. | Choose an appropriate navigation wait condition and separately wait for app readiness. |
eyes.check() fails while a spinner is visible |
The checkpoint ran before the page reached the required state. | Wait for the spinner to become hidden or detached, or use the SDK’s supported pre-capture callback. |
| Eyes visual comparison is slow after the UI is stable | Visual matching/stabilization may need more time, or environment/SDK behavior differs. | Confirm the Eyes SDK and MatchTimeout units; adjust the relevant per-step or supported setting. |
| Timeout is inconsistent in CI | Network, server, third-party, or resource bottleneck creates variable readiness. | Use traces and operation-level timings to locate the variability; avoid global timeout inflation as the first fix. |
| Example configuration option is rejected | SDK or Playwright API differs from the version assumed by the example. | Check lockfile, installed package docs, and whether the project uses the fixture or standard integration. |
7. Performance, reliability, and timeout trade-offs
A readiness wait improves reliability when it names the actual condition needed by the checkpoint. A fixed sleep adds its full delay even when the page is already ready, while a larger timeout only increases the maximum time a failing operation can consume. On the other hand, a timeout that is too short can fail under normal CI variation. Use traces and observed operation timing to choose a bounded value appropriate to the test environment; the reviewed sources provide configuration defaults, not a universal optimal timeout or performance benchmark.
Keep timeout changes scoped. A one-test increase is easier to evaluate than a global setting, and separate assertion, navigation, test, and Eyes settings make failures easier to interpret. Revisit temporary increases after stabilizing the app condition or removing a slow dependency.
8. Or skip the browser setup
If your task is to capture a website image rather than run an Applitools visual assertion inside Playwright, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. Its screenshot capture accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status in headers. An MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents.
For a direct screenshot call, see the ScreenshotNeo API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo is an alternative to try first when you need a website capture without managing browser setup: cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed; an MCP server lets AI agents take screenshots; and 1,000 screenshots a month are free with no card, with paid plans starting at $5 for 3,000. Create a free account and get 1,000 screenshots a month with no card.
FAQ
Is MatchTimeout the same as a Playwright timeout?
No. Playwright timeouts govern test-runner work and browser operations such as assertions, actions, or navigation. Eyes MatchTimeout is for visual stabilization and matching. Identify the failing operation before changing either.
Why does eyes.check() time out when the page looks loaded?
The screenshot may be captured while a relevant region is still changing, or the visual comparison may be the slow step. Wait for the application condition needed by the checkpoint and inspect the exact Eyes error and SDK version.
Should I increase every Playwright timeout?
Usually start with the narrowest scope that owns the failure. A larger global limit can hide a race and make unrelated failures slower without correcting an unmet UI condition.
Can I use waitForTimeout() to fix flaky visual tests?
It can provide a bounded fallback when no deterministic condition exists, but it is rigid. A readiness locator or documented pre-capture wait is generally more reliable.


