Table of contents

How to handle iframes in Puppeteer?

Handling iframes in Puppeteer requires understanding that each iframe is a separate HTML document with its own context. You need to get a reference to the iframe before interacting with its content.

Basic Iframe Access

Method 1: Using contentFrame()

// Get iframe by selector and access its frame
const iframeElement = await page.$('iframe#myFrame');
const frame = await iframeElement.contentFrame();

// Now you can interact with the iframe content
await frame.click('#button-inside-iframe');
await frame.type('#input-field', 'Hello World');

Method 2: Using page.frames()

// Get all frames on the page
const frames = await page.frames();

// Find specific frame by name or URL
const targetFrame = frames.find(frame => 
  frame.name() === 'myFrameName' || 
  frame.url().includes('iframe-content.html')
);

if (targetFrame) {
  await targetFrame.click('#button');
}

Waiting for Iframes to Load

Always wait for iframes to fully load before interacting with them:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.goto('https://example.com/page-with-iframe');

  // Wait for iframe to appear
  await page.waitForSelector('iframe#myFrame');

  // Get iframe reference
  const iframeElement = await page.$('iframe#myFrame');
  const frame = await iframeElement.contentFrame();

  // Wait for content inside iframe to load
  await frame.waitForSelector('#content-inside-iframe');

  // Now safely interact with iframe content
  const text = await frame.$eval('#title', el => el.textContent);
  console.log('Iframe title:', text);

  await browser.close();
})();

Working with Multiple Iframes

async function handleMultipleIframes(page) {
  // Get all iframes on the page
  const iframeElements = await page.$$('iframe');

  for (let i = 0; i < iframeElements.length; i++) {
    const frame = await iframeElements[i].contentFrame();

    if (frame) {
      // Check if frame contains specific content
      const hasLoginForm = await frame.$('#login-form');

      if (hasLoginForm) {
        await frame.type('#username', 'user@example.com');
        await frame.type('#password', 'password123');
        await frame.click('#login-button');
        break;
      }
    }
  }
}

Extracting Data from Iframes

async function extractIframeData(page) {
  const iframeElement = await page.$('iframe.data-frame');
  const frame = await iframeElement.contentFrame();

  // Extract data from iframe
  const data = await frame.evaluate(() => {
    const rows = Array.from(document.querySelectorAll('table tr'));
    return rows.map(row => {
      const cells = Array.from(row.querySelectorAll('td'));
      return cells.map(cell => cell.textContent.trim());
    });
  });

  return data;
}

Cross-Origin Iframe Handling

For iframes from different domains, you may need special handling:

async function handleCrossOriginIframe(page) {
  try {
    const iframeElement = await page.$('iframe[src*="external-domain.com"]');
    const frame = await iframeElement.contentFrame();

    // Note: Cross-origin iframes may have limited access
    if (frame) {
      // Only basic operations may work
      await frame.waitForLoadState('networkidle');
      const url = frame.url();
      console.log('Iframe URL:', url);
    }
  } catch (error) {
    console.log('Cross-origin iframe access restricted:', error.message);
  }
}

Error Handling and Best Practices

async function robustIframeHandling(page) {
  try {
    // Wait for iframe with timeout
    await page.waitForSelector('iframe', { timeout: 10000 });

    const iframeElement = await page.$('iframe');
    if (!iframeElement) {
      throw new Error('Iframe not found');
    }

    const frame = await iframeElement.contentFrame();
    if (!frame) {
      throw new Error('Cannot access iframe content');
    }

    // Wait for iframe content to be ready
    await frame.waitForFunction(
      () => document.readyState === 'complete',
      { timeout: 15000 }
    );

    // Perform actions
    await frame.click('#submit-button');

  } catch (error) {
    console.error('Iframe handling failed:', error.message);

    // Fallback: try alternative approach
    const frames = await page.frames();
    const targetFrame = frames.find(f => f.url().includes('target-content'));

    if (targetFrame) {
      await targetFrame.click('#submit-button');
    }
  }
}

Common Iframe Patterns

Nested Iframes

// Handle iframes within iframes
const outerIframe = await page.$('iframe#outer');
const outerFrame = await outerIframe.contentFrame();

const innerIframe = await outerFrame.$('iframe#inner');
const innerFrame = await innerIframe.contentFrame();

await innerFrame.click('#deep-nested-button');

Dynamic Iframes

// Wait for dynamically created iframes
await page.waitForFunction(
  () => document.querySelectorAll('iframe').length > 0,
  { timeout: 10000 }
);

const dynamicFrame = await page.frames().find(
  frame => frame.url().includes('dynamic-content')
);

if (dynamicFrame) {
  await dynamicFrame.waitForSelector('#dynamic-element');
}

Key Points to Remember

  • Always wait for iframes to load completely before interaction
  • Use contentFrame() for element-based access or page.frames() for frame collection
  • Cross-origin iframes may have access restrictions
  • Implement proper error handling for robust iframe interactions
  • Consider using waitForFunction() for complex loading scenarios

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

📖 Related Blog Guides

Expand your knowledge with these comprehensive tutorials:

Web Scraping with JavaScript

Complete JavaScript scraping guide including Puppeteer

JavaScript Scraping Libraries

Compare Puppeteer with other JavaScript tools

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon