TimeoutError: waiting for selector failed: timeout 30000ms exceeded
Learn how to fix the 'waiting for selector timeout' error when elements don't appear within the expected time
Ivan Muñoz
Apr 30, 2025
Crash

This error occurs when Puppeteer cannot find an element matching the specified selector within the default 30-second timeout period. Let’s explore the causes and solutions.
Common Causes
- Element doesn’t exist: The selector doesn’t match any element on the page
- Dynamic content: Element is added to the page after the timeout
- Incorrect selector: The CSS selector is wrong or not specific enough
- Page not fully loaded: Trying to find elements before the page is ready
- Hidden elements: Element exists but is not visible or accessible
Solutions
1. Increase the selector timeout
// Wait longer for the element
await page.waitForSelector('#my-element', {
timeout: 60000, // 60 seconds
visible: true // Only wait for visible elements
});
2. Verify the selector
// Check if element exists
const elementExists = await page.evaluate(() => {
return !!document.querySelector('#my-element');
});
if (!elementExists) {
console.log('Element not found on page');
// Take screenshot for debugging
await page.screenshot({ path: 'debug.png' });
}
3. Wait for multiple conditions
// Wait for both the element and page load
await Promise.all([
page.waitForSelector('#my-element', { timeout: 60000 }),
page.waitForFunction(() => document.readyState === 'complete')
]);
4. Handle dynamic content
// Wait for element to be added to the page
await page.waitForFunction(
() => document.querySelector('#my-element') !== null,
{ timeout: 60000 }
);
// Or wait for specific content
await page.waitForFunction(
() => document.querySelector('#my-element').textContent.includes('Expected Text'),
{ timeout: 60000 }
);
5. Use more reliable selectors
// Instead of
await page.waitForSelector('.button');
// Use more specific selectors
await page.waitForSelector('button.submit-button[data-testid="submit"]');
// Or use XPath for complex conditions
await page.waitForXPath('//button[contains(text(), "Submit")]');
6. Implement retry logic
async function waitForElementWithRetry(page, selector, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
await page.waitForSelector(selector, { timeout: 30000 });
return true;
} catch (error) {
if (i === maxRetries - 1) throw error;
console.log(`Retry ${i + 1} of ${maxRetries}`);
await page.reload();
}
}
}
Still Encountering Issues?
If you’re still having trouble with selector timeouts, you can use a visual testing tool like Buglesstack to debug your automation and verify element presence.
// .. assuming you already have your Puppeteer browser and page initialized
try {
await page.goto('https://www.google.com/search?q=puppeteer');
await page.waitForSelector('[name="q"]');
}
catch (error) {
// Prepare buglesstack data
const buglesstackData = {
url: page.url(),
screenshot: await page.screenshot({ encoding: 'base64' }),
html: await page.content(),
metadata: {},
message: error.message,
stack: error.stack
};
// Get your access token from https://app.buglesstack.com
const ACCESS_TOKEN = 'HERE_YOUR_ACCESS_TOKEN';
// Send error to buglesstack
await axios.post('https://app.buglesstack.com/api/v1/crashes', buglesstackData, {
headers: {
Authorization: `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
// Re-throw the error to propagate it
throw error;
}
By implementing proper selector strategies and timeout handling, you can resolve the “waiting for selector timeout” error and make your automation more reliable.