Call frame.url() on the Puppeteer Frame you want. It returns that frame’s URL as a string, synchronously, so you do not use await.
Get the URL of a specific frame
First obtain the relevant frame, then read its URL:
As an Amazon Associate I earn from qualifying purchases.
const frameUrl = frame.url();
console.log(frameUrl);
The Puppeteer Frame API defines url(): string as the frame’s URL. Because the call is synchronous, write frame.url(), not await frame.url().
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesFind frames attached to a page
A page can contain its main frame as well as child frames, including frames nested inside other frames. Use page.frames() to get the frames currently attached to the page, then call url() on each:
#1 Best Overall
for (const frame of page.frames()) {
console.log(frame.url());
}
For a list of URL strings, map the frame objects to their URLs:
const frameUrls = page.frames().map(frame => frame.url());
page.frames() and page.mainFrame() are documented in Puppeteer’s Page API.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Main-frame URL versus an iframe URL
page.url() returns the main-frame URL; it is documented as a shortcut for page.mainFrame().url(). It does not select an arbitrary iframe. For a child frame’s URL, use that child’s frame.url().
const mainFrameUrl = page.url();
const allFrameUrls = page.frames().map(frame => frame.url());
The distinction is documented by Puppeteer’s Page.url API and Frame.url API.
Rank #3
Traverse nested frames
When the frame hierarchy matters, start at the main frame and recursively visit its child frames. Puppeteer’s Frame API documents childFrames() and demonstrates traversing the tree:
function logFrameUrls(frame, indent = '') {
console.log(indent + frame.url());
for (const child of frame.childFrames()) {
logFrameUrls(child, indent + ' ');
}
}
logFrameUrls(page.mainFrame());
The indentation shows each frame’s depth beneath the main frame. If you only need a flat list of all currently attached frames, page.frames() is more direct.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Read after the navigation you care about
If your code needs the URL after a particular navigation, coordinate the read with that navigation in your own flow. For example, wait for navigation alongside the action that triggers it, then read the frame’s URL:
Recommended Free Tools
const navigation = page.waitForNavigation();
await page.click('a#continue');
await navigation;
const frameUrl = page.mainFrame().url();
This example reads the main frame after navigation. For an iframe, retain or locate its Frame object and call url() on that frame at the appropriate point. The API references document URL retrieval but do not promise a cached or historical URL value.
Best Value
Troubleshooting
await frame.url()appears to work, but is unnecessary:url()returns a string synchronously. Removeawait.- You are getting the top-level address instead of the iframe address:
page.url()addresses the main frame. Select the child frame frompage.frames()and read itsurl(). - Your frame list does not show the frame you expect:
page.frames()returns frames attached to that page. Check that you are inspecting the intended page and that the frame is attached when you read the list. - A nested frame is easy to confuse with another child: Traverse from
page.mainFrame()withchildFrames(), or print every attached frame’s URL and identify the intended one. - The URL is not the one expected after an action: Ensure the navigation or other page change has completed before reading; do not treat the call as a historical snapshot.
The reviewed API references do not establish exact behavior for detached frames or unusual URL schemes, so avoid depending on a particular result for those cases without checking the behavior in your Puppeteer version.
Or skip the browser setup
If your goal is a screenshot or PDF rather than Puppeteer frame inspection, ScreenshotNeo provides a website screenshot API and MCP server. For a screenshot, one GET request can return an image or PDF. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with response headers indicating the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents and other MCP clients.
The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for ScreenshotNeo’s free plan.
Frequently Asked Questions
Does `frame.url()` return a string or a promise?
It returns a string synchronously; do not await it.
Can `page.url()` return a child frame’s URL?
No. It is the main-frame URL shortcut. Use the child frame’s `url()` method.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




