ScreenshotNeo

BlogHow-to

How to Get the Title of a Frame in Puppeteer

Use `await frame.title()` to read a selected Puppeteer frame’s title. Learn how to find the right frame, handle asynchronous frames, and troubleshoot common issues.

By the ScreenshotNeo team4 October 20267 min read

To get the title of a specific Puppeteer frame, call and await frame.title():

const title = await frame.title();

For the page’s main frame, use await page.title(). That method is a shortcut for page.mainFrame().title(); it does not read a child iframe’s title. The [Puppeteer Frame API](https://pptr.dev/api/puppeteer.frame.title) documents Frame.title() as returning a Promise<string>, and the [Page API](https://pptr.dev/api/puppeteer.page.title) documents the main-frame shortcut.

1. Read the title of a selected frame

Once you have the relevant Frame object, call its title() method. For example, find an attached frame by a URL condition:

const frame = page.frames().find(frame => frame.url().includes('/embedded/'));

if (!frame) {
  throw new Error('Target frame not found');
}

const title = await frame.title();
console.log(title);

Replace '/embedded/' with a condition that identifies your target frame uniquely. A URL substring is only an example: multiple frames can have similar URLs, and a frame may navigate after it first appears.

The result is a string. An empty string can be a valid result when the frame’s document has no title. Since the method is asynchronous, await it before using the value.

2. Complete runnable example

This Node.js example launches Chromium, opens a page, looks for a frame whose URL contains /embedded/, reads its title, and closes the browser even if an error occurs. Install Puppeteer with npm install puppeteer, save this as frame-title.js, then run node frame-title.js https://example.com. Choose a URL that contains the frame you want to inspect.

const puppeteer = require('puppeteer');

async function main() {
  const targetUrl = process.argv[2];
  if (!targetUrl) {
    throw new Error('Usage: node frame-title.js <page-url>');
  }

  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });

    const frame = page.frames().find(frame =>
      frame.url().includes('/embedded/')
    );

    if (!frame) {
      throw new Error('Target frame not found; check the URL matching condition.');
    }

    const title = await frame.title();
    console.log(title);
  } finally {
    await browser.close();
  }
}

main().catch(error => {
  console.error(error);
  process.exitCode = 1;
});

