Puppeteer ConsoleMessageLocation: Source URL, Line, and Column
Get a Puppeteer console message’s source URL, line, and column, with safe handling for missing values and zero-based coordinates.
ConsoleMessageLocation describes where a Puppeteer console message originated. Call message.location() inside the page’s console event handler to get its optional url, lineNumber, and columnNumber. The line and column are zero-based, and any field may be unavailable.
1. Read a console message’s location
Install Puppeteer and run this complete Node.js example. It opens a page, logs each console message and its location, then closes the browser. Save it as console-location.cjs and run node console-location.cjs.
const puppeteer = require('puppeteer');
async function main() {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
page.on('console', message => {
const location = message.location();
const source = formatLocation(location);
console.log(`[${message.type()}] ${message.text()} (${source})`);
});
await page.goto('https://example.com', { waitUntil: 'load' });
await page.evaluate(() => console.log('Page console example'));
} finally {
await browser.close();
}
}
function formatLocation({ url, lineNumber, columnNumber }) {
const resource = url ?? '<unknown resource>';
const line = lineNumber === undefined ? '?' : lineNumber;
const column = columnNumber === undefined ? '?' : columnNumber;
return `${resource}:${line}:${column}`;
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});
Install the package with npm install puppeteer. The example’s formatLocation function preserves the 0-based values and prints a question mark for unknown coordinates instead of assuming they exist.
2. Understand the location fields
| Property | Type | Meaning |
|---|---|---|
url |
string | undefined |
Resource URL when Puppeteer knows it. |
lineNumber |
number | undefined |
Zero-based line position in the resource. |
columnNumber |
number | undefined |
Zero-based column position in the resource. |
For example, lineNumber: 0 refers to the first line, and columnNumber: 0 to the first column. Do not add one unless you are deliberately converting to a one-based display convention. The source fields are optional, so callers must handle absent positions. See the official ConsoleMessageLocation reference.
3. TypeScript example
The same event pattern works in TypeScript. The API supplies the location object; the formatter below handles unknown coordinates safely.
import puppeteer, { type ConsoleMessageLocation } from 'puppeteer';
function formatLocation(location: ConsoleMessageLocation): string {
const resource = location.url ?? '<unknown resource>';
const line = location.lineNumber ?? '?';
const column = location.columnNumber ?? '?';
return `${resource}:${line}:${column}`;
}
async function main(): Promise<void> {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
page.on('console', message => {
console.log(message.type(), message.text(), formatLocation(message.location()));
});
await page.goto('https://example.com', { waitUntil: 'load' });
await page.evaluate(() => console.warn('Example warning'));
} finally {
await browser.close();
}
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});
Here ?? is appropriate because line or column zero is valid. Avoid a truthiness check such as location.lineNumber || '?', which would incorrectly treat zero as missing.
4. Event and method behavior
Puppeteer dispatches console messages through the page’s console event. In the handler, message.location() returns the ConsoleMessageLocation object. The ConsoleMessage constructor is internal; application code should consume messages from the event rather than construct or subclass them.
The interface reference consulted for this guide displays Puppeteer 25.3.0, while the method reference displays 25.12.0. Those page labels differ. Check the API documentation matching your installed Puppeteer version if a detail or type declaration differs.
5. Common problems and fixes
| Symptom | Cause | Fix |
|---|---|---|
| The URL or coordinates are missing. | The resource or position is unknown for that message. | Keep the values optional and render a fallback; do not assume every message maps to a source line. |
| The displayed line or column seems one too small. | Puppeteer reports zero-based positions. | Convert to one-based values only at the presentation boundary, adding one to known numbers. |
| Your handler never runs. | The listener may be attached after navigation or after the message was emitted. | Register page.on('console', ...) before goto or before triggering page code. |
| The listener sees page messages but not browser or Node.js output. | The event reports page console messages, not arbitrary host-process logging. | Use Node.js logging for the host process and Puppeteer’s page event for messages emitted by the page. |
| A TypeScript import or property type does not match. | Your installed package version and the consulted reference version may differ. | Use the docs and type declarations for the version in your lockfile; the inspected reference pages show different version labels. |
6. Reliability, performance, and operational notes
- Attach early: register the event listener before navigation or the action that may emit the message, so startup messages are not missed.
- Keep the handler lightweight: format and enqueue relevant fields, then do expensive file or network work outside the callback. This helps avoid slowing event processing.
- Expect partial source data: logs should remain useful when URL, line, or column is unknown. Preserve the message type and text alongside location fields.
- Manage browser lifetime: close the browser in a
finallyblock so navigation errors do not leave Chromium running. - Cost: this API returns metadata from the browser session; the cited interface documentation specifies no per-message fee. Your infrastructure cost depends on how you run Puppeteer and retain or transmit logs.
7. Or skip the browser setup
If your goal is a clean page capture rather than inspecting console source coordinates, ScreenshotNeo returns a screenshot or PDF from one GET request. Its API documentation covers the 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}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card.
8. FAQ
Does location() return a string?
No. It returns a location object with optional URL, line, and column properties.
Should I add one to line and column?
Keep the raw values zero-based for programmatic use. Add one only when converting them for a display that uses one-based coordinates.
Can every console message be mapped to a script URL?
No. Treat the URL and both positions as optional.
Can I create my own ConsoleMessage?
The documented constructor is internal. Consume instances delivered by the page’s console event.


