Free tools Windows power users keep installed
One-click scans. No signup required.
Get the iframe’s Frame object, then create the locator from that frame: frame.locator(selector). The locator searches and acts inside that frame, not the page’s main document.
Use a locator inside an iframe
Here is a complete Node.js example using Puppeteer. Replace the URL, iframe-identifying fragment, and field selector with values from the page you are automating.
As an Amazon Associate I earn from qualifying purchases.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
// Use a distinctive, verified property of the intended iframe.
const frame = page.frames().find(candidate =>
candidate.url().includes('/embedded-form')
);
if (!frame) throw new Error('Form iframe not found');
await frame.locator('input[name="email"]').fill('[email protected]');
await frame.locator('button[type="submit"]').click();
} finally {
await browser.close();
}
})();
The URL fragment is only an example. Make sure it identifies the intended frame on the page; a vague match can select the wrong frame or no frame at all.
Find and verify the intended frame
A page has a main frame and may have child frames, including nested frames. page.frames() returns the page’s current frames. You can also start at page.mainFrame() and inspect a frame’s childFrames() when you need to follow the hierarchy.
#1 Best Overall
Identify a frame by its URL
If the iframe’s URL has a distinctive path or other stable fragment, a URL lookup is concise:
const frame = page.frames().find(candidate => candidate.url().includes('checkout'));
if (!frame) throw new Error('Checkout frame not found');
await frame.locator('button[type="submit"]').click();
Check that the match is the frame you expect before interacting with it. If several frames can match, use a more discriminating condition. Puppeteer’s Frame API also supports examining a frame’s associated iframe element and reading one of its attributes, which can help identify it by a property on the embedding element.
Rank #2
Handle nested or changing frames
For a nested iframe, identify the correct parent frame first, then inspect its child frames rather than assuming the target is directly under the main frame. Frames can attach, navigate, and detach as a page changes. If the site replaces an iframe during a flow, a previously found frame may no longer be the frame containing the current content; locate it again after the change.
Why use Frame.locator()?
Puppeteer’s Page interactions guide recommends locators for selecting elements and interacting with them. A locator waits for the target and checks action preconditions rather than requiring you to query an element immediately and manage every readiness check yourself. For clicking, documented checks include being in the viewport, visibility, enabled state, and a stable bounding box across consecutive animation frames.
Use the frame’s locator for each interaction that belongs inside the iframe:
await frame.locator('input[name="email"]').fill('[email protected]');
await frame.locator('button[type="submit"]').click();
fill() supports inputs, textareas, selects, and contenteditable elements. It also accepts boolean values for checkboxes, radio buttons, and switches. For example, to check a checkbox:
Rank #4
await frame.locator('input[name="terms"]').fill(true);
Choose a selector that fits the page
Frame.locator() accepts a selector or supported locator function in that frame. CSS selectors work directly. Puppeteer also supports selector syntax for text, accessibility role and name, XPath, and supported combinations that cross shadow roots.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11- CSS: useful when the page exposes a clear attribute, such as
input[name="email"]. - Role and accessible name: useful when an element has an informative accessible label, for example a submit button with a clear name.
- Text or XPath: useful when those forms express the target more clearly than CSS.
- Shadow-root combinations: useful only where the target is within supported shadow DOM boundaries.
Prefer selectors based on meaningful attributes or accessible names when the page provides them. No selector is guaranteed to remain stable if the site changes its markup or labels.
Best Value
When to use lower-level frame queries
Use a locator for ordinary selection and interaction. If the operation you need is not available through locators, Puppeteer still provides lower-level frame methods such as waitForSelector() and ElementHandle. The frame’s $() method returns an element handle for the first match, or null when there is no match.
| Approach | Readiness and result | Use it when |
|---|---|---|
frame.locator(selector) |
Waits for the target and relevant action preconditions; performs locator-supported interactions. | You need to find and interact with an element, such as filling a field or clicking a button. |
frame.$(selector) |
Returns the first matching ElementHandle or null; it does not itself provide locator action readiness checks. |
You specifically need an element handle or need to handle the no-match result directly. |
frame.waitForSelector(selector) |
Waits for a selector according to that method’s options and returns a handle when found. | You need a lower-level wait or an operation not covered by locators. |
With a lower-level query, account explicitly for the possibility that the element is missing and for any readiness conditions your next operation requires.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot iframe locator failures
- “Frame not found”: the identifying condition may not match the iframe URL or property, or the frame may not yet be attached. Inspect
page.frames(), refine the match, and locate the frame after it appears. - The locator finds no element: confirm the selector belongs to the iframe’s document, not the main page; check the frame URL and current markup; and verify that the frame has finished navigating to the content you expect.
- The wrong element is targeted: your frame or selector condition may match more than one candidate. Make the frame identification and selector more specific, then verify the match before clicking or submitting.
- A frame reference stops working after navigation: the page may have navigated or replaced the iframe. Re-identify the current frame and create a locator from it.
- A click does not proceed: the element may not meet the locator’s action preconditions, such as being visible, enabled, in the viewport, and stable. Check whether an overlay or page state is preventing the action, and wait for the intended UI state before continuing.
- A lower-level query returns
null:frame.$()found no match at query time. Check the selector and frame context; if the element appears later, use an appropriate wait or locator instead.
Or skip the browser setup
If you need an image or PDF of the page rather than scripted interaction with an iframe, ScreenshotNeo offers a one-request screenshot API. It does not replace Puppeteer locators for filling or clicking elements inside a frame.
Recommended Free Tools
For example, this cURL request captures a page as WebP:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for the API options. Before capture, it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response reports the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




