ScreenshotNeo

BlogHow-to

How to Set Locator Visibility in Puppeteer

Use Puppeteer’s `setVisibility()` to configure locator visibility checks. Learn when to disable them, when to use `waitForSelector()`, and how to diagnose failed actions.

By the ScreenshotNeo team4 October 20266 min read

To set locator visibility in Puppeteer, call setVisibility() on the locator. It returns a new locator configured with that visibility behavior; it does not change the element’s CSS or make the element visible.

await page
  .locator('button')
  .setVisibility(null)
  .click();

Here, null disables the locator’s visibility check. The click can still fail for other reasons, such as the element not existing, being disabled, moving, or being outside the viewport. See Puppeteer’s setVisibility() API reference and page interactions guide.

1. What locator visibility means

Puppeteer locators provide a way to select and interact with elements while waiting for action preconditions. For a click, those preconditions can include that the element is in the viewport, visible, enabled, and has a stable bounding box. setVisibility() configures the visibility part of that behavior.

The method takes a VisibilityOption and returns a locator with the changed setting. The visibility option controls whether the locator waits for the element to be visible or hidden; pass null to disable visibility checks. Since the call returns a locator, chain an action such as click() or save the configured locator for later use.

const button = page.locator('button#continue');
const buttonWithoutVisibilityCheck = button.setVisibility(null);

await buttonWithoutVisibilityCheck.click();

This configures locator behavior. To change page styling, use a page-side DOM operation or your application’s own code instead.

2. Configure a locator’s visibility behavior

Keep the default visibility check

For ordinary interaction, use the locator directly. Puppeteer’s locator action waits for the relevant preconditions, including visibility for a click.

await page.locator('button#continue').click();

Disable the visibility check

Use .setVisibility(null) when the action should not wait on locator visibility. This skips that check only; it does not bypass all other action conditions or guarantee that the browser can complete the action.

await page.locator('button#continue').setVisibility(null).click();

Use the returned locator

setVisibility() produces a configured locator. If you need the original behavior elsewhere, keep the original locator and use the returned one for the specific action:

const continueButton = page.locator('button#continue');
const clickWithoutVisibilityCheck = continueButton.setVisibility(null);

await clickWithoutVisibilityCheck.click();
await continueButton.click();

The second click uses the original locator configuration. Whether either action succeeds still depends on the page state and the remaining action preconditions.

3. Wait for visibility with waitForSelector()

If the task is to wait for an element to appear or become visible or hidden, use page.waitForSelector(). It returns an element handle when the selector is found, or can resolve to null when waiting for a hidden element that is absent.

// Wait until the element is present and visible.
const handle = await page.waitForSelector('#status', { visible: true });

// Wait until the element is absent or hidden.
await page.waitForSelector('#loading', { hidden: true });

The documented visible check requires the element to be in the DOM and not have display: none or visibility: hidden. The hidden option waits until the element is absent or hidden by those CSS properties. The default timeout is 30,000 ms; change it for a page with a known longer wait:

page.setDefaultTimeout(60000);
await page.waitForSelector('#status', { visible: true });

Use a locator when configuring an action’s preconditions; use waitForSelector() when you specifically need an explicit wait and its element handle. Refer to the waitForSelector() reference for the version you use.

4. Complete runnable example

This Node.js example opens a page, tries a normal locator click, and shows how to configure a second click with visibility checking disabled. Install Puppeteer with npm install puppeteer, then save this as visibility.mjs and run node visibility.mjs.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });

try {
  const page = await browser.newPage();
  await page.setContent(`
    <button id="visible">Visible button</button>
    <button id="hidden" style="display:none">Hidden button</button>
  `);

  // Standard interaction: Puppeteer waits for locator action conditions.
  await page.locator('#visible').click();
  console.log('Clicked the visible button');

  // Disables the locator visibility check. This does not make the hidden
  // button visible, and other click preconditions may still prevent the action.
  try {
    await page.locator('#hidden').setVisibility(null).click();
    console.log('Hidden button click completed');
  } catch (error) {
    console.error('Click still failed:', error.message);
  }

  // For a visibility wait, use waitForSelector instead.
  const hiddenHandle = await page.waitForSelector('#hidden', {
    visible: false,
    timeout: 1000,
  });
  console.log('Found hidden element:', Boolean(hiddenHandle));
  await hiddenHandle?.dispose();
} finally {
  await browser.close();
}

The example catches the second action’s error because disabling one precondition does not make an otherwise non-interactable element clickable. Choose an action that matches the page state: reveal the element, wait for it to become actionable, or use a DOM-level operation only when that is what the task requires.

5. Common errors and fixes

Symptom Likely cause What to do
The action still times out after setVisibility(null). Another action precondition is unmet, or the element cannot be found. Confirm the selector matches, inspect the page state, and check whether the element is enabled, in the viewport, and stable. Disabling visibility skips only the visibility check.
The element remains hidden. setVisibility() changes locator configuration, not CSS. Trigger the application behavior that reveals it, or change its style through page-side code if that is explicitly the intended operation.
waitForSelector() times out while waiting for visibility. The element never entered the DOM, remained hidden, or appeared after the timeout. Check the selector and page state. Increase the timeout with the option or page.setDefaultTimeout() only if the longer wait is expected.
A wait for hidden state returns without an element handle. The element may already be absent, which satisfies the hidden condition. Handle the result as nullable when using a hidden wait.
A locator configuration seems unchanged on another action. setVisibility() returns a configured locator; the original locator remains separate. Use the returned locator for the action that needs the changed setting.

6. Performance, reliability, and cost

Choose the narrowest wait that matches the page behavior. Waiting for a selector to become visible is generally more reliable than adding a fixed delay when the page has a meaningful DOM state to observe. A longer timeout can absorb slow pages, but it also makes a genuine failure take longer to report. Avoid disabling visibility checks as a general workaround: it removes a useful signal while leaving other action conditions in place.

Puppeteer runs the browser automation locally or in the environment where you deploy it, so account for browser process and page lifecycle management in your own runtime and hosting costs. The cited Puppeteer documentation does not specify a hosted-browser price or performance benchmark.

7. Or skip the browser setup

If your goal is a rendered page screenshot rather than a Puppeteer interaction, ScreenshotNeo returns an image or PDF from one API request. Its API documentation covers available parameters.

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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before capture.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers report the page verdict and billing status.
  • An MCP server lets AI agents using Claude, Cursor, or another MCP client take screenshots.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

8. FAQ

Does setVisibility(false) hide an element?

No. The method configures locator visibility behavior; it does not apply CSS. Use waitForSelector() to wait for a hidden state, or update the page through application or DOM code if you need to change styling.

Does setVisibility(null) make a hidden element clickable?

No. It disables visibility checks for the locator. Other requirements or the browser’s ability to interact with the element can still cause the action to fail.

Which approach should I choose?

Use setVisibility() to configure visibility checks for a locator action. Use waitForSelector() to explicitly wait for a selector’s visible or hidden state and obtain its element handle.

Where can I check the exact API for my Puppeteer version?

Consult the Locator.setVisibility() reference and the Page.waitForSelector() reference for the version installed in your project.