You wrote a scraper. The data shows up in your browser, but it's missing from your response. The culprit is almost always an iframe.
This guide explains what an iframe is, why its content hides from your scraper, and three concrete methods to extract it. It's written for developers new to the topic, with copy-pastable code and a decision framework at the end.
What Is an iframe (and Why Its Content Hides From Your Scraper)
An iframe is an HTML element that embeds a separate web page inside the current one. That embedded page has its own document, so its content is not part of the parent page's HTML your scraper first downloads. That gap is why you see the data on screen but not in your response.
In MDN's words, the <iframe> HTML element represents a nested browsing context, embedding another HTML page into the current one. Think of it as a window into a second page, living inside the first.
For a scraper, that second page is the whole problem. Your first request returns the outer page, and the data you want lives one layer deeper.
Why iframe Content Isn't in the Page HTML
The parent HTML only contains the <iframe> tag and its src attribute, not the embedded page's content. The browser reads that tag and makes a second request to load the iframe. A basic HTTP scraper never makes that second request.
This points to one fundamental rule: you must make the request that actually returns the data. A single fetch of the outer page is not enough.
You'll hit this a lot with tabular data. When you go to extract table data, the table often sits inside an iframe and must be rendered before you can read it.
The Cross-Origin Wall
When the iframe loads a page from a different domain, that's a cross-origin iframe. The browser's same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin, per MDN. In plain terms, code running on the parent page can't reach into a cross-origin iframe and read it.
Here's the distinction that trips people up:
- What is blocked: In-page JavaScript on the parent page. MDN notes that the contentDocument property returns a Document when the iframe and its parent are same origin, else returns null. So a script on the page can't read a cross-origin frame's DOM.
- What is not blocked: A headless browser or scraping API you control. A headless browser is a real browser with no visible window, driven by code. It can load the iframe's
srcdirectly and read the result, because it isn't a page script bound by the same-origin rule.
Some sites also send an X-Frame-Options header. MDN describes it as an HTTP response header that indicates whether a browser should be allowed to render the document in a <frame>, <iframe>, <embed> or <object>. This prevents framing and clickjacking in a browser rendering context — it is not an anti-scraping measure, and it doesn't stop you from requesting the URL directly.
Framing controls are common. According to the HTTP Archive Web Almanac, X-Frame-Options was found in 35.3%, 34% and 37% respectively across the 2022, 2023, and 2024 desktop crawls.
Method 1: Find the iframe's Source URL and Request It Directly
This is the fastest fix, and it's free. Open your browser's DevTools, inspect the <iframe> tag, and copy its src URL. Then scrape that URL directly, as if it were a normal page.
The tag looks like this:
<iframe src="https://example.com/embedded-widget" width="600" height="400"></iframe>You ignore the outer page and request https://example.com/embedded-widget on its own. The embedded page usually returns its content in that one response.
When this works and when it doesn't:
- Works: The
srcis a real, standalone URL you can open directly in a new tab. - Doesn't work: The
srcis blank, generated by JavaScript after load, or gated behind authentication.
If the extracted URL still needs a browser to render, point it at a rendering scraper instead of a plain HTTP request. Treat this method as step one of a decision framework, not the only answer.
Method 2: Use a Headless Browser to Switch Into the Frame
When there's no clean src URL, drive a real browser with a tool like Puppeteer, Playwright, or Selenium. You load the page, wait for the iframe to load, select the frame, then query the elements inside it.
The core pattern is to grab the page's child frames and pick the one you want, usually by its URL or name:
// Vendor-neutral headless-browser pattern (Puppeteer/Playwright style)
await page.goto("https://example.com");
// Get every frame on the page, then switch into the target iframe
const frames = page.childFrames();
const target = frames.find((f) => f.url().includes("embedded-widget"));
// Query elements inside the frame, not the parent page
const data = await target.$eval(".price", (el) => el.textContent);Selenium follows the same idea with switch_to.frame. Not sure which tool to pick? Start with Selenium vs Puppeteer for the tradeoffs. For a second comparison, see Puppeteer vs Playwright. A nested iframe — an iframe inside another iframe — just means going one level deeper, switching into the outer frame and then into its child.
Handling Dynamically Loaded and Nested iframes
Some iframes are injected by JavaScript after the page loads, or load their content late. If your extraction runs too early, the frame is empty and you get nothing back.
The fix is to wait for the frame and its content to appear before you read it. Wait for a specific element inside the frame rather than a fixed timer, which is more reliable across slow loads. This is where JavaScript rendering matters: the page must run its scripts before the data exists.
Nested iframes need a frame-within-a-frame traversal. Locate the outer frame, then locate its child frame, then query inside the innermost one.
Communicating With an iframe via postMessage
For completeness: when you control both the parent page and the iframe, they can exchange data with postMessage. MDN says the window.postMessage API safely enables cross-origin communication between Window objects; for example, between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
It's only safe when the receiver validates the origin of the incoming message. For third-party scraping this rarely applies, since you don't control the embedded page. It matters mostly when you own both sides.
Method 3: Use a Web Scraping API That Renders iframes for You
Maintaining a headless-browser fleet, proxy rotation, and wait logic is heavy work. A managed Web Data API renders every page in a real browser and returns the fully rendered content — including iframe content — as clean Markdown or JSON, with no infrastructure to run.
This is where Olostep fits. It runs full JavaScript execution as the norm for every request, so iframe content is captured like any other DOM content, with no special config. Olostep's scrape endpoint loads the page, renders it, and hands back the finished result.
Its capabilities map directly onto the hard parts of iframe scraping:
- Rendering by default: Every request runs in a real browser, so late-loading and JS-injected iframes render before extraction.
- Actions to trigger content: Built-in
actions(click, scroll, wait) fire the interactions that load a dynamic iframe before you read it. - Structured output: AI-powered extraction turns messy rendered iframe HTML into clean, schema-defined JSON.
- Scale and reliability: Batch runs and residential proxies extract iframe content across many URLs and help you avoid getting blocked.
The rendering matters more than it sounds. According to figures cited by Olostep, up to 94% of modern sites require browser automation capabilities, so a plain HTTP request misses their content — iframe or not.
Anti-bot pressure is the other reason to let infrastructure handle this. According to the Imperva Bad Bot Report, bad bots now make up 37% of all internet traffic, which is why so many pages fight back against naive scrapers.
Which Method Should You Use?
Start simple and escalate. Try the src URL first, move to a headless browser for a few complex domains, and reach for a scraping API when you need scale and reliability.
| Method | Best for | Skill level | Scale |
|---|---|---|---|
Find the src URL | A clean, standalone iframe URL you can request directly | Beginner | Low — one page at a time |
| Headless browser | Complex frames with no clean src, including nested iframes | Intermediate to advanced | Medium — a few domains |
| Web scraping API | Rendering, anti-bot, and structured output across many URLs | Beginner to intermediate | High — hundreds to millions of URLs |
Frequently Asked Questions
Can you scrape content inside an iframe?
Yes. You can request the iframe's src URL directly, drive a headless browser into the frame, or use a rendering API that returns the iframe's content for you.
Why is the iframe data missing from my HTML response?
The iframe is a separate embedded page that the browser loads with a second request, so its content never appears in the outer page's HTML that a basic scraper downloads.
Can I scrape a cross-origin iframe?
In-page JavaScript can't read a cross-origin iframe, but a headless browser or API you control can load the iframe's src and read the result.
How do I scrape a nested iframe (iframe inside an iframe)?
Use a headless browser to traverse frame by frame — switch into the outer frame, then into its child — since most no-code tools can't reach an iframe inside an iframe.
Why is my iframe scrape returning empty results?
The iframe most likely loads its content late or is injected by JavaScript, so you need to wait for it to render before extracting.
Do I need a headless browser to scrape iframes?
Not always — try the src URL first, and only reach for a headless browser or a rendering API when that direct request fails.
Conclusion / Next Steps
Scraping iframe content comes down to one habit: make the request that actually returns the data. Try the src URL first, escalate to a headless browser when there's no clean URL, and use a rendering API when you need scale and reliability.
For iframe-heavy pages, skip the browser infrastructure and let a managed API render and return the content for you. Point Olostep's scrape endpoint at your target and capture iframe content as clean Markdown or JSON in a single request.
