Skip to main content
The ConsoleMessage class represents messages logged by the page to the browser console. Listen for console messages using the page.on('console') event.

Overview

import { test } from '@playwright/test';

test('capture console messages', async ({ page }) => {
  page.on('console', msg => {
    console.log(`Console ${msg.type()}: ${msg.text()}`);
  });
  
  await page.goto('https://example.com');
  await page.evaluate(() => console.log('Hello from the page'));
});

Methods

type()

Get the type of the console message. Returns: string Possible values:
  • 'log'
  • 'debug'
  • 'info'
  • 'error'
  • 'warning'
  • 'dir'
  • 'dirxml'
  • 'table'
  • 'trace'
  • 'clear'
  • 'startGroup'
  • 'startGroupCollapsed'
  • 'endGroup'
  • 'assert'
  • 'profile'
  • 'profileEnd'
  • 'count'
  • 'timeEnd'
page.on('console', msg => {
  if (msg.type() === 'error') {
    console.error('Page error:', msg.text());
  }
});

text()

Get the text of the console message. Returns: string
page.on('console', msg => {
  console.log(msg.text());
});

args()

Get the list of arguments passed to the console method. Returns: JSHandle[] Each argument is represented as a JSHandle that can be evaluated:
page.on('console', async msg => {
  const args = msg.args();
  for (const arg of args) {
    const value = await arg.jsonValue();
    console.log(value);
  }
});

location()

Get the location in the source code where the console method was called. Returns: { url: string, lineNumber: number, columnNumber: number }
url
string
URL of the script where console was called
lineNumber
number
Line number in the script (0-based)
columnNumber
number
Column number in the script (0-based)
page.on('console', msg => {
  const location = msg.location();
  console.log(`Console at ${location.url}:${location.lineNumber}`);
});

timestamp()

Get the timestamp when the message was logged. Returns: number Timestamp in milliseconds since Unix epoch:
page.on('console', msg => {
  const time = new Date(msg.timestamp());
  console.log(`Message at ${time.toISOString()}: ${msg.text()}`);
});

page()

Get the page that emitted the console message. Returns: Page | null Returns null if the message came from a worker:
page.on('console', msg => {
  const sourcePage = msg.page();
  if (sourcePage) {
    console.log(`Message from page: ${sourcePage.url()}`);
  }
});

worker()

Get the worker that emitted the console message. Returns: Worker | null Returns null if the message came from a page:
page.on('console', msg => {
  const worker = msg.worker();
  if (worker) {
    console.log(`Message from worker: ${worker.url()}`);
  }
});

Examples

Filter by Message Type

test('capture errors only', async ({ page }) => {
  const errors: string[] = [];
  
  page.on('console', msg => {
    if (msg.type() === 'error') {
      errors.push(msg.text());
    }
  });
  
  await page.goto('https://example.com');
  
  // Assert no errors occurred
  expect(errors).toHaveLength(0);
});

Log with Source Location

page.on('console', msg => {
  const location = msg.location();
  console.log(
    `[${msg.type()}] ${msg.text()} ` +
    `(${location.url}:${location.lineNumber}:${location.columnNumber})`
  );
});

Inspect Complex Objects

page.on('console', async msg => {
  console.log(`Type: ${msg.type()}`);
  
  // Get all arguments
  const args = msg.args();
  for (let i = 0; i < args.length; i++) {
    const value = await args[i].jsonValue();
    console.log(`Arg ${i}:`, value);
  }
});

// In page
await page.evaluate(() => {
  console.log('User:', { name: 'Alice', age: 30 });
});

Collect Console Timeline

test('console timeline', async ({ page }) => {
  const timeline: Array<{ time: number, type: string, text: string }> = [];
  
  page.on('console', msg => {
    timeline.push({
      time: msg.timestamp(),
      type: msg.type(),
      text: msg.text(),
    });
  });
  
  await page.goto('https://example.com');
  
  // Print timeline
  timeline.forEach(entry => {
    const time = new Date(entry.time).toISOString();
    console.log(`${time} [${entry.type}] ${entry.text}`);
  });
});

Distinguish Page vs Worker

page.on('console', msg => {
  if (msg.page()) {
    console.log('Page console:', msg.text());
  } else if (msg.worker()) {
    console.log('Worker console:', msg.text());
  }
});

Best Practices

Always Check Message Type

Different message types may require different handling:
page.on('console', msg => {
  switch (msg.type()) {
    case 'error':
      console.error(msg.text());
      break;
    case 'warning':
      console.warn(msg.text());
      break;
    default:
      console.log(msg.text());
  }
});

Handle Async Operations

If you need to evaluate JSHandles, make the listener async:
page.on('console', async msg => {
  const args = msg.args();
  for (const arg of args) {
    try {
      const value = await arg.jsonValue();
      console.log(value);
    } catch (e) {
      // Handle evaluation errors
    }
  }
});

Dispose JSHandles

JSHandles keep objects in memory. Dispose them when done:
page.on('console', async msg => {
  const args = msg.args();
  for (const arg of args) {
    const value = await arg.jsonValue();
    console.log(value);
    await arg.dispose(); // Free memory
  }
});

Build docs developers (and LLMs) love