How to Capture Content Inside Iframes with a Screenshot API
Capture a rendered iframe, crop to its rectangle, or target an element inside it. Choose the right method and handle cross-origin and loading edge cases.
A screenshot API can capture the content an iframe renders as part of a page, including a cross-origin frame, without your page script reading the frame’s DOM. For the whole composition, capture the page. To capture only the iframe’s displayed rectangle, use selector or element capture if the API supports it. To locate a particular node inside a frame, use browser automation with a frame-aware locator such as Playwright’s frameLocator(). Verify the result with the actual embed: rendering, authentication, loading, and frame restrictions can affect what appears.
1. Choose the capture scope
| What you need | Approach | What it captures |
|---|---|---|
| The page as visitors see it | Screenshot endpoint page capture | The rendered composition, including iframe pixels when the frame loads successfully. |
| Only the iframe rectangle | Selector or element capture targeting the iframe element | The area associated with the iframe element. Check the output; APIs do not necessarily handle every frame type identically. |
| A particular element inside the frame | Browser automation with a frame locator, then a locator screenshot | The selected node inside the frame, provided it is available and rendered. |
| A user-selected tab, window, or screen | Browser getDisplayMedia() |
A user-approved capture surface. The browser asks the user to select and approve it. |
The cross-origin restriction concerns JavaScript access to another origin’s DOM. It does not by itself mean a browser cannot render and capture the pixels it displays. The screenshot service, target site, frame configuration, and loaded state still determine the result.
2. Capture the full page with a screenshot endpoint
Use the screenshot endpoint when you want the complete rendered page. The following Cloudflare Browser Run example shows the endpoint’s url and screenshot configuration shape. Consult its documentation for current authentication and supported options.
curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/browser-rendering/screenshot" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"url":"https://example.com/page-with-iframe","screenshot":{"type":"png","fullPage":true}}' \
--output page.png
For a whole-page screenshot, the endpoint renders HTML and JavaScript before capture. Wait for the iframe’s content to appear according to the service’s available wait options. A page-level capture does not require the parent page’s JavaScript to inspect the iframe DOM.
3. Capture only the iframe rectangle
If the endpoint supports selector-based capture, target the iframe element in the parent document. For example, use iframe#report as the selector in the service’s screenshot configuration. Cloudflare Browser Run documents a selector option for capturing a specific page element.
curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/browser-rendering/screenshot" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"url":"https://example.com/page-with-iframe","screenshot":{"type":"png","selector":"iframe#report"}}' \
--output iframe.png
Use the selector for the iframe element in the parent page, not a selector that exists only inside the frame. Selector capture behavior can vary for cross-origin, nested, blocked, or sandboxed frames, so inspect the generated image for clipping, blank content, and overlays.
4. Target a node inside an iframe with Playwright
When you need to find a specific element inside the iframe, use browser automation that can target frames. Playwright’s frameLocator() enters a frame for locating content; its locator screenshot captures the selected element.
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
try {
await page.goto('https://example.com/page-with-iframe', {
waitUntil: 'domcontentloaded',
timeout: 60000,
});
const report = page.frameLocator('iframe#report');
const chart = report.locator('[data-testid="chart"]');
await chart.waitFor({ state: 'visible', timeout: 30000 });
await chart.screenshot({ path: 'chart.png' });
} finally {
await browser.close();
}
Replace the page URL, frame selector, and inner locator with values from the target. If multiple frames match, make the frame selector specific. Playwright locators are strict where an operation requires a single match, so ambiguous selectors can fail rather than silently choosing one.
For the entire rendered page rather than a node, use await page.screenshot({ path: 'page.png', fullPage: true }). For only the iframe rectangle, locate the iframe element in the parent page and screenshot that element; this is different from locating a node inside the frame.
5. Browser-native screen capture is a different workflow
getDisplayMedia() is appropriate when a person needs to choose a screen, window, or tab to share. It prompts the user to select and confirm a surface and returns a media stream; it is not an unattended backend screenshot API. Screen capture in an iframe may also be governed by the display-capture Permissions Policy and the iframe’s allow attribute.
const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const track = stream.getVideoTracks()[0];
const image = await new ImageCapture(track).grabFrame();
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext('2d').drawImage(image, 0, 0);
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
// Stop capture when finished.
stream.getTracks().forEach(track => track.stop());
This code must run in a supported browser context and follows a user-mediated capture prompt. Element Capture and Region Capture are also browser screen-capture concepts: Element Capture targets an element subtree, while Region Capture uses an element’s bounding box to define a tab area. They solve different needs from a server-side screenshot request.
6. Or skip the browser setup
For a rendered page screenshot, use ScreenshotNeo. Its one-call API returns an image or PDF, and its selector capture can target an iframe element’s displayed rectangle. It does not provide frame-locator access to arbitrary DOM nodes inside an iframe; use browser automation when you need to inspect or select a node inside the frame.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com/page-with-iframe \
-d selector=iframe%23report \
-o iframe.webp
See the ScreenshotNeo API documentation for authentication and options. Cookie banners, popups, and chat widgets are removed before capture; each of those cleanup steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server lets AI agents use screenshot and page-info tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up for ScreenshotNeo and get 1,000 free screenshots a month, with no card required.
7. Validate the output and handle edge cases
- Wait for the iframe to render. A page load event does not guarantee that a third-party frame or its lazy-loaded content is ready. Wait for a visible frame or a known page state when your tool supports it.
- Check authentication. A frame that requires cookies, a session, or authorization may show a login screen or an error. Supply supported cookies or headers, or authenticate through the browser workflow.
- Check the embed itself. The target may block embedding, show a consent screen, or behave differently when framed. A screenshot cannot make content render when the target refuses or fails to display it.
- Check nesting and sandboxing. Nested frames require the correct frame chain for automation. Sandboxed or restricted embeds can limit functionality; selector capture should be validated against the actual page.
- Check geometry and scroll state. An iframe may be clipped by its container or show only its current internal scroll position. A screenshot of the iframe element does not automatically mean every scrollable frame document has been captured.
- Check overlays and lazy content. Cookie prompts, sticky elements, delayed widgets, and lazy-loaded images can obscure or change the result. Wait for the desired state and inspect the image.
8. Troubleshooting
| Symptom | Likely cause | What to try |
|---|---|---|
| Iframe area is blank | Frame has not loaded, is blocked, or requires authentication. | Wait for a frame-specific visible state; check the target page and session; verify the embed works in a normal browser. |
| Cross-origin access error | Parent-page JavaScript attempted to read the frame DOM. | Use page or selector screenshot for rendered pixels. Use Playwright frame locators for frame-aware automation rather than evaluating the frame through parent-page JavaScript. |
| Selector not found | Selector points inside the frame, is incorrect, or the page has not rendered the element. | For rectangle capture, target the iframe element in the parent document. For an inner node, first select the frame, then the inner locator; wait for it. |
| Strict mode or multiple-match error | The frame selector or inner locator matches more than one element. | Narrow the selector to the intended frame and node. |
| Screenshot is clipped or too small | Element dimensions, parent overflow, viewport, or frame scroll position constrain the visible area. | Inspect the iframe’s rendered size and parent styles; adjust viewport or scroll state. Capture the page if you need its complete composition. |
| Timeout while waiting | The frame is slow, never reaches the expected state, or is blocked. | Use a realistic timeout, wait for a specific visible condition instead of general network idleness, and distinguish a failed embed from a slow one. |
9. Performance, reliability, and cost
Page rendering time is often dominated by the target page and third-party iframe. Capture only the needed scope: a full-page screenshot can involve more layout and image work than a single element. Wait for a condition related to the desired frame rather than waiting indefinitely for all network activity, which may continue due to analytics or long-lived requests.
For reliability, use explicit timeouts, stable selectors, and a clear failure path. Save or inspect output dimensions and confirm that the image is not blank before treating a capture as successful. Revalidate after the embed provider or target page changes. Hosted APIs avoid maintaining a browser process, while Playwright offers more control over frame internals at the cost of managing browser execution and dependencies. The research sources provide no comparable price or performance benchmarks, so compare current service pricing and measure against your own target pages.
10. FAQ
Can a screenshot API capture content displayed inside an iframe?
Usually it can capture rendered pixels as part of the page when the frame loads, but verify the specific API and embed.
Does the iframe need to be same-origin?
No, not merely to capture what the browser renders. Same-origin restrictions matter when script code tries to inspect the frame’s DOM.
How do I screenshot only the iframe?
Use selector or element capture on the iframe element if the screenshot endpoint supports it. Use a frame locator only when you need a node inside the iframe.
Can getDisplayMedia() take a screenshot without asking?
No. The browser asks the user to choose and confirm the capture surface.
Sources
- Cloudflare Browser Run documentation — screenshot endpoint, rendering, and selector capture.
- Playwright frames documentation and screenshots guide — frame locators and page or element screenshots.
- MDN: Using the Screen Capture API — user selection and screen-capture permissions.
- Chrome: Element Capture — capturing an element subtree in a screen-capture workflow.


