Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Call await frame.content() to get a Puppeteer frame’s complete HTML as a string, including its DOCTYPE. If you’re starting from an <iframe> element, first resolve its associated frame with contentFrame().
Get HTML from a Frame you already have
Frame.content() is the direct method for retrieving a frame’s full HTML document:
As an Amazon Associate I earn from qualifying purchases.
const html = await frame.content();
The result is a string containing the frame’s HTML, including its DOCTYPE. This works for the main frame or a child frame, provided frame refers to the frame whose document you want.
Get the frame from an iframe element
Use ElementHandle.contentFrame() to obtain the frame associated with an iframe element, then call content(). Check that the selector matched before calling methods on the handle.
#1 Best Overall
const iframeHandle = await page.$('iframe#report');
if (!iframeHandle) {
throw new Error('iframe#report was not found');
}
const frame = await iframeHandle.contentFrame();
if (!frame) {
throw new Error('Could not resolve the iframe frame');
}
const html = await frame.content();
console.log(html);
For an HTMLIFrameElement, Puppeteer documents that the associated frame exists. The explicit null check is still useful as defensive handling if the element changes or becomes detached while your code runs.
Complete runnable example
This Node.js example launches Puppeteer, opens a page, reads a selected iframe’s HTML, and closes the browser even if an operation fails. Install Puppeteer in your project first with npm install puppeteer.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com');
const iframeHandle = await page.$('iframe#report');
if (!iframeHandle) {
throw new Error('iframe#report was not found');
}
const frame = await iframeHandle.contentFrame();
if (!frame) {
throw new Error('Could not resolve the iframe frame');
}
const html = await frame.content();
console.log(html);
} finally {
await browser.close();
}
Replace the example URL and selector with the page and iframe you need. If the iframe fills in asynchronously, wait for a condition that reflects the content you need before calling content(). There is no single readiness condition that fits every site.
Choose the method that matches what you need
| Goal | Method | What it returns |
|---|---|---|
| Read the full selected frame document | frame.content() |
HTML string for the frame, including DOCTYPE. |
| Read a DOM expression’s result in a frame | frame.evaluate(() => document.documentElement.outerHTML) |
The result of evaluating that expression in the frame’s context. |
| Read the page’s full HTML | page.content() |
HTML string for the page, including DOCTYPE; it does not select a child iframe. |
| Read one matching element in a frame | frame.$eval(selector, fn) |
The function’s result for the first matching element; it throws if no element matches. |
When a page has several frames, choose the target frame first. Puppeteer’s frame tree exposes frame URLs and child frames, but the selector or matching rule depends on the page. Use frame.content() for the whole document; use frame.$eval() when you only need a specific matching element.
Rank #3
Troubleshooting
- The iframe handle is null: The selector did not match an element at the time it ran. Check the selector and page state, and wait for the iframe element if it is added later.
- The HTML is empty or missing expected content: The frame may not have finished populating. Wait for a page-specific selector or other condition tied to the content you need, then read the frame again.
- You got the top-level page instead:
page.content()reads the page, not the chosen child frame. Resolve the iframe’s frame and callframe.content(). frame.$eval()throws: No element matched the selector inside that frame. Verify the selector and that it applies within the frame’s document.- The selected frame is not the one you intended: A page may contain multiple frames. Inspect the frame tree and choose using a page-appropriate rule, such as a known frame URL or the iframe element you selected.
Or skip the browser setup
If your goal is a visual capture rather than the frame’s source HTML, ScreenshotNeo can return a screenshot or PDF with one GET request. It is a screenshot API, not a way to retrieve a frame’s HTML.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo API documentation for request options. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Learn more at ScreenshotNeo.
Sign up free for 1,000 screenshots a month, with no card required.
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.




