How to Get the Source Location of a Puppeteer Console Message
Capture a Puppeteer console message’s URL, line, and column with `msg.location()`, or inspect additional locations with `msg.stackTrace()`.
Listen for the page’s console event and call msg.location() on the ConsoleMessage. It returns an object with optional url, lineNumber, and columnNumber fields. Use msg.stackTrace() when you need an array of locations associated with the message.
page.on('console', msg => {
const location = msg.location();
console.log({
text: msg.text(),
url: location.url,
lineNumber: location.lineNumber,
columnNumber: location.columnNumber,
});
});
The line and column values are zero-based. Add one only when presenting them to people in a one-based editor or display; preserve the original values when passing them to tooling. Any location field can be undefined if Puppeteer does not know it.
1. Capture console locations in Puppeteer
Browser-side console.* output does not automatically appear in the Node.js process. Register a listener on the Puppeteer Page before the page runs the code whose messages you want to capture.
Runnable Node.js example
This example launches Chromium, attaches the listener before navigation, prints structured message data, and closes the browser even if navigation or capture fails. Install Puppeteer in a Node.js project with npm install puppeteer, then save this as console-location.js and run node console-location.js.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
page.on('console', msg => {
const { url, lineNumber, columnNumber } = msg.location();
console.log({
type: msg.type(),
text: msg.text(),
url,
lineNumber,
columnNumber,
});
});
await page.goto('https://example.com', { waitUntil: 'load' });
await page.evaluate(() => console.warn('Example browser console message'));
} finally {
await browser.close();
}
})().catch(error => {
console.error(error);
process.exitCode = 1;
});
The listener is attached before goto(), so it can receive messages produced during page loading. The explicit page.evaluate() call demonstrates a browser-side message generated after navigation. Replace the example URL with the page you are debugging.
Handle missing fields safely
The location fields are optional. Keep missing values distinct from confirmed URLs or coordinates in logs and machine-readable output.
page.on('console', msg => {
const { url, lineNumber, columnNumber } = msg.location();
console.log(msg.text(), {
url: url ?? '(unknown URL)',
lineNumber: lineNumber ?? null,
columnNumber: columnNumber ?? null,
});
});
Using null in a serialized record is one practical choice; leaving the original undefined values intact is also valid. Avoid turning an unavailable coordinate into zero, because zero is a real zero-based position.
2. Choose between location() and stackTrace()
| Method | Returns | Use it for | Handle |
|---|---|---|---|
msg.location() |
One location object | Compact structured logging of the message’s source coordinates | Each field may be undefined |
msg.stackTrace() |
An array of locations | Investigating additional locations associated with the message | The array may be empty; check before using an entry |
Use the single location when that is enough to point a log entry at a resource. Use the stack array when you need more context. The API defines the array return type but does not promise that it is populated for every message.
page.on('console', msg => {
const locations = msg.stackTrace();
console.log({
text: msg.text(),
locations,
firstLocation: locations.length > 0 ? locations[0] : undefined,
});
});
3. Interpret the source coordinates
url: The resource URL Puppeteer associates with the console message, if available.lineNumberandcolumnNumber: Zero-based coordinates, if available. For a human-facing display that starts counting at one, showlineNumber + 1andcolumnNumber + 1only when the respective value is defined.- Generated resources: Treat the returned URL as the reported resource location. The API documentation does not guarantee that it resolves to authored source rather than generated code.
- Missing metadata: An absent URL or coordinate means it is unavailable in that message’s location data. It does not by itself establish that the message has no source.
For records consumed by tools, retain the original zero-based values. Convert coordinates only at the presentation boundary, such as when formatting a clickable editor link.
4. Capture messages from the right execution context
Puppeteer has Node.js code and browser-page code. A message printed by the page’s console is delivered to Node.js through page.on('console'). A console.log() in your Puppeteer script itself is already a Node.js log and is not a browser ConsoleMessage.
- Create or obtain the
Page. - Register the
consoleevent listener. - Navigate or trigger the page behavior that may emit messages.
- Read the message text and location inside the listener.
If the issue requires watching execution interactively, Puppeteer’s debugging guide also describes opening DevTools with devtools: true and using a browser-side debugger statement. See the official Puppeteer debugging guide.
5. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| No browser messages appear in Node.js | The listener is missing, attached to a different page, or added after the message was emitted. | Attach page.on('console', ...) to the page that runs the code, before navigation or the action that emits the message. |
| The URL or coordinates are undefined | Puppeteer does not have that location field for this message. | Preserve the missing value. Inspect msg.stackTrace() for additional locations, while allowing for an empty array. |
| The displayed location is off by one | The API coordinates are zero-based but the display expects counting from one, or the conversion was applied twice. | Keep raw values in data. Add one once, only when formatting for a one-based display. |
| The location points to generated code | The reported resource may be generated rather than the authored source. | Use the returned location as reported and inspect the page’s build and debugging setup. The API reference does not promise authored-source mapping. |
| The stack array has no entries | The API does not guarantee a non-empty stack array for every console message. | Check locations.length before accessing an item and fall back to the single location() object where useful. |
| A Puppeteer script log is missing from the listener | The log was emitted by Node.js, not the browser page. | Log it directly in Node.js; use the page event for browser-side console output. |
| Example code behaves differently across installations | Puppeteer API behavior or supported options can depend on the installed release and browser setup. | Check the API documentation for the version used by the project and keep the package version consistent with the project lockfile. |
6. Performance, reliability, and operational notes
The examples perform a small amount of work per console event: read the message fields and write a record. If a page emits many messages, synchronous console output can become noisy and slow down your own logging pipeline. Filter by msg.type(), collect records for later output, or send them to a bounded logger when volume matters.
Attach the listener before navigation when startup messages matter. Always close the browser in a finally block in scripts that may fail, so an exception does not leave Chromium running. Treat location metadata as best-effort optional data: preserve the message text even when the URL or coordinates are unavailable.
The location API itself does not require a paid service. The main operational costs are the browser process, page loading, and whatever logging or storage your application adds. This method reports console message locations; it does not capture a screenshot.
7. Or skip the browser setup
If your goal is to inspect how a page renders rather than capture console source coordinates, ScreenshotNeo can return a screenshot or PDF with one GET request. It does not replace Puppeteer’s console event or provide msg.location().
See the ScreenshotNeo API documentation for request options. This example saves a screenshot response:
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 and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP server provides screenshot, page-info, and PDF tools for AI agents. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Sign up for free and get 1,000 screenshots a month with no card.
8. FAQ
How do I get the URL, line number, and column number from page.on('console')?
Call msg.location() in the listener and read its url, lineNumber, and columnNumber fields. Each field may be undefined.
How do I get a stack trace from a Puppeteer console message?
Call msg.stackTrace(). It returns an array of locations; check whether the array has entries before relying on a particular one.
Are the line and column numbers one-based?
No. They are zero-based. Add one only for a display that counts from one.


