I’m working on a web scraping project with Puppeteer and I’m stuck on accessing elements that are inside an iframe. The website I’m trying to automate has a login form embedded in an iframe, and I can’t figure out how to interact with the input fields and buttons.
Here’s what I’ve tried so far:
const browser = await puppeteer.launch({headless: false});
const mainPage = await browser.newPage();
await mainPage.goto('https://example-site.com/auth');
await mainPage.waitForSelector('iframe');
const iframeElement = await mainPage.$('section#login-container iframe');
const iframeContent = await iframeElement.contentFrame();
await browser.close();
I can successfully get the iframe reference and even select the main container like this:
iframeContent.$('.container')
But when I try to access the actual form elements like email input, password input, or submit button, they all return null. I need to automate filling out these fields but I can’t seem to grab them properly. What’s the correct way to select and interact with elements nested inside an iframe?
Sounds like a cross-origin issue. I hit this same problem scraping a third-party auth widget. You can grab the contentFrame reference just fine, but accessing elements inside fails silently when CORS blocks you. Check if the iframe src loads from the same domain as your parent page. If it’s cross-origin, you’ll need a different approach. I switched to using page.frames() to iterate through all frames instead of contentFrame():
const frames = page.frames();
const targetFrame = frames.find(frame => frame.url().includes(‘login’));
const emailInput = await targetFrame.$(‘input[name=“email”]’);
This worked way better for embedded login forms from external providers.
first, double-check your selectors are right. the iframe might have different class names or IDs than you think. run iframeContent.$$eval('*', els => els.map(el => el.tagName)) to see what’s actually inside. also heads up - some iframes deliberately block automation by detecting puppeteer and hiding elements.
This is a timing issue - you’re trying to grab elements before they’ve loaded in the iframe. You need to wait for the elements to actually exist before selecting them.
I hit the same problem scraping a payment gateway iframe. Fixed it by adding explicit waits after switching to the iframe:
const iframeContent = await iframeElement.contentFrame();
await iframeContent.waitForSelector('input[type="email"]', {timeout: 5000});
await iframeContent.waitForSelector('input[type="password"]');
const emailField = await iframeContent.$('input[type="email"]');
const passwordField = await iframeContent.$('input[type="password"]');
Also check if the iframe loads content with JavaScript. If it does, wait for network idle before grabbing elements. The iframe’s DOM might not be ready when you get the content frame reference.
This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.