Playwright offers multiple timeout handling methods to control how long operations wait before failing. Understanding these approaches is crucial for building reliable web automation and scraping applications.
Default Timeout Configuration
Global Default Timeout
Set a default timeout for all operations in your test or script:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
// Set global default timeout (30 seconds)
page.setDefaultTimeout(30000);
await page.goto('https://example.com');
await page.click('button'); // Uses 30s timeout
await browser.close();
})();
Context-Level Default Timeout
Apply timeout settings to all pages within a browser context:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
// Set timeout for all pages in this context
context.setDefaultTimeout(15000);
const page = await context.newPage();
await page.goto('https://example.com'); // Uses 15s timeout
await browser.close();
})();
Per-Action Timeout Configuration
Navigation Timeouts
Control how long to wait for page navigation:
// Set timeout for specific navigation
await page.goto('https://slow-website.com', { timeout: 60000 });
// Wait for navigation with custom timeout
await Promise.all([
page.waitForNavigation({ timeout: 10000 }),
page.click('a[href="/next-page"]')
]);
Element Interaction Timeouts
Set timeouts for individual element operations:
// Click with custom timeout
await page.click('button#submit', { timeout: 5000 });
// Fill input with timeout
await page.fill('input[name="email"]', 'user@example.com', { timeout: 3000 });
// Wait for element with timeout
await page.waitForSelector('.loading-spinner', { timeout: 10000 });
Wait Methods and Timeouts
waitForSelector with Timeout
Wait for elements to appear or disappear:
// Wait for element to appear
await page.waitForSelector('.content', { timeout: 15000 });
// Wait for element to be hidden
await page.waitForSelector('.loading', {
state: 'hidden',
timeout: 20000
});
// Wait for element to be visible and enabled
await page.waitForSelector('button#submit', {
state: 'visible',
timeout: 5000
});
waitForLoadState with Timeout
Wait for specific page load states:
// Wait for page to be fully loaded
await page.waitForLoadState('networkidle', { timeout: 30000 });
// Wait for DOM to be ready
await page.waitForLoadState('domcontentloaded', { timeout: 10000 });
Fixed Delays (Use Sparingly)
Sometimes you need to wait for a specific duration:
// Wait for 2 seconds (avoid in production code)
await page.waitForTimeout(2000);
// Better: Wait for specific condition instead
await page.waitForFunction(() => {
return document.querySelector('.animation').classList.contains('completed');
}, { timeout: 10000 });
Advanced Timeout Patterns
Conditional Waiting with Timeout
Handle dynamic content that may or may not appear:
try {
// Try to wait for modal, but don't fail if it doesn't appear
await page.waitForSelector('.modal', { timeout: 3000, state: 'visible' });
await page.click('.modal button.close');
} catch (error) {
console.log('Modal did not appear, continuing...');
}
Race Conditions with Multiple Timeouts
Wait for the first of multiple conditions:
const result = await Promise.race([
page.waitForSelector('.success-message', { timeout: 10000 }),
page.waitForSelector('.error-message', { timeout: 10000 })
]);
if (await result.textContent() === 'Success!') {
console.log('Operation succeeded');
} else {
console.log('Operation failed');
}
Custom Wait Functions
Create reusable timeout patterns:
async function waitForElementWithRetry(page, selector, maxAttempts = 3) {
for (let i = 0; i < maxAttempts; i++) {
try {
await page.waitForSelector(selector, { timeout: 5000 });
return true;
} catch (error) {
if (i === maxAttempts - 1) throw error;
await page.waitForTimeout(1000); // Wait 1s before retry
}
}
}
// Usage
await waitForElementWithRetry(page, '.dynamic-content');
Error Handling and Timeout Exceptions
Handling Timeout Errors
Gracefully handle timeout failures:
try {
await page.waitForSelector('.slow-loading-element', { timeout: 5000 });
} catch (error) {
if (error.name === 'TimeoutError') {
console.log('Element did not load within 5 seconds');
// Implement fallback behavior
} else {
throw error; // Re-throw non-timeout errors
}
}
Timeout Best Practices
Configure timeouts based on your specific needs:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
// Conservative global timeout
page.setDefaultTimeout(30000);
// Fast operations can use shorter timeouts
await page.fill('input', 'text', { timeout: 2000 });
// Slow operations may need longer timeouts
await page.goto('https://heavy-site.com', { timeout: 60000 });
// API calls or file uploads
await page.waitForResponse('**/api/upload', { timeout: 120000 });
await browser.close();
})();
Timeout Configuration Summary
| Method | Scope | Default | Use Case |
|--------|-------|---------|----------|
| page.setDefaultTimeout()
| Page-level | 30000ms | All page operations |
| context.setDefaultTimeout()
| Context-level | 30000ms | All pages in context |
| { timeout: N }
option | Single action | Varies | Specific operations |
| waitForTimeout()
| Fixed delay | N/A | Explicit waits |
All timeout values are in milliseconds (1000ms = 1 second). Choose appropriate timeouts based on your application's performance characteristics and network conditions.