Skip to content
Puppeteer · error message

Puppeteer: No element found for selector

Permanent - do not retrySelectors & waiting

Last verified

The exact message
Error: No element found for selector: #submit

What it means

Shortcut methods on page and frame such as click(), type(), focus(), hover(), select() and tap() query the selector once and act on the result. They do not wait. If nothing matches at that instant, they throw this error immediately rather than after a timeout.

That is the key difference from waitForSelector and from the Locator API: the element may appear a few hundred milliseconds later, but these methods have already given up. On pages that render content with JavaScript, calling page.click() straight after page.goto() is a frequent source of this error.

What is not wrong: the timeout settings. Changing setDefaultTimeout has no effect here because no waiting happens at all. The fix is to add a wait, not to lengthen one.

What it looks like

// Throws if #submit is not in the DOM yet
// await page.click('#submit');

// Waits up to the default timeout, then clicks
await page.locator('#submit').click();

// Typing with a wait
await page.locator('input[name="email"]').fill('[email protected]');

Why it happens

  • The element is rendered by JavaScript after the action was attempted.
  • The selector has a typo or relies on generated class names that changed.
  • The element is inside an iframe, so the page-level query cannot see it.
  • The element is inside a shadow root and the selector does not pierce it.
  • The page is not the one you expect (redirect, consent screen, error page).

How to fix it

  1. Wait first: await page.waitForSelector('#submit') before page.click('#submit').
  2. Better, use the auto-waiting Locator API: await page.locator('#submit').click().
  3. Verify the selector in DevTools on the same page state with document.querySelector().
  4. For iframes, act on the frame: const frame = page.frames().find(f => f.url().includes('checkout')); await frame.click('#submit').
  5. For shadow DOM, use the >>> combinator or pierce/ prefix.

How to stop it recurring

Use the Locator API (page.locator()) for all interactions in new code; it waits for the element to exist, be visible and stop moving. Reserve page.click(selector) for elements you have already waited for. Log the page URL alongside selector errors so unexpected redirects are obvious.

Official documentation: pptr.dev/api/puppeteer.page.click. See all Puppeteer error messages.

Related errors

Definitions

Quick answers

What does "No element found for selector" mean in Puppeteer?

Shortcut methods on page and frame such as click() , type() , focus() , hover() , select() and tap() query the selector once and act on the result. They do not wait. If nothing matches at that instant, they throw this error immediately rather than after a timeout.

How do I fix "No element found for selector"?

1. Wait first: await page.waitForSelector('#submit') before page.click('#submit'). 2. Better, use the auto-waiting Locator API: await page.locator('#submit').click(). 3. Verify the selector in DevTools on the same page state with document.querySelector(). 4. For iframes, act on the frame: const frame = page.frames().find(f => f.url().includes('checkout')); await frame.click('#submit'). 5. For shadow DOM, use the >>> combinator or pierce/ prefix.

Run browser automation you can watch and take over

Autonoly runs each job in a real cloud Chromium browser driven by Playwright. Timeouts and detached elements still happen; the difference is that you can watch the run live, see the step that failed, and take control of the browser to finish it.

Also see Live browser control.