Chrome Devtools Console Commands (2026)

The Chrome DevTools console is one of the most powerful tools in a web developer’s toolkit. Beyond simple console.log(), the console API offers a comprehensive suite of commands that can dramatically improve your debugging workflow. Most developers use maybe five percent of what the console can do. This guide covers the essential Chrome DevTools console commands that professional developers rely on daily, including several that rarely appear in introductory tutorials but save significant time once you know they exist.

Accessing the Console

Open Chrome DevTools by pressing F12, Ctrl+Shift+I (Windows/Linux), or Cmd+Option+I (Mac). Click the Console tab, or press Ctrl+` (backtick) to toggle the console drawer while viewing any other DevTools panel. You can also right-click any element on a page and choose “Inspect” to jump directly to the Elements panel, then switch to Console from there.

One underused tip: open a standalone console window by clicking the three-dot menu in DevTools and selecting “Undock into separate window.” This gives you a full-screen console alongside your app, which is useful on single-monitor setups during long debugging sessions.

Essential Console Output Commands

console.log() and Its Variants

The most commonly used command is console.log(), but the console API provides distinct methods for different logging levels:

// Basic logging
console.log('Application started');
console.info('User logged in successfully');
console.warn('This feature will be deprecated in v2.0');
console.error('Failed to connect to API');

Using the appropriate method matters for more than aesthetics. Each level has a distinct visual style in the console, but more importantly, you can filter by level using the dropdown at the top of the console panel. When an application logs hundreds of messages, being able to show only console.error() calls is the difference between finding a bug in 30 seconds versus 30 minutes.

The console.error() method also automatically captures a stack trace. Every error log includes a clickable link back to the source file and line number, making it far more useful than console.log() for tracking down where something went wrong.

Structured Logging with console.table()

For arrays and objects, console.table() displays data in a readable tabular format:

const users = [
 { id: 1, name: 'Alice', role: 'admin' },
 { id: 2, name: 'Bob', role: 'editor' },
 { id: 3, name: 'Charlie', role: 'viewer' }
];
console.table(users);

This command is particularly useful for inspecting API responses, database query results, or any structured data. You can also specify which columns to display by passing an array of property names as the second argument:

// Only show the name and role columns, not id
console.table(users, ['name', 'role']);

The output is a sortable table, you can click column headers to sort, which makes comparing values across records much faster than reading through an expanded object tree.

console.dir() vs. console.log() for DOM Nodes

When logging a DOM element, console.log() and console.dir() behave differently in ways that matter:

const button = document.querySelector('#submit-btn');
console.log(button); // Shows the HTML element representation
console.dir(button); // Shows the JavaScript object with all properties

If you need to inspect event listeners, style properties, or custom data attributes on a DOM node, use console.dir(). The HTML representation from console.log() is easier to read visually, but the object view from console.dir() exposes the full API surface.

Debugging Commands

console.assert()

Write assertions that only log when a condition is false:

function divide(a, b) {
 console.assert(b !== 0, 'Division by zero attempted', { a, b });
 return b !== 0 ? a / b : NaN;
}
divide(10, 0);
// Output: Assertion failed: Division by zero attempted {a: 10, b: 0}

This approach keeps your code clean while providing runtime validation during development. Unlike throwing an error, a failed assertion logs to the console and continues execution, useful for catching invalid states that don’t immediately break anything but indicate a logic problem upstream.

console.trace()

When working with complex call stacks, console.trace() prints the full execution path that led to that point:

function innerFunction() {
 console.trace('How did we get here?');
}
function middlewareFunction() {
 innerFunction();
}
function outerFunction() {
 middlewareFunction();
}
outerFunction();

Output will show the complete call chain: innerFunction > middlewareFunction > outerFunction. This is invaluable when a function is called from multiple places in a large codebase and you need to know which code path triggered a particular execution. It’s also useful for tracking down the source of recursive calls gone wrong.

console.count() and console.countReset()

Track how many times a code block executes without manually maintaining counters:

function handleClick() {
 console.count('Button clicks');
}
handleClick(); // Button clicks: 1
handleClick(); // Button clicks: 2
handleClick(); // Button clicks: 3
console.countReset('Button clicks');
handleClick(); // Button clicks: 1

This works particularly well for monitoring event handler invocations or loop iterations. If an event fires 47 times when you expected 3, console.count() will surface that immediately. You can use multiple counters simultaneously with different labels.

console.time() and console.timeEnd()

Measure how long synchronous operations take with microsecond precision:

console.time('Array processing');
const result = largeArray
 .filter(item => item.active)
 .map(item => item.value * 2)
 .sort((a, b) => b - a);
console.timeEnd('Array processing');
// Output: Array processing: 12.453 ms

For async operations, wrap the timer around a Promise or use console.timeStamp() to mark points in a performance recording. You can run multiple timers simultaneously with different labels:

console.time('db-query');
console.time('render');
fetchUsers().then(users => {
 console.timeEnd('db-query');
 renderList(users);
 console.timeEnd('render');
});

This gives you independent measurements for each phase without the timers interfering with each other.

The debugger Statement

The most direct way to pause execution is the debugger statement, which triggers a breakpoint when DevTools is open:

function processPayment(amount, currency) {
 debugger; // Execution pauses here with DevTools open
 const converted = convertCurrency(amount, currency);
 return submitTransaction(converted);
}

When execution hits debugger, the Sources panel opens automatically and you can step through code, inspect variable values, and evaluate expressions in the console while execution is paused. This is more reliable than a conditional console.log() for diagnosing issues that only appear with specific inputs.

Advanced Console Techniques

Grouping Output

Organize related console output with collapsible groups:

console.group('User Authentication');
console.log('Checking credentials...');
console.log('Validating token...');
if (tokenValid) {
 console.group('Session Setup');
 console.log('Creating session');
 console.log('Setting cookies');
 console.groupEnd();
}
console.groupEnd();

Use console.groupCollapsed() instead of console.group() when you want the group to start in a collapsed state. This is useful for verbose logging that you want available without cluttering the visible console:

console.groupCollapsed('Request details (click to expand)');
console.log('Headers:', request.headers);
console.log('Body:', request.body);
console.log('Timestamp:', new Date().toISOString());
console.groupEnd();

String Substitution

Insert variables into console output using format specifiers:

const user = { name: 'Sarah', id: 42 };
console.log('User %s has ID %d', user.name, user.id);
// Output: User Sarah has ID 42
console.log('Memory usage: %o', performanceObject);
// %o renders as a clickable, expandable object

The available format specifiers are:

  • %s. string
  • %d or %i. integer
  • %f. floating point number
  • %o. object (expandable)
  • %O. object (formatted with JSON-style display)
  • %c. CSS styling (apply the next argument as CSS)

Styling Console Output

Add CSS styling to make important messages stand out in a busy console:

console.log('%cImportant: ', 'color: red; font-weight: bold; font-size: 14px;', 'Action required');
console.log('%cSuccess: ', 'color: green; font-weight: bold;', 'Task completed');
console.log(
 '%c[DEPLOY] %c Production deployment started',
 'background: #e74c3c; color: white; padding: 2px 6px; border-radius: 3px;',
 'color: #333; font-weight: bold;'
);

This technique is most useful in development frameworks and libraries that want their internal messages visually distinct from application code. You can also use it to make your own debug logs easier to spot in a long console output.

Console Utilities

$ and $$ Selectors

The console provides shorthand DOM selection functions that work like jQuery:

// Returns the first element matching the selector (like querySelector)
$('.submit-button')
// Returns all matching elements as an array (like querySelectorAll)
$$('div.item')
// Both support complex selectors
$$('form input[type="text"]:not([disabled])')

These are only available in the DevTools console itself, not in page scripts. They save keystrokes when you’re doing exploratory debugging and don’t want to type document.querySelector repeatedly.

$0 Through $4: Recently Inspected Elements

In the Elements panel, $0 refers to the most recently selected element. Chrome keeps a history of the last five elements you inspected:

$0 // Most recently selected element
$1 // Previously selected element
$2 // Selected two selections ago
// ...and so on through $4

This is useful for comparing properties across elements or testing DOM manipulation:

// Check if two inspected elements have the same parent
$0.parentElement === $1.parentElement // true or false
// Copy an attribute value from one element to another
$0.setAttribute('data-theme', $1.getAttribute('data-theme'));

copy(): Clipboard Access

Copy any JavaScript value directly to your clipboard:

copy(document.querySelector('html').outerHTML);
copy(JSON.stringify(window.__APP_STATE__, null, 2));
copy($$('a').map(a => a.href));

The copy() function serializes whatever you pass it. For objects, it converts to JSON automatically. This is especially useful for extracting API response data, configuration objects embedded in page state, or HTML snippets for further analysis.

monitor(): Function Calls

Automatically log every call to a function along with its arguments:

function calculateTotal(items) {
 return items.reduce((sum, item) => sum + item.price, 0);
}
monitor(calculateTotal);
calculateTotal([{price: 10}, {price: 20}]);
// Output: function calculateTotal called with arguments: Array(2) [{price: 10}, {price: 20}]

Use unmonitor(calculateTotal) to stop tracking. This is useful when you suspect a function is being called with unexpected arguments but don’t want to modify the source code to add logging.

Practical Debugging Workflows

Inspecting Network Response Data

Combine the console with the Network panel for a powerful debugging loop:

  1. Trigger an API request from your application
  2. In the Network panel, click the request and find the response
  3. Right-click the response body and choose “Copy response”
  4. In the console: const data = JSON.parse(/* paste here */)
  5. Now explore data interactively with console.table(data.results), console.dir(data), etc.

This workflow lets you analyze API responses with the full power of JavaScript without building throwaway test scripts.

Live Expression

Instead of repeatedly logging a value, use the Live Expression feature (the eye icon in the console toolbar) to pin an expression that continuously updates:

// Pin these as live expressions to watch values change in real time
window.scrollY
document.activeElement
performance.now()

Live expressions re-evaluate every 250ms and display the current value inline. This is particularly useful for debugging scroll handlers, focus management, or animation timing.

Conditional Breakpoints via Console

Set breakpoints programmatically when you identify problematic conditions:

function processItem(item) {
 if (item.corrupted) {
 debugger; // Only breaks on corrupted items
 }
 return transform(item);
}

You can also set conditional breakpoints in the Sources panel by right-clicking a line number and choosing “Add conditional breakpoint.” Type any JavaScript expression; execution only pauses when the expression evaluates to true.

Clearing the Console

Keep output clean during long debugging sessions:

console.clear(); // Clears all previous output

You can also press Ctrl+L (or Cmd+K on Mac) to clear without touching the keyboard shortcut. If you want to prevent console.clear() from working (for example, to preserve logs added by browser extensions), check “Preserve log” in the console settings.

Quick Reference: Console Command Summary

Command Purpose When to Use
console.log() General output Daily use
console.error() Error with stack trace Error handling
console.warn() Warning messages Deprecation notices
console.table() Tabular data display Arrays and objects
console.dir() Object property tree DOM nodes, deep objects
console.assert() Conditional logging Runtime validation
console.trace() Call stack snapshot Tracking call origins
console.time/End() Performance measurement Benchmarking
console.count() Execution counter Event monitoring
console.group() Collapsible log groups Organized output
debugger Hard breakpoint Pausing execution
$() / $$() DOM selection Element inspection
$0 Last selected element Elements panel work
copy() Clipboard export Extracting data
monitor() Function call logging Call tracking

Mastering these commands transforms the console from a print statement dumping ground into a proper interactive debugging environment. Start with console.table() and console.time() if you’re new to the advanced APIs, those two alone will visibly improve how quickly you can diagnose data shape problems and performance bottlenecks.


Try it: Paste your error into our Error Diagnostic for an instant fix.

I'm a solo developer in Vietnam. 50K Chrome extension users. $500K+ on Upwork. 5 Claude Max subscriptions running agent fleets in parallel. These are my actual CLAUDE.md templates, orchestration configs, and prompts. Not a course. Not theory. The files I copy into every project before I write a line of code. **[See what's inside →](https://zovo.one/lifetime?utm_source=ccg&utm_medium=cta-default&utm_campaign=chrome-devtools-console-commands)** $99 once. Free forever. 47/500 founding spots left.

Related Reading

Related guides: Mastering Browser Developer Tools

Built by theluckystrike. More at zovo.one

Find the right skill → Browse 155+ skills in our Skill Finder.