Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use Puppeteer’s Frame objects to find each iframe, then query and scroll content through the frame that owns it. For a scrollable region, use a frame-scoped locator and .scroll(); to reveal a particular element, use scrollIntoView() or a locator action that brings it into view. Nested iframes require selecting a child frame explicitly.
How Puppeteer sees iframes
A page has a main frame and may have child frames, including frames nested inside other frames. Each Frame has its own document and JavaScript context: querying the main frame does not automatically search inside an iframe. Puppeteer’s Frame class reference describes frames as analogous to <iframe> elements and documents the frame tree.
There are two different scrolling tasks. You can scroll the iframe element as it appears in its parent document, or scroll a container or target inside the iframe’s own document. The latter requires selecting the frame first and performing the query there.
Recommended Free Tools
Find and identify the frames
After navigation, inspect the attached frames with page.frames(), or start at page.mainFrame() and walk each frame’s childFrames(). A frame’s URL and its iframe element’s attributes can help distinguish it. Do not assume a name is unique or stable: choose a site-specific identifying condition that fits the page.
#1 Best Overall
const frames = page.frames();
for (const frame of frames) {
console.log({ url: frame.url(), name: frame.name() });
}
For nested frames, walk the tree recursively rather than assuming every target is a direct child of the main frame:
function listFrames(frame, depth = 0) {
console.log(`${' '.repeat(depth)}${frame.url()} (${frame.name()})`);
for (const child of frame.childFrames()) {
listFrames(child, depth + 1);
}
}
listFrames(page.mainFrame());
These snippets inspect frames; the URLs, names, and depth that identify the target depend on the site you are automating.
Scroll a region inside every matching iframe
Use a locator scoped to each matching Frame. The example below selects frames by a URL fragment and scrolls a region within each one by 500 pixels. Replace the URL test and selector with conditions for the page you control.
Rank #2
const frames = page.frames();
for (const frame of frames) {
if (frame.url().includes('/embedded/')) {
const region = frame.locator('.scroll-region');
await region.scroll({ scrollTop: 500, scrollLeft: 0 });
}
}
Locator.scroll() uses mouse-wheel events to scroll the located element. This is appropriate when the goal is to move a scrollable region by an amount, rather than simply reveal one particular item. See the Locator.scroll() reference.
Wait for the frame and region
Embedded content can appear after the initial page load or navigate after attachment. Wait for the actual frame or target condition rather than assuming it is ready immediately. Puppeteer’s page interactions guide explains locator readiness and retry behavior; the Frame reference documents frame waiting methods.
A locator action normally waits for action preconditions. Its ensure-in-viewport behavior is enabled by default and can be configured; consult the installed version’s viewport-setting reference when that behavior matters. If a frame navigates or detaches, reacquire the current frame from the page before continuing.
Bring a specific element into view
If the goal is to reveal a target element, rather than move its container by a fixed offset, select the target inside the frame and call scrollIntoView() on its element handle:
Free tools Windows power users keep installed
One-click scans. No signup required.
const frame = page.frames().find(frame => frame.url().includes('/embedded/'));
if (!frame) throw new Error('Target frame was not found');
await frame.waitForSelector('.target');
const target = await frame.$('.target');
if (!target) throw new Error('Target element was not found');
await target.scrollIntoView();
frame.$() returns the first matching element handle or null. Checking both the frame and handle makes missing targets easier to diagnose. Puppeteer documents this method in the ElementHandle.scrollIntoView() reference. A suitable locator action can also ensure an element is in the viewport; choose that approach when its built-in action checks and retries fit the task.
Scroll the iframe element in its parent instead
Sometimes the desired movement is the iframe itself within the parent page—for example, moving down a page until the embedded frame is visible. In that case, query the iframe element from its parent frame, not from the embedded document:
Rank #4
const parent = page.mainFrame();
const iframeElement = await parent.$('iframe[data-widget="example"]');
if (!iframeElement) throw new Error('Iframe element was not found');
await iframeElement.scrollIntoView();
Use a selector grounded in the page’s actual markup. This operation brings the iframe element into view; it does not scroll a region inside the iframe. For content within the embedded document, select the corresponding child Frame and query there.
Complete runnable example
This Node.js example launches Puppeteer, opens a page, finds every attached frame matching a URL fragment, waits for a region in each, and scrolls it. Set TARGET_URL to the page you are authorized to automate, and change FRAME_URL_PART and REGION_SELECTOR to match its iframe and scrollable container. Install Puppeteer in your project with npm install puppeteer, then run the file with Node.js.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto(process.env.TARGET_URL || 'https://example.com', {
waitUntil: 'domcontentloaded',
});
const frameUrlPart = process.env.FRAME_URL_PART || '/embedded/';
const regionSelector = process.env.REGION_SELECTOR || '.scroll-region';
const matchingFrames = page.frames().filter(frame =>
frame.url().includes(frameUrlPart)
);
if (matchingFrames.length === 0) {
throw new Error(`No frame URL contained: ${frameUrlPart}`);
}
for (const frame of matchingFrames) {
await frame.waitForSelector(regionSelector, { timeout: 10000 });
await frame.locator(regionSelector).scroll({
scrollTop: 500,
scrollLeft: 0,
});
console.log(`Scrolled region in ${frame.url()}`);
}
} finally {
await browser.close();
}
})().catch(error => {
console.error(error);
process.exitCode = 1;
});
The URL fragment, selector, and offset are examples, not universal site values. If each iframe needs a different action, branch on its URL, name, or another stable condition rather than applying one selector blindly.
Best Value
- Used Book in Good Condition
Or skip the browser setup
If the task is to capture a website screenshot rather than automate scrolling through its embedded content, ScreenshotNeo offers a one-request screenshot API and an MCP server for AI agents. For a simple capture, make a GET request with the target URL:
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 API documentation for request options. ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf 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. A screenshot API captures pages; it is not a replacement for Puppeteer when you need to interact with iframe contents or control scrolling.
Sign up for ScreenshotNeo to get 1,000 free screenshots a month with no card.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC 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 & 11Troubleshooting
- No frame matches. The embedded content may not yet be attached, may have navigated to a different URL, or your identifying condition may be too narrow. Inspect
page.frames()after navigation and wait for the expected frame state. - The selector is not found. Confirm that the selector belongs to the frame’s document, not the parent page. Wait for the target to appear and verify the current frame URL and selector.
- The frame is nested. Find its parent and traverse
childFrames(), or inspect all attached frames. A parent frame’s JavaScript context does not automatically include nested frame documents. - The frame detached or changed during the operation. Navigation can replace the document or detach a frame. Re-read the page’s current frame collection, identify the new frame, and wait for the target again.
- The content moved but the item is still not visible. A fixed-offset scroll and bringing an item into view are different operations. Use
scrollIntoView()for a specific target; use locator.scroll()for a scrollable region and an offset. - Scrolling appears to do nothing. Check that the selected element is actually the scrollable region and that it can scroll in the requested direction. If the goal is to reveal an item, target that item instead of an unrelated container.
- A locator action fails its viewport check. Locator interactions perform readiness checks and may retry. Review the viewport setting for the Puppeteer version installed in the project; change it only when the task requires different viewport handling.
Version and reliability notes
Puppeteer’s online references do not all show the same release: the Frame and page-interactions pages cited here display version 25.12.0, while the Frame.locator reference displays 25.9.0. Check the API against the version installed in your project, particularly for locator methods, and use that version’s documentation if a method is unavailable.
For more reliable automation, base frame selection on an expected URL, name, or page-specific attribute; wait for the relevant frame and selector; and handle the possibility of frame navigation or detachment. The cited API references do not establish cross-origin status as an obstacle to these Puppeteer operations, so do not infer a same-origin restriction from them. Page-specific behavior, delayed loading, and the lifecycle of the embedded frame can still affect whether and when a selector appears.
Frequently Asked Questions
Can I scroll all iframes with one page-level selector?
No. Select each frame and query its document separately; for nested content, select the child frame that owns the target.
Which method should I use for a fixed scroll amount?
Use a frame-scoped locator’s .scroll() for a scrollable region; use scrollIntoView() when you need a particular element revealed.
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.