The example waits for the main document’s DOM to be parsed. If the site creates the iframe later, wait for that frame explicitly as shown below. Puppeteer’s frame tree and frame enumeration are described in the [Frame API documentation](https://pptr.dev/api/puppeteer.frame).

3. Identify the correct frame

A page can contain a main frame, direct child frames, and nested frames. Puppeteer exposes attached frames through page.frames(). You can also start at page.mainFrame() and inspect that frame’s childFrames(). A frame name or the iframe element’s selector is not itself the document title: first identify the corresponding Puppeteer Frame, then read its title.

Match by URL

Use a URL condition when the embedded document has a stable, distinctive URL:

const frame = page.frames().find(frame =>
  frame.url() === 'https://widget.example.test/content'
);

if (!frame) {
  throw new Error('Widget frame was not attached');
}

console.log(await frame.title());

For query parameters or changing paths, match the relevant portion of the URL, but make the condition as specific as possible. Inspect page.frames().map(frame => frame.url()) while debugging to see which URLs Puppeteer currently exposes.

Match a named iframe element

If the page identifies the iframe by its name attribute, find the associated frame element and ask Puppeteer for its content frame:

const iframeElement = await page.$('iframe[name="support-widget"]');
if (!iframeElement) {
  throw new Error('Named iframe element not found');
}

const frame = await iframeElement.contentFrame();
if (!frame) {
  throw new Error('The iframe element has no attached content frame');
}

console.log(await frame.title());

This distinguishes the iframe element’s name from the embedded document’s title. The title comes from the loaded document inside the frame.

Handle nested frames

page.frames() includes attached frames across the page’s frame tree, so searching that list can find nested frames too. If you traverse from the main frame, inspect each frame’s childFrames() recursively:

function* descendants(frame) {
  for (const child of frame.childFrames()) {
    yield child;
    yield* descendants(child);
  }
}

const allFrames = [page.mainFrame(), ...descendants(page.mainFrame())];
const frame = allFrames.find(frame => frame.url().includes('/embedded/'));

if (!frame) {
  throw new Error('Nested target frame not found');
}

console.log(await frame.title());

4. Wait for a frame that appears later

Some pages attach an iframe after scripts run or after a user action. Use page.waitForFrame() with a predicate, then read the returned frame’s title:

const frame = await page.waitForFrame(
  frame => frame.url().includes('/embedded/'),
  { timeout: 10000 }
);

const title = await frame.title();
console.log(title);

The predicate should identify the intended frame. The optional timeout is in milliseconds; if no matching frame appears before it expires, Puppeteer rejects the wait. See the [Puppeteer Page.waitForFrame reference](https://pptr.dev/api/puppeteer.page.waitforframe) for the API details. Use documentation matching the Puppeteer version installed in your project.

If a frame already exists but its document is still navigating, a title read can race with that navigation. Wait for the expected frame URL or for a page-specific readiness condition before reading the title. Avoid assuming a fixed delay is sufficient when the site’s load time varies.

5. Main frame versus child frame

What you need Use What it reads
The top-level page title await page.title() The main frame’s document title
The title of a known frame await frame.title() The selected frame’s document title
The main frame explicitly await page.mainFrame().title() The same title as page.title()
A lower-level frame-scoped read await frame.evaluate(() => document.title) The selected frame’s document title through evaluation

Use page.title() only when the main document is the target. For an iframe, select its Frame first. Frame.evaluate() runs in that frame’s execution context, but frame.title() is the direct API for this job.

6. Troubleshooting

Symptom Likely cause Fix
The title belongs to the top-level page You called page.title(), which reads the main frame. Find the child Frame and call await frame.title().
frame is undefined No attached frame matched the search condition, or the frame has not appeared yet. Inspect page.frames().map(f => f.url()), tighten or correct the match, or wait with page.waitForFrame().
The frame search times out The expected frame was not attached before the timeout, or the predicate does not match its actual URL. Check the iframe element, inspect live frame URLs, and verify the page reached the state that creates the frame.
The title is an empty string The frame’s document may not define a title, or the document is not ready yet. Check the embedded document’s title element and wait for the relevant navigation or readiness condition.
The title is stale or unexpected The frame may have navigated after it was located, or the match selected another similar frame. Match more precisely and read after the intended frame navigation completes.
frame.title is not a function The variable may be an iframe element handle, a different object, or the installed Puppeteer version/API is mismatched. Confirm it is a Puppeteer Frame from page.frames() or contentFrame(), and check the docs for the installed version.
Evaluation fails due to a detached frame The frame was removed or replaced while the operation was in progress. Reacquire the frame after the page update, then read its title.

7. Performance, reliability, and cost

Reading a title with frame.title() is a small browser protocol operation. The costly parts of a screenshot or automation workflow are usually browser startup, page navigation, and waiting for a dynamic page, so reuse a browser where appropriate and wait on meaningful conditions instead of adding arbitrary long delays. Always close browser resources in a finally block in scripts that may fail.

Frame attachment and navigation are asynchronous. A robust script checks whether the target frame exists, uses a specific predicate, handles timeout or detachment, and treats an empty title as a possible result rather than automatically as an API failure. Exact behavior and available options can vary across Puppeteer versions; consult documentation for the version in your lockfile.

8. Or skip the browser setup

If you need a screenshot rather than programmatic access to the iframe’s title, ScreenshotNeo returns a website screenshot or PDF from one GET request. See the ScreenshotNeo API documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = require('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

9. FAQ

Does page.title() return an iframe’s title?

No. It reads the main frame. Select the iframe’s Puppeteer Frame and call frame.title().

Can I get a frame title without a selector?

Yes. Search page.frames() using a distinguishing property such as the frame URL, or wait for it with page.waitForFrame().

Is the iframe’s name the same as its title?

No. The name identifies the iframe element; the title is read from the document loaded in that frame.